Loading fs/dcache.c +44 −27 Original line number Diff line number Diff line Loading @@ -2439,16 +2439,14 @@ static int prepend_name(char **buffer, int *buflen, struct qstr *name) /** * prepend_path - Prepend path string to a buffer * @path: the dentry/vfsmount to report * @root: root vfsmnt/dentry (may be modified by this function) * @root: root vfsmnt/dentry * @buffer: pointer to the end of the buffer * @buflen: pointer to buffer length * * Caller holds the rename_lock. * * If path is not reachable from the supplied root, then the value of * root is changed (without modifying refcounts). */ static int prepend_path(const struct path *path, struct path *root, static int prepend_path(const struct path *path, const struct path *root, char **buffer, int *buflen) { struct dentry *dentry = path->dentry; Loading Loading @@ -2483,10 +2481,10 @@ static int prepend_path(const struct path *path, struct path *root, dentry = parent; } out: if (!error && !slash) error = prepend(buffer, buflen, "/", 1); out: br_read_unlock(vfsmount_lock); return error; Loading @@ -2500,15 +2498,17 @@ static int prepend_path(const struct path *path, struct path *root, WARN(1, "Root dentry has weird name <%.*s>\n", (int) dentry->d_name.len, dentry->d_name.name); } root->mnt = vfsmnt; root->dentry = dentry; if (!slash) error = prepend(buffer, buflen, "/", 1); if (!error) error = vfsmnt->mnt_ns ? 1 : 2; goto out; } /** * __d_path - return the path of a dentry * @path: the dentry/vfsmount to report * @root: root vfsmnt/dentry (may be modified by this function) * @root: root vfsmnt/dentry * @buf: buffer to return value in * @buflen: buffer length * Loading @@ -2519,10 +2519,10 @@ static int prepend_path(const struct path *path, struct path *root, * * "buflen" should be positive. * * If path is not reachable from the supplied root, then the value of * root is changed (without modifying refcounts). * If the path is not reachable from the supplied root, return %NULL. */ char *__d_path(const struct path *path, struct path *root, char *__d_path(const struct path *path, const struct path *root, char *buf, int buflen) { char *res = buf + buflen; Loading @@ -2533,7 +2533,28 @@ char *__d_path(const struct path *path, struct path *root, error = prepend_path(path, root, &res, &buflen); write_sequnlock(&rename_lock); if (error) if (error < 0) return ERR_PTR(error); if (error > 0) return NULL; return res; } char *d_absolute_path(const struct path *path, char *buf, int buflen) { struct path root = {}; char *res = buf + buflen; int error; prepend(&res, &buflen, "\0", 1); write_seqlock(&rename_lock); error = prepend_path(path, &root, &res, &buflen); write_sequnlock(&rename_lock); if (error > 1) error = -EINVAL; if (error < 0) return ERR_PTR(error); return res; } Loading @@ -2541,7 +2562,8 @@ char *__d_path(const struct path *path, struct path *root, /* * same as __d_path but appends "(deleted)" for unlinked files. */ static int path_with_deleted(const struct path *path, struct path *root, static int path_with_deleted(const struct path *path, const struct path *root, char **buf, int *buflen) { prepend(buf, buflen, "\0", 1); Loading Loading @@ -2579,7 +2601,6 @@ char *d_path(const struct path *path, char *buf, int buflen) { char *res = buf + buflen; struct path root; struct path tmp; int error; /* Loading @@ -2594,9 +2615,8 @@ char *d_path(const struct path *path, char *buf, int buflen) get_fs_root(current->fs, &root); write_seqlock(&rename_lock); tmp = root; error = path_with_deleted(path, &tmp, &res, &buflen); if (error) error = path_with_deleted(path, &root, &res, &buflen); if (error < 0) res = ERR_PTR(error); write_sequnlock(&rename_lock); path_put(&root); Loading @@ -2617,7 +2637,6 @@ char *d_path_with_unreachable(const struct path *path, char *buf, int buflen) { char *res = buf + buflen; struct path root; struct path tmp; int error; if (path->dentry->d_op && path->dentry->d_op->d_dname) Loading @@ -2625,9 +2644,8 @@ char *d_path_with_unreachable(const struct path *path, char *buf, int buflen) get_fs_root(current->fs, &root); write_seqlock(&rename_lock); tmp = root; error = path_with_deleted(path, &tmp, &res, &buflen); if (!error && !path_equal(&tmp, &root)) error = path_with_deleted(path, &root, &res, &buflen); if (error > 0) error = prepend_unreachable(&res, &buflen); write_sequnlock(&rename_lock); path_put(&root); Loading Loading @@ -2758,19 +2776,18 @@ SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size) write_seqlock(&rename_lock); if (!d_unlinked(pwd.dentry)) { unsigned long len; struct path tmp = root; char *cwd = page + PAGE_SIZE; int buflen = PAGE_SIZE; prepend(&cwd, &buflen, "\0", 1); error = prepend_path(&pwd, &tmp, &cwd, &buflen); error = prepend_path(&pwd, &root, &cwd, &buflen); write_sequnlock(&rename_lock); if (error) if (error < 0) goto out; /* Unreachable from current root */ if (!path_equal(&tmp, &root)) { if (error > 0) { error = prepend_unreachable(&cwd, &buflen); if (error) goto out; Loading fs/namespace.c +11 −9 Original line number Diff line number Diff line Loading @@ -1048,15 +1048,12 @@ static int show_mountinfo(struct seq_file *m, void *v) if (err) goto out; seq_putc(m, ' '); seq_path_root(m, &mnt_path, &root, " \t\n\\"); if (root.mnt != p->root.mnt || root.dentry != p->root.dentry) { /* * Mountpoint is outside root, discard that one. Ugly, * but less so than trying to do that in iterator in a * race-free way (due to renames). */ return SEQ_SKIP; } /* mountpoints outside of chroot jail will give SEQ_SKIP on this */ err = seq_path_root(m, &mnt_path, &root, " \t\n\\"); if (err) goto out; seq_puts(m, mnt->mnt_flags & MNT_READONLY ? " ro" : " rw"); show_mnt_opts(m, mnt); Loading Loading @@ -2776,3 +2773,8 @@ void kern_unmount(struct vfsmount *mnt) } } EXPORT_SYMBOL(kern_unmount); bool our_mnt(struct vfsmount *mnt) { return check_mnt(mnt); } fs/seq_file.c +3 −3 Original line number Diff line number Diff line Loading @@ -449,8 +449,6 @@ EXPORT_SYMBOL(seq_path); /* * Same as seq_path, but relative to supplied root. * * root may be changed, see __d_path(). */ int seq_path_root(struct seq_file *m, struct path *path, struct path *root, char *esc) Loading @@ -463,6 +461,8 @@ int seq_path_root(struct seq_file *m, struct path *path, struct path *root, char *p; p = __d_path(path, root, buf, size); if (!p) return SEQ_SKIP; res = PTR_ERR(p); if (!IS_ERR(p)) { char *end = mangle_path(buf, p, esc); Loading @@ -474,7 +474,7 @@ int seq_path_root(struct seq_file *m, struct path *path, struct path *root, } seq_commit(m, res); return res < 0 ? res : 0; return res < 0 && res != -ENAMETOOLONG ? res : 0; } /* Loading include/linux/dcache.h +2 −1 Original line number Diff line number Diff line Loading @@ -339,7 +339,8 @@ extern int d_validate(struct dentry *, struct dentry *); */ extern char *dynamic_dname(struct dentry *, char *, int, const char *, ...); extern char *__d_path(const struct path *path, struct path *root, char *, int); extern char *__d_path(const struct path *, const struct path *, char *, int); extern char *d_absolute_path(const struct path *, char *, int); extern char *d_path(const struct path *, char *, int); extern char *d_path_with_unreachable(const struct path *, char *, int); extern char *dentry_path_raw(struct dentry *, char *, int); Loading include/linux/fs.h +1 −0 Original line number Diff line number Diff line Loading @@ -1942,6 +1942,7 @@ extern int fd_statfs(int, struct kstatfs *); extern int statfs_by_dentry(struct dentry *, struct kstatfs *); extern int freeze_super(struct super_block *super); extern int thaw_super(struct super_block *super); extern bool our_mnt(struct vfsmount *mnt); extern int current_umask(void); Loading Loading
fs/dcache.c +44 −27 Original line number Diff line number Diff line Loading @@ -2439,16 +2439,14 @@ static int prepend_name(char **buffer, int *buflen, struct qstr *name) /** * prepend_path - Prepend path string to a buffer * @path: the dentry/vfsmount to report * @root: root vfsmnt/dentry (may be modified by this function) * @root: root vfsmnt/dentry * @buffer: pointer to the end of the buffer * @buflen: pointer to buffer length * * Caller holds the rename_lock. * * If path is not reachable from the supplied root, then the value of * root is changed (without modifying refcounts). */ static int prepend_path(const struct path *path, struct path *root, static int prepend_path(const struct path *path, const struct path *root, char **buffer, int *buflen) { struct dentry *dentry = path->dentry; Loading Loading @@ -2483,10 +2481,10 @@ static int prepend_path(const struct path *path, struct path *root, dentry = parent; } out: if (!error && !slash) error = prepend(buffer, buflen, "/", 1); out: br_read_unlock(vfsmount_lock); return error; Loading @@ -2500,15 +2498,17 @@ static int prepend_path(const struct path *path, struct path *root, WARN(1, "Root dentry has weird name <%.*s>\n", (int) dentry->d_name.len, dentry->d_name.name); } root->mnt = vfsmnt; root->dentry = dentry; if (!slash) error = prepend(buffer, buflen, "/", 1); if (!error) error = vfsmnt->mnt_ns ? 1 : 2; goto out; } /** * __d_path - return the path of a dentry * @path: the dentry/vfsmount to report * @root: root vfsmnt/dentry (may be modified by this function) * @root: root vfsmnt/dentry * @buf: buffer to return value in * @buflen: buffer length * Loading @@ -2519,10 +2519,10 @@ static int prepend_path(const struct path *path, struct path *root, * * "buflen" should be positive. * * If path is not reachable from the supplied root, then the value of * root is changed (without modifying refcounts). * If the path is not reachable from the supplied root, return %NULL. */ char *__d_path(const struct path *path, struct path *root, char *__d_path(const struct path *path, const struct path *root, char *buf, int buflen) { char *res = buf + buflen; Loading @@ -2533,7 +2533,28 @@ char *__d_path(const struct path *path, struct path *root, error = prepend_path(path, root, &res, &buflen); write_sequnlock(&rename_lock); if (error) if (error < 0) return ERR_PTR(error); if (error > 0) return NULL; return res; } char *d_absolute_path(const struct path *path, char *buf, int buflen) { struct path root = {}; char *res = buf + buflen; int error; prepend(&res, &buflen, "\0", 1); write_seqlock(&rename_lock); error = prepend_path(path, &root, &res, &buflen); write_sequnlock(&rename_lock); if (error > 1) error = -EINVAL; if (error < 0) return ERR_PTR(error); return res; } Loading @@ -2541,7 +2562,8 @@ char *__d_path(const struct path *path, struct path *root, /* * same as __d_path but appends "(deleted)" for unlinked files. */ static int path_with_deleted(const struct path *path, struct path *root, static int path_with_deleted(const struct path *path, const struct path *root, char **buf, int *buflen) { prepend(buf, buflen, "\0", 1); Loading Loading @@ -2579,7 +2601,6 @@ char *d_path(const struct path *path, char *buf, int buflen) { char *res = buf + buflen; struct path root; struct path tmp; int error; /* Loading @@ -2594,9 +2615,8 @@ char *d_path(const struct path *path, char *buf, int buflen) get_fs_root(current->fs, &root); write_seqlock(&rename_lock); tmp = root; error = path_with_deleted(path, &tmp, &res, &buflen); if (error) error = path_with_deleted(path, &root, &res, &buflen); if (error < 0) res = ERR_PTR(error); write_sequnlock(&rename_lock); path_put(&root); Loading @@ -2617,7 +2637,6 @@ char *d_path_with_unreachable(const struct path *path, char *buf, int buflen) { char *res = buf + buflen; struct path root; struct path tmp; int error; if (path->dentry->d_op && path->dentry->d_op->d_dname) Loading @@ -2625,9 +2644,8 @@ char *d_path_with_unreachable(const struct path *path, char *buf, int buflen) get_fs_root(current->fs, &root); write_seqlock(&rename_lock); tmp = root; error = path_with_deleted(path, &tmp, &res, &buflen); if (!error && !path_equal(&tmp, &root)) error = path_with_deleted(path, &root, &res, &buflen); if (error > 0) error = prepend_unreachable(&res, &buflen); write_sequnlock(&rename_lock); path_put(&root); Loading Loading @@ -2758,19 +2776,18 @@ SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size) write_seqlock(&rename_lock); if (!d_unlinked(pwd.dentry)) { unsigned long len; struct path tmp = root; char *cwd = page + PAGE_SIZE; int buflen = PAGE_SIZE; prepend(&cwd, &buflen, "\0", 1); error = prepend_path(&pwd, &tmp, &cwd, &buflen); error = prepend_path(&pwd, &root, &cwd, &buflen); write_sequnlock(&rename_lock); if (error) if (error < 0) goto out; /* Unreachable from current root */ if (!path_equal(&tmp, &root)) { if (error > 0) { error = prepend_unreachable(&cwd, &buflen); if (error) goto out; Loading
fs/namespace.c +11 −9 Original line number Diff line number Diff line Loading @@ -1048,15 +1048,12 @@ static int show_mountinfo(struct seq_file *m, void *v) if (err) goto out; seq_putc(m, ' '); seq_path_root(m, &mnt_path, &root, " \t\n\\"); if (root.mnt != p->root.mnt || root.dentry != p->root.dentry) { /* * Mountpoint is outside root, discard that one. Ugly, * but less so than trying to do that in iterator in a * race-free way (due to renames). */ return SEQ_SKIP; } /* mountpoints outside of chroot jail will give SEQ_SKIP on this */ err = seq_path_root(m, &mnt_path, &root, " \t\n\\"); if (err) goto out; seq_puts(m, mnt->mnt_flags & MNT_READONLY ? " ro" : " rw"); show_mnt_opts(m, mnt); Loading Loading @@ -2776,3 +2773,8 @@ void kern_unmount(struct vfsmount *mnt) } } EXPORT_SYMBOL(kern_unmount); bool our_mnt(struct vfsmount *mnt) { return check_mnt(mnt); }
fs/seq_file.c +3 −3 Original line number Diff line number Diff line Loading @@ -449,8 +449,6 @@ EXPORT_SYMBOL(seq_path); /* * Same as seq_path, but relative to supplied root. * * root may be changed, see __d_path(). */ int seq_path_root(struct seq_file *m, struct path *path, struct path *root, char *esc) Loading @@ -463,6 +461,8 @@ int seq_path_root(struct seq_file *m, struct path *path, struct path *root, char *p; p = __d_path(path, root, buf, size); if (!p) return SEQ_SKIP; res = PTR_ERR(p); if (!IS_ERR(p)) { char *end = mangle_path(buf, p, esc); Loading @@ -474,7 +474,7 @@ int seq_path_root(struct seq_file *m, struct path *path, struct path *root, } seq_commit(m, res); return res < 0 ? res : 0; return res < 0 && res != -ENAMETOOLONG ? res : 0; } /* Loading
include/linux/dcache.h +2 −1 Original line number Diff line number Diff line Loading @@ -339,7 +339,8 @@ extern int d_validate(struct dentry *, struct dentry *); */ extern char *dynamic_dname(struct dentry *, char *, int, const char *, ...); extern char *__d_path(const struct path *path, struct path *root, char *, int); extern char *__d_path(const struct path *, const struct path *, char *, int); extern char *d_absolute_path(const struct path *, char *, int); extern char *d_path(const struct path *, char *, int); extern char *d_path_with_unreachable(const struct path *, char *, int); extern char *dentry_path_raw(struct dentry *, char *, int); Loading
include/linux/fs.h +1 −0 Original line number Diff line number Diff line Loading @@ -1942,6 +1942,7 @@ extern int fd_statfs(int, struct kstatfs *); extern int statfs_by_dentry(struct dentry *, struct kstatfs *); extern int freeze_super(struct super_block *super); extern int thaw_super(struct super_block *super); extern bool our_mnt(struct vfsmount *mnt); extern int current_umask(void); Loading