From 18fc8abdb7537bf841a65ce06a33977c109acc92 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 28 Oct 2016 21:52:50 -0400 Subject: ceph: unify dentry_operations instances Signed-off-by: Al Viro --- fs/ceph/dir.c | 30 +++--------------------------- fs/ceph/inode.c | 9 +++++---- fs/ceph/super.c | 1 + fs/ceph/super.h | 3 +-- 4 files changed, 10 insertions(+), 33 deletions(-) (limited to 'fs') diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 78180d151730..80f5339d097b 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c @@ -50,13 +50,6 @@ int ceph_init_dentry(struct dentry *dentry) goto out_unlock; } - if (ceph_snap(d_inode(dentry->d_parent)) == CEPH_NOSNAP) - d_set_d_op(dentry, &ceph_dentry_ops); - else if (ceph_snap(d_inode(dentry->d_parent)) == CEPH_SNAPDIR) - d_set_d_op(dentry, &ceph_snapdir_dentry_ops); - else - d_set_d_op(dentry, &ceph_snap_dentry_ops); - di->dentry = dentry; di->lease_session = NULL; di->time = jiffies; @@ -1319,16 +1312,6 @@ static void ceph_d_release(struct dentry *dentry) kmem_cache_free(ceph_dentry_cachep, di); } -static int ceph_snapdir_d_revalidate(struct dentry *dentry, - unsigned int flags) -{ - /* - * Eventually, we'll want to revalidate snapped metadata - * too... probably... - */ - return 1; -} - /* * When the VFS prunes a dentry from the cache, we need to clear the * complete flag on the parent directory. @@ -1347,6 +1330,9 @@ static void ceph_d_prune(struct dentry *dentry) if (d_unhashed(dentry)) return; + if (ceph_snap(d_inode(dentry->d_parent)) == CEPH_SNAPDIR) + return; + /* * we hold d_lock, so d_parent is stable, and d_fsdata is never * cleared until d_release @@ -1518,13 +1504,3 @@ const struct dentry_operations ceph_dentry_ops = { .d_release = ceph_d_release, .d_prune = ceph_d_prune, }; - -const struct dentry_operations ceph_snapdir_dentry_ops = { - .d_revalidate = ceph_snapdir_d_revalidate, - .d_release = ceph_d_release, -}; - -const struct dentry_operations ceph_snap_dentry_ops = { - .d_release = ceph_d_release, - .d_prune = ceph_d_prune, -}; diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index bca1b49c1c4b..29fcbee2d416 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -1023,16 +1023,17 @@ static void update_dentry_lease(struct dentry *dentry, long unsigned half_ttl = from_time + (duration * HZ / 2) / 1000; struct inode *dir; - /* only track leases on regular dentries */ - if (dentry->d_op != &ceph_dentry_ops) - return; - spin_lock(&dentry->d_lock); dout("update_dentry_lease %p duration %lu ms ttl %lu\n", dentry, duration, ttl); /* make lease_rdcache_gen match directory */ dir = d_inode(dentry->d_parent); + + /* only track leases on regular dentries */ + if (ceph_snap(dir) != CEPH_NOSNAP) + goto out_unlock; + di->lease_shared_gen = ceph_inode(dir)->i_shared_gen; if (duration == 0) diff --git a/fs/ceph/super.c b/fs/ceph/super.c index a29ffce98187..0617580b2508 100644 --- a/fs/ceph/super.c +++ b/fs/ceph/super.c @@ -877,6 +877,7 @@ static int ceph_set_super(struct super_block *s, void *data) fsc->sb = s; s->s_op = &ceph_super_ops; + s->s_d_op = &ceph_dentry_ops; s->s_export_op = &ceph_export_ops; s->s_time_gran = 1000; /* 1000 ns == 1 us */ diff --git a/fs/ceph/super.h b/fs/ceph/super.h index 3e3fa9163059..26a5a5d6bf36 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h @@ -934,8 +934,7 @@ extern const struct file_operations ceph_dir_fops; extern const struct file_operations ceph_snapdir_fops; extern const struct inode_operations ceph_dir_iops; extern const struct inode_operations ceph_snapdir_iops; -extern const struct dentry_operations ceph_dentry_ops, ceph_snap_dentry_ops, - ceph_snapdir_dentry_ops; +extern const struct dentry_operations ceph_dentry_ops; extern loff_t ceph_make_fpos(unsigned high, unsigned off, bool hash_order); extern int ceph_handle_notrace_create(struct inode *dir, struct dentry *dentry); -- cgit v1.2.3 From ad5cb123fd0e4d929b36f0f9bbdec14cb6229ad7 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 28 Oct 2016 22:05:13 -0400 Subject: ceph: switch to use of ->d_init() Signed-off-by: Al Viro --- fs/ceph/dir.c | 21 ++------------------- fs/ceph/export.c | 26 ++------------------------ fs/ceph/file.c | 4 ---- fs/ceph/inode.c | 13 +------------ fs/ceph/super.c | 1 - fs/ceph/super.h | 7 ------- 6 files changed, 5 insertions(+), 67 deletions(-) (limited to 'fs') diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 80f5339d097b..c23eb0e9348c 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c @@ -32,33 +32,19 @@ const struct dentry_operations ceph_dentry_ops; /* * Initialize ceph dentry state. */ -int ceph_init_dentry(struct dentry *dentry) +static int ceph_d_init(struct dentry *dentry) { struct ceph_dentry_info *di; - if (dentry->d_fsdata) - return 0; - di = kmem_cache_zalloc(ceph_dentry_cachep, GFP_KERNEL); if (!di) return -ENOMEM; /* oh well */ - spin_lock(&dentry->d_lock); - if (dentry->d_fsdata) { - /* lost a race */ - kmem_cache_free(ceph_dentry_cachep, di); - goto out_unlock; - } - di->dentry = dentry; di->lease_session = NULL; di->time = jiffies; - /* avoid reordering d_fsdata setup so that the check above is safe */ - smp_mb(); dentry->d_fsdata = di; ceph_dentry_lru_add(dentry); -out_unlock: - spin_unlock(&dentry->d_lock); return 0; } @@ -730,10 +716,6 @@ static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry, if (dentry->d_name.len > NAME_MAX) return ERR_PTR(-ENAMETOOLONG); - err = ceph_init_dentry(dentry); - if (err < 0) - return ERR_PTR(err); - /* can we conclude ENOENT locally? */ if (d_really_is_negative(dentry)) { struct ceph_inode_info *ci = ceph_inode(dir); @@ -1503,4 +1485,5 @@ const struct dentry_operations ceph_dentry_ops = { .d_revalidate = ceph_d_revalidate, .d_release = ceph_d_release, .d_prune = ceph_d_prune, + .d_init = ceph_d_init, }; diff --git a/fs/ceph/export.c b/fs/ceph/export.c index 1780218a48f0..180bbef760f2 100644 --- a/fs/ceph/export.c +++ b/fs/ceph/export.c @@ -62,7 +62,6 @@ static struct dentry *__fh_to_dentry(struct super_block *sb, u64 ino) { struct ceph_mds_client *mdsc = ceph_sb_to_client(sb)->mdsc; struct inode *inode; - struct dentry *dentry; struct ceph_vino vino; int err; @@ -94,16 +93,7 @@ static struct dentry *__fh_to_dentry(struct super_block *sb, u64 ino) return ERR_PTR(-ESTALE); } - dentry = d_obtain_alias(inode); - if (IS_ERR(dentry)) - return dentry; - err = ceph_init_dentry(dentry); - if (err < 0) { - dput(dentry); - return ERR_PTR(err); - } - dout("__fh_to_dentry %llx %p dentry %p\n", ino, inode, dentry); - return dentry; + return d_obtain_alias(inode); } /* @@ -131,7 +121,6 @@ static struct dentry *__get_parent(struct super_block *sb, struct ceph_mds_client *mdsc = ceph_sb_to_client(sb)->mdsc; struct ceph_mds_request *req; struct inode *inode; - struct dentry *dentry; int mask; int err; @@ -164,18 +153,7 @@ static struct dentry *__get_parent(struct super_block *sb, if (!inode) return ERR_PTR(-ENOENT); - dentry = d_obtain_alias(inode); - if (IS_ERR(dentry)) - return dentry; - err = ceph_init_dentry(dentry); - if (err < 0) { - dput(dentry); - return ERR_PTR(err); - } - dout("__get_parent ino %llx parent %p ino %llx.%llx\n", - child ? ceph_ino(d_inode(child)) : ino, - dentry, ceph_vinop(inode)); - return dentry; + return d_obtain_alias(inode); } static struct dentry *ceph_get_parent(struct dentry *child) diff --git a/fs/ceph/file.c b/fs/ceph/file.c index 7bf08825cc11..9d1554c7d036 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c @@ -351,10 +351,6 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry, if (dentry->d_name.len > NAME_MAX) return -ENAMETOOLONG; - err = ceph_init_dentry(dentry); - if (err < 0) - return err; - if (flags & O_CREAT) { err = ceph_pre_init_acls(dir, &mode, &acls); if (err < 0) diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 29fcbee2d416..9d0522ba069c 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -1203,12 +1203,7 @@ retry_lookup: err = -ENOMEM; goto done; } - err = ceph_init_dentry(dn); - if (err < 0) { - dput(dn); - dput(parent); - goto done; - } + err = 0; } else if (d_really_is_positive(dn) && (ceph_ino(d_inode(dn)) != vino.ino || ceph_snap(d_inode(dn)) != vino.snap)) { @@ -1561,12 +1556,6 @@ retry_lookup: err = -ENOMEM; goto out; } - ret = ceph_init_dentry(dn); - if (ret < 0) { - dput(dn); - err = ret; - goto out; - } } else if (d_really_is_positive(dn) && (ceph_ino(d_inode(dn)) != vino.ino || ceph_snap(d_inode(dn)) != vino.snap)) { diff --git a/fs/ceph/super.c b/fs/ceph/super.c index 0617580b2508..fd2ea18a0ca3 100644 --- a/fs/ceph/super.c +++ b/fs/ceph/super.c @@ -795,7 +795,6 @@ static struct dentry *open_root_dentry(struct ceph_fs_client *fsc, root = ERR_PTR(-ENOMEM); goto out; } - ceph_init_dentry(root); dout("open_root_inode success, root dentry is %p\n", root); } else { root = ERR_PTR(err); diff --git a/fs/ceph/super.h b/fs/ceph/super.h index 26a5a5d6bf36..931687f71a7c 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h @@ -950,13 +950,6 @@ extern void ceph_invalidate_dentry_lease(struct dentry *dentry); extern unsigned ceph_dentry_hash(struct inode *dir, struct dentry *dn); extern void ceph_readdir_cache_release(struct ceph_readdir_cache_control *ctl); -/* - * our d_ops vary depending on whether the inode is live, - * snapshotted (read-only), or a virtual ".snap" directory. - */ -int ceph_init_dentry(struct dentry *dentry); - - /* ioctl.c */ extern long ceph_ioctl(struct file *file, unsigned int cmd, unsigned long arg); -- cgit v1.2.3 From cbbd26b8b1a6af9c02e2b6523e12bd50cc765059 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 1 Nov 2016 22:09:04 -0400 Subject: [iov_iter] new primitives - copy_from_iter_full() and friends copy_from_iter_full(), copy_from_iter_full_nocache() and csum_and_copy_from_iter_full() - counterparts of copy_from_iter() et.al., advancing iterator only in case of successful full copy and returning whether it had been successful or not. Convert some obvious users. *NOTE* - do not blindly assume that something is a good candidate for those unless you are sure that not advancing iov_iter in failure case is the right thing in this case. Anything that does short read/short write kind of stuff (or is in a loop, etc.) is unlikely to be a good one. Signed-off-by: Al Viro --- fs/ncpfs/file.c | 2 +- fs/orangefs/devorangefs-req.c | 13 ++++--------- 2 files changed, 5 insertions(+), 10 deletions(-) (limited to 'fs') diff --git a/fs/ncpfs/file.c b/fs/ncpfs/file.c index dd38ca1f2ecb..83ca77231707 100644 --- a/fs/ncpfs/file.c +++ b/fs/ncpfs/file.c @@ -203,7 +203,7 @@ ncp_file_write_iter(struct kiocb *iocb, struct iov_iter *from) bufsize - (pos % bufsize), iov_iter_count(from)); - if (copy_from_iter(bouncebuffer, to_write, from) != to_write) { + if (!copy_from_iter_full(bouncebuffer, to_write, from)) { errno = -EFAULT; break; } diff --git a/fs/orangefs/devorangefs-req.c b/fs/orangefs/devorangefs-req.c index 516ffb4dc9a0..b0ced669427e 100644 --- a/fs/orangefs/devorangefs-req.c +++ b/fs/orangefs/devorangefs-req.c @@ -355,7 +355,6 @@ static ssize_t orangefs_devreq_write_iter(struct kiocb *iocb, __u64 tag; } head; int total = ret = iov_iter_count(iter); - int n; int downcall_size = sizeof(struct orangefs_downcall_s); int head_size = sizeof(head); @@ -372,8 +371,7 @@ static ssize_t orangefs_devreq_write_iter(struct kiocb *iocb, return -EFAULT; } - n = copy_from_iter(&head, head_size, iter); - if (n < head_size) { + if (!copy_from_iter_full(&head, head_size, iter)) { gossip_err("%s: failed to copy head.\n", __func__); return -EFAULT; } @@ -407,8 +405,7 @@ static ssize_t orangefs_devreq_write_iter(struct kiocb *iocb, return ret; } - n = copy_from_iter(&op->downcall, downcall_size, iter); - if (n != downcall_size) { + if (!copy_from_iter_full(&op->downcall, downcall_size, iter)) { gossip_err("%s: failed to copy downcall.\n", __func__); goto Efault; } @@ -462,10 +459,8 @@ static ssize_t orangefs_devreq_write_iter(struct kiocb *iocb, goto Enomem; } memset(op->downcall.trailer_buf, 0, op->downcall.trailer_size); - n = copy_from_iter(op->downcall.trailer_buf, - op->downcall.trailer_size, - iter); - if (n != op->downcall.trailer_size) { + if (!copy_from_iter_full(op->downcall.trailer_buf, + op->downcall.trailer_size, iter)) { gossip_err("%s: failed to copy trailer.\n", __func__); vfree(op->downcall.trailer_buf); goto Efault; -- cgit v1.2.3 From c1d4dd27678fc6892e30ea3de4a7caf86f39df1c Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 5 Jun 2016 16:38:18 -0400 Subject: namei.c: get rid of user_path_parent() direct use of filename_parentat() is just as readable Signed-off-by: Al Viro --- fs/namei.c | 34 ++++++++-------------------------- 1 file changed, 8 insertions(+), 26 deletions(-) (limited to 'fs') diff --git a/fs/namei.c b/fs/namei.c index 5b4eed221530..85d2097fec9a 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -2558,24 +2558,6 @@ int user_path_at_empty(int dfd, const char __user *name, unsigned flags, } EXPORT_SYMBOL(user_path_at_empty); -/* - * NB: most callers don't do anything directly with the reference to the - * to struct filename, but the nd->last pointer points into the name string - * allocated by getname. So we must hold the reference to it until all - * path-walking is complete. - */ -static inline struct filename * -user_path_parent(int dfd, const char __user *path, - struct path *parent, - struct qstr *last, - int *type, - unsigned int flags) -{ - /* only LOOKUP_REVAL is allowed in extra flags */ - return filename_parentat(dfd, getname(path), flags & LOOKUP_REVAL, - parent, last, type); -} - /** * mountpoint_last - look up last component for umount * @nd: pathwalk nameidata - currently pointing at parent directory of "last" @@ -3861,8 +3843,8 @@ static long do_rmdir(int dfd, const char __user *pathname) int type; unsigned int lookup_flags = 0; retry: - name = user_path_parent(dfd, pathname, - &path, &last, &type, lookup_flags); + name = filename_parentat(dfd, getname(pathname), lookup_flags, + &path, &last, &type); if (IS_ERR(name)) return PTR_ERR(name); @@ -3991,8 +3973,8 @@ static long do_unlinkat(int dfd, const char __user *pathname) struct inode *delegated_inode = NULL; unsigned int lookup_flags = 0; retry: - name = user_path_parent(dfd, pathname, - &path, &last, &type, lookup_flags); + name = filename_parentat(dfd, getname(pathname), lookup_flags, + &path, &last, &type); if (IS_ERR(name)) return PTR_ERR(name); @@ -4491,15 +4473,15 @@ SYSCALL_DEFINE5(renameat2, int, olddfd, const char __user *, oldname, target_flags = 0; retry: - from = user_path_parent(olddfd, oldname, - &old_path, &old_last, &old_type, lookup_flags); + from = filename_parentat(olddfd, getname(oldname), lookup_flags, + &old_path, &old_last, &old_type); if (IS_ERR(from)) { error = PTR_ERR(from); goto exit; } - to = user_path_parent(newdfd, newname, - &new_path, &new_last, &new_type, lookup_flags); + to = filename_parentat(newdfd, getname(newname), lookup_flags, + &new_path, &new_last, &new_type); if (IS_ERR(to)) { error = PTR_ERR(to); goto exit1; -- cgit v1.2.3 From ba8f46135ab19a6bc3ac11a16e8455956e13f6b1 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 14 Nov 2016 00:40:33 -0500 Subject: namei: saner calling conventions for mountpoint_last() leave the result in nd->path, have caller do follow_mount() and copy it to the final destination. Signed-off-by: Al Viro --- fs/namei.c | 50 +++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 25 deletions(-) (limited to 'fs') diff --git a/fs/namei.c b/fs/namei.c index 85d2097fec9a..ab4caccfe304 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -2561,7 +2561,6 @@ EXPORT_SYMBOL(user_path_at_empty); /** * mountpoint_last - look up last component for umount * @nd: pathwalk nameidata - currently pointing at parent directory of "last" - * @path: pointer to container for result * * This is a special lookup_last function just for umount. In this case, we * need to resolve the path without doing any revalidation. @@ -2574,23 +2573,20 @@ EXPORT_SYMBOL(user_path_at_empty); * * Returns: * -error: if there was an error during lookup. This includes -ENOENT if the - * lookup found a negative dentry. The nd->path reference will also be - * put in this case. + * lookup found a negative dentry. * - * 0: if we successfully resolved nd->path and found it to not to be a - * symlink that needs to be followed. "path" will also be populated. - * The nd->path reference will also be put. + * 0: if we successfully resolved nd->last and found it to not to be a + * symlink that needs to be followed. * * 1: if we successfully resolved nd->last and found it to be a symlink - * that needs to be followed. "path" will be populated with the path - * to the link, and nd->path will *not* be put. + * that needs to be followed. */ static int -mountpoint_last(struct nameidata *nd, struct path *path) +mountpoint_last(struct nameidata *nd) { int error = 0; - struct dentry *dentry; struct dentry *dir = nd->path.dentry; + struct path path; /* If we're in rcuwalk, drop out of it to handle last component */ if (nd->flags & LOOKUP_RCU) { @@ -2604,36 +2600,34 @@ mountpoint_last(struct nameidata *nd, struct path *path) error = handle_dots(nd, nd->last_type); if (error) return error; - dentry = dget(nd->path.dentry); + path.dentry = dget(nd->path.dentry); } else { - dentry = d_lookup(dir, &nd->last); - if (!dentry) { + path.dentry = d_lookup(dir, &nd->last); + if (!path.dentry) { /* * No cached dentry. Mounted dentries are pinned in the * cache, so that means that this dentry is probably * a symlink or the path doesn't actually point * to a mounted dentry. */ - dentry = lookup_slow(&nd->last, dir, + path.dentry = lookup_slow(&nd->last, dir, nd->flags | LOOKUP_NO_REVAL); - if (IS_ERR(dentry)) - return PTR_ERR(dentry); + if (IS_ERR(path.dentry)) + return PTR_ERR(path.dentry); } } - if (d_is_negative(dentry)) { - dput(dentry); + if (d_is_negative(path.dentry)) { + dput(path.dentry); return -ENOENT; } if (nd->depth) put_link(nd); - path->dentry = dentry; - path->mnt = nd->path.mnt; - error = should_follow_link(nd, path, nd->flags & LOOKUP_FOLLOW, - d_backing_inode(dentry), 0); + path.mnt = nd->path.mnt; + error = should_follow_link(nd, &path, nd->flags & LOOKUP_FOLLOW, + d_backing_inode(path.dentry), 0); if (unlikely(error)) return error; - mntget(path->mnt); - follow_mount(path); + path_to_nameidata(&path, nd); return 0; } @@ -2654,13 +2648,19 @@ path_mountpoint(struct nameidata *nd, unsigned flags, struct path *path) if (IS_ERR(s)) return PTR_ERR(s); while (!(err = link_path_walk(s, nd)) && - (err = mountpoint_last(nd, path)) > 0) { + (err = mountpoint_last(nd)) > 0) { s = trailing_symlink(nd); if (IS_ERR(s)) { err = PTR_ERR(s); break; } } + if (!err) { + *path = nd->path; + nd->path.mnt = NULL; + nd->path.dentry = NULL; + follow_mount(path); + } terminate_walk(nd); return err; } -- cgit v1.2.3 From 7f49b471097011d03316d4ae1bc38f9c177126c3 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 14 Nov 2016 01:34:52 -0500 Subject: namei: shift interpretation of LOOKUP_FOLLOW inside should_follow_link() Simplifies the arguments both for it and for walk_component() Signed-off-by: Al Viro --- fs/namei.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) (limited to 'fs') diff --git a/fs/namei.c b/fs/namei.c index ab4caccfe304..379168db782b 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1737,7 +1737,7 @@ static inline int should_follow_link(struct nameidata *nd, struct path *link, { if (likely(!d_is_symlink(link->dentry))) return 0; - if (!follow) + if (!follow && !(nd->flags & LOOKUP_FOLLOW)) return 0; /* make sure that d_is_symlink above matches inode */ if (nd->flags & LOOKUP_RCU) { @@ -2248,12 +2248,7 @@ static inline int lookup_last(struct nameidata *nd) nd->flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY; nd->flags &= ~LOOKUP_PARENT; - return walk_component(nd, - nd->flags & LOOKUP_FOLLOW - ? nd->depth - ? WALK_PUT | WALK_GET - : WALK_GET - : 0); + return walk_component(nd, nd->depth ? WALK_PUT : 0); } /* Returns 0 and nd will be valid on success; Retuns error, otherwise. */ @@ -2623,7 +2618,7 @@ mountpoint_last(struct nameidata *nd) if (nd->depth) put_link(nd); path.mnt = nd->path.mnt; - error = should_follow_link(nd, &path, nd->flags & LOOKUP_FOLLOW, + error = should_follow_link(nd, &path, 0, d_backing_inode(path.dentry), 0); if (unlikely(error)) return error; @@ -3319,8 +3314,7 @@ static int do_last(struct nameidata *nd, finish_lookup: if (nd->depth) put_link(nd); - error = should_follow_link(nd, &path, nd->flags & LOOKUP_FOLLOW, - inode, seq); + error = should_follow_link(nd, &path, 0, inode, seq); if (unlikely(error)) return error; -- cgit v1.2.3 From 1c4ff1a87e46a06fc00a83da2fbbc3ac0298f221 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 14 Nov 2016 01:39:36 -0500 Subject: namei: invert WALK_PUT logics ... turning the condition for put_link() in walk_component() into "WALK_MORE not passed and depth is non-zero". Again, makes for simpler arguments. Signed-off-by: Al Viro --- fs/namei.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'fs') diff --git a/fs/namei.c b/fs/namei.c index 379168db782b..57d60922396e 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1747,7 +1747,7 @@ static inline int should_follow_link(struct nameidata *nd, struct path *link, return pick_link(nd, link, inode, seq); } -enum {WALK_GET = 1, WALK_PUT = 2}; +enum {WALK_GET = 1, WALK_MORE = 2}; static int walk_component(struct nameidata *nd, int flags) { @@ -1762,7 +1762,7 @@ static int walk_component(struct nameidata *nd, int flags) */ if (unlikely(nd->last_type != LAST_NORM)) { err = handle_dots(nd, nd->last_type); - if (flags & WALK_PUT) + if (!(flags & WALK_MORE) && nd->depth) put_link(nd); return err; } @@ -1789,7 +1789,7 @@ static int walk_component(struct nameidata *nd, int flags) inode = d_backing_inode(path.dentry); } - if (flags & WALK_PUT) + if (!(flags & WALK_MORE) && nd->depth) put_link(nd); err = should_follow_link(nd, &path, flags & WALK_GET, inode, seq); if (unlikely(err)) @@ -2104,9 +2104,10 @@ OK: if (!name) return 0; /* last component of nested symlink */ - err = walk_component(nd, WALK_GET | WALK_PUT); - } else { err = walk_component(nd, WALK_GET); + } else { + /* not the last component */ + err = walk_component(nd, WALK_GET | WALK_MORE); } if (err < 0) return err; @@ -2248,7 +2249,7 @@ static inline int lookup_last(struct nameidata *nd) nd->flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY; nd->flags &= ~LOOKUP_PARENT; - return walk_component(nd, nd->depth ? WALK_PUT : 0); + return walk_component(nd, 0); } /* Returns 0 and nd will be valid on success; Retuns error, otherwise. */ -- cgit v1.2.3 From 31d66bcd3f197d135145afb268996b4f5ea83459 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 14 Nov 2016 01:43:34 -0500 Subject: namei: pass both WALK_GET and WALK_MORE to should_follow_link() ... and pull put_link() logics into it. Signed-off-by: Al Viro --- fs/namei.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) (limited to 'fs') diff --git a/fs/namei.c b/fs/namei.c index 57d60922396e..5d31f0b2006d 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1725,6 +1725,8 @@ static int pick_link(struct nameidata *nd, struct path *link, return 1; } +enum {WALK_GET = 1, WALK_MORE = 2}; + /* * Do we need to follow links? We _really_ want to be able * to do this check without having to look at inode->i_op, @@ -1732,12 +1734,14 @@ static int pick_link(struct nameidata *nd, struct path *link, * for the common case. */ static inline int should_follow_link(struct nameidata *nd, struct path *link, - int follow, + int flags, struct inode *inode, unsigned seq) { + if (!(flags & WALK_MORE) && nd->depth) + put_link(nd); if (likely(!d_is_symlink(link->dentry))) return 0; - if (!follow && !(nd->flags & LOOKUP_FOLLOW)) + if (!(flags & WALK_GET) && !(nd->flags & LOOKUP_FOLLOW)) return 0; /* make sure that d_is_symlink above matches inode */ if (nd->flags & LOOKUP_RCU) { @@ -1747,8 +1751,6 @@ static inline int should_follow_link(struct nameidata *nd, struct path *link, return pick_link(nd, link, inode, seq); } -enum {WALK_GET = 1, WALK_MORE = 2}; - static int walk_component(struct nameidata *nd, int flags) { struct path path; @@ -1789,9 +1791,7 @@ static int walk_component(struct nameidata *nd, int flags) inode = d_backing_inode(path.dentry); } - if (!(flags & WALK_MORE) && nd->depth) - put_link(nd); - err = should_follow_link(nd, &path, flags & WALK_GET, inode, seq); + err = should_follow_link(nd, &path, flags, inode, seq); if (unlikely(err)) return err; path_to_nameidata(&path, nd); @@ -2616,8 +2616,6 @@ mountpoint_last(struct nameidata *nd) dput(path.dentry); return -ENOENT; } - if (nd->depth) - put_link(nd); path.mnt = nd->path.mnt; error = should_follow_link(nd, &path, 0, d_backing_inode(path.dentry), 0); @@ -3313,8 +3311,6 @@ static int do_last(struct nameidata *nd, seq = 0; /* out of RCU mode, so the value doesn't matter */ inode = d_backing_inode(path.dentry); finish_lookup: - if (nd->depth) - put_link(nd); error = should_follow_link(nd, &path, 0, inode, seq); if (unlikely(error)) return error; -- cgit v1.2.3 From 8f64fb1ccef331077a96cbfc3c23f91cbe563fd0 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 14 Nov 2016 01:50:26 -0500 Subject: namei: fold should_follow_link() with the step into not-followed link All callers are followed by the same boilerplate - "if it has returned 0, update nd->path/inode/seq - we are not following a symlink here". Pull it into the function itself, renaming it into step_into(). Rename WALK_GET to WALK_FOLLOW, while we are at it - more descriptive name. Signed-off-by: Al Viro --- fs/namei.c | 48 ++++++++++++++++++------------------------------ 1 file changed, 18 insertions(+), 30 deletions(-) (limited to 'fs') diff --git a/fs/namei.c b/fs/namei.c index 5d31f0b2006d..092ac5667ec7 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1725,7 +1725,7 @@ static int pick_link(struct nameidata *nd, struct path *link, return 1; } -enum {WALK_GET = 1, WALK_MORE = 2}; +enum {WALK_FOLLOW = 1, WALK_MORE = 2}; /* * Do we need to follow links? We _really_ want to be able @@ -1733,22 +1733,25 @@ enum {WALK_GET = 1, WALK_MORE = 2}; * so we keep a cache of "no, this doesn't need follow_link" * for the common case. */ -static inline int should_follow_link(struct nameidata *nd, struct path *link, - int flags, - struct inode *inode, unsigned seq) +static inline int step_into(struct nameidata *nd, struct path *path, + int flags, struct inode *inode, unsigned seq) { if (!(flags & WALK_MORE) && nd->depth) put_link(nd); - if (likely(!d_is_symlink(link->dentry))) - return 0; - if (!(flags & WALK_GET) && !(nd->flags & LOOKUP_FOLLOW)) + if (likely(!d_is_symlink(path->dentry)) || + !(flags & WALK_FOLLOW || nd->flags & LOOKUP_FOLLOW)) { + /* not a symlink or should not follow */ + path_to_nameidata(path, nd); + nd->inode = inode; + nd->seq = seq; return 0; + } /* make sure that d_is_symlink above matches inode */ if (nd->flags & LOOKUP_RCU) { - if (read_seqcount_retry(&link->dentry->d_seq, seq)) + if (read_seqcount_retry(&path->dentry->d_seq, seq)) return -ECHILD; } - return pick_link(nd, link, inode, seq); + return pick_link(nd, path, inode, seq); } static int walk_component(struct nameidata *nd, int flags) @@ -1791,13 +1794,7 @@ static int walk_component(struct nameidata *nd, int flags) inode = d_backing_inode(path.dentry); } - err = should_follow_link(nd, &path, flags, inode, seq); - if (unlikely(err)) - return err; - path_to_nameidata(&path, nd); - nd->inode = inode; - nd->seq = seq; - return 0; + return step_into(nd, &path, flags, inode, seq); } /* @@ -2104,10 +2101,10 @@ OK: if (!name) return 0; /* last component of nested symlink */ - err = walk_component(nd, WALK_GET); + err = walk_component(nd, WALK_FOLLOW); } else { /* not the last component */ - err = walk_component(nd, WALK_GET | WALK_MORE); + err = walk_component(nd, WALK_FOLLOW | WALK_MORE); } if (err < 0) return err; @@ -2617,12 +2614,7 @@ mountpoint_last(struct nameidata *nd) return -ENOENT; } path.mnt = nd->path.mnt; - error = should_follow_link(nd, &path, 0, - d_backing_inode(path.dentry), 0); - if (unlikely(error)) - return error; - path_to_nameidata(&path, nd); - return 0; + return step_into(nd, &path, 0, d_backing_inode(path.dentry), 0); } /** @@ -3311,15 +3303,11 @@ static int do_last(struct nameidata *nd, seq = 0; /* out of RCU mode, so the value doesn't matter */ inode = d_backing_inode(path.dentry); finish_lookup: - error = should_follow_link(nd, &path, 0, inode, seq); + error = step_into(nd, &path, 0, inode, seq); if (unlikely(error)) return error; - - path_to_nameidata(&path, nd); - nd->inode = inode; - nd->seq = seq; - /* Why this, you ask? _Now_ we might have grown LOOKUP_JUMPED... */ finish_open: + /* Why this, you ask? _Now_ we might have grown LOOKUP_JUMPED... */ error = complete_walk(nd); if (error) return error; -- cgit v1.2.3