From 496ad9aa8ef448058e36ca7a787c61f2e63f0f54 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 23 Jan 2013 17:07:38 -0500 Subject: new helper: file_inode(file) Signed-off-by: Al Viro --- fs/namei.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs/namei.c') diff --git a/fs/namei.c b/fs/namei.c index 43a97ee..df00b75 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -2778,7 +2778,7 @@ retry_lookup: goto out; if ((*opened & FILE_CREATED) || - !S_ISREG(file->f_path.dentry->d_inode->i_mode)) + !S_ISREG(file_inode(file)->i_mode)) will_truncate = false; audit_inode(name, file->f_path.dentry, 0); -- cgit v1.1 From 1afc99beaf0fca3767d9b67789a7ae91c4f7a9c9 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 14 Feb 2013 20:41:04 -0500 Subject: propagate error from get_empty_filp() to its callers Based on parts from Anatol's patch (the rest is the next commit). Signed-off-by: Al Viro --- fs/namei.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'fs/namei.c') diff --git a/fs/namei.c b/fs/namei.c index df00b75..e0a33f5 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -2941,8 +2941,8 @@ static struct file *path_openat(int dfd, struct filename *pathname, int error; file = get_empty_filp(); - if (!file) - return ERR_PTR(-ENFILE); + if (IS_ERR(file)) + return file; file->f_flags = op->open_flag; -- cgit v1.1 From 5f4a6a695075b79261793c25b1128e3b30007646 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 24 Jan 2013 18:04:22 -0500 Subject: link_path_walk(): move assignments to nd->last/nd->last_type up ... and clean the main loop a bit Signed-off-by: Al Viro --- fs/namei.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) (limited to 'fs/namei.c') diff --git a/fs/namei.c b/fs/namei.c index e0a33f5..14eab84 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1802,8 +1802,11 @@ static int link_path_walk(const char *name, struct nameidata *nd) } } + nd->last = this; + nd->last_type = type; + if (!name[len]) - goto last_component; + return 0; /* * If it wasn't NUL, we know it was '/'. Skip that * slash, and continue until no more slashes. @@ -1812,7 +1815,8 @@ static int link_path_walk(const char *name, struct nameidata *nd) len++; } while (unlikely(name[len] == '/')); if (!name[len]) - goto last_component; + return 0; + name += len; err = walk_component(nd, &next, &this, type, LOOKUP_FOLLOW); @@ -1824,16 +1828,10 @@ static int link_path_walk(const char *name, struct nameidata *nd) if (err) return err; } - if (can_lookup(nd->inode)) - continue; - err = -ENOTDIR; - break; - /* here ends the main loop */ - -last_component: - nd->last = this; - nd->last_type = type; - return 0; + if (!can_lookup(nd->inode)) { + err = -ENOTDIR; + break; + } } terminate_walk(nd); return err; -- cgit v1.1 From 21b9b073924aceb6b8d19c49f61daa86c0340e1a Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 24 Jan 2013 18:10:25 -0500 Subject: get rid of name and type arguments of walk_component() ... always can be found in nameidata now. Signed-off-by: Al Viro --- fs/namei.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'fs/namei.c') diff --git a/fs/namei.c b/fs/namei.c index 14eab84..5f6da6c 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1519,7 +1519,7 @@ static inline int should_follow_link(struct inode *inode, int follow) } static inline int walk_component(struct nameidata *nd, struct path *path, - struct qstr *name, int type, int follow) + int follow) { struct inode *inode; int err; @@ -1528,14 +1528,14 @@ static inline int walk_component(struct nameidata *nd, struct path *path, * to be able to know about the current root directory and * parent relationships. */ - if (unlikely(type != LAST_NORM)) - return handle_dots(nd, type); - err = lookup_fast(nd, name, path, &inode); + if (unlikely(nd->last_type != LAST_NORM)) + return handle_dots(nd, nd->last_type); + err = lookup_fast(nd, &nd->last, path, &inode); if (unlikely(err)) { if (err < 0) goto out_err; - err = lookup_slow(nd, name, path); + err = lookup_slow(nd, &nd->last, path); if (err < 0) goto out_err; @@ -1594,8 +1594,7 @@ static inline int nested_symlink(struct path *path, struct nameidata *nd) res = follow_link(&link, nd, &cookie); if (res) break; - res = walk_component(nd, path, &nd->last, - nd->last_type, LOOKUP_FOLLOW); + res = walk_component(nd, path, LOOKUP_FOLLOW); put_link(nd, &link, cookie); } while (res > 0); @@ -1819,7 +1818,7 @@ static int link_path_walk(const char *name, struct nameidata *nd) name += len; - err = walk_component(nd, &next, &this, type, LOOKUP_FOLLOW); + err = walk_component(nd, &next, LOOKUP_FOLLOW); if (err < 0) return err; @@ -1930,8 +1929,7 @@ static inline int lookup_last(struct nameidata *nd, struct path *path) nd->flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY; nd->flags &= ~LOOKUP_PARENT; - return walk_component(nd, path, &nd->last, nd->last_type, - nd->flags & LOOKUP_FOLLOW); + return walk_component(nd, path, nd->flags & LOOKUP_FOLLOW); } /* Returns 0 and nd will be valid on success; Retuns error, otherwise. */ -- cgit v1.1 From e97cdc87be5804eb2922e169f6d81d3e214587ec Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 24 Jan 2013 18:16:00 -0500 Subject: lookup_fast: get rid of name argument Signed-off-by: Al Viro --- fs/namei.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'fs/namei.c') diff --git a/fs/namei.c b/fs/namei.c index 5f6da6c..2782382 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1342,7 +1342,7 @@ static struct dentry *__lookup_hash(struct qstr *name, * small and for now I'd prefer to have fast path as straight as possible. * It _is_ time-critical. */ -static int lookup_fast(struct nameidata *nd, struct qstr *name, +static int lookup_fast(struct nameidata *nd, struct path *path, struct inode **inode) { struct vfsmount *mnt = nd->path.mnt; @@ -1358,7 +1358,7 @@ static int lookup_fast(struct nameidata *nd, struct qstr *name, */ if (nd->flags & LOOKUP_RCU) { unsigned seq; - dentry = __d_lookup_rcu(parent, name, &seq, nd->inode); + dentry = __d_lookup_rcu(parent, &nd->last, &seq, nd->inode); if (!dentry) goto unlazy; @@ -1400,7 +1400,7 @@ unlazy: if (unlazy_walk(nd, dentry)) return -ECHILD; } else { - dentry = __d_lookup(parent, name); + dentry = __d_lookup(parent, &nd->last); } if (unlikely(!dentry)) @@ -1530,7 +1530,7 @@ static inline int walk_component(struct nameidata *nd, struct path *path, */ if (unlikely(nd->last_type != LAST_NORM)) return handle_dots(nd, nd->last_type); - err = lookup_fast(nd, &nd->last, path, &inode); + err = lookup_fast(nd, path, &inode); if (unlikely(err)) { if (err < 0) goto out_err; @@ -2728,7 +2728,7 @@ static int do_last(struct nameidata *nd, struct path *path, if (open_flag & O_PATH && !(nd->flags & LOOKUP_FOLLOW)) symlink_ok = true; /* we _can_ be in RCU mode here */ - error = lookup_fast(nd, &nd->last, path, &inode); + error = lookup_fast(nd, path, &inode); if (likely(!error)) goto finish_lookup; -- cgit v1.1 From cc2a5271155a108c9c6a8d70ec4e4f860f32cd07 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 24 Jan 2013 18:19:49 -0500 Subject: lookup_slow: get rid of name argument Signed-off-by: Al Viro --- fs/namei.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'fs/namei.c') diff --git a/fs/namei.c b/fs/namei.c index 2782382..052c095 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1436,8 +1436,7 @@ need_lookup: } /* Fast lookup failed, do it the slow way */ -static int lookup_slow(struct nameidata *nd, struct qstr *name, - struct path *path) +static int lookup_slow(struct nameidata *nd, struct path *path) { struct dentry *dentry, *parent; int err; @@ -1446,7 +1445,7 @@ static int lookup_slow(struct nameidata *nd, struct qstr *name, BUG_ON(nd->inode != parent->d_inode); mutex_lock(&parent->d_inode->i_mutex); - dentry = __lookup_hash(name, parent, nd->flags); + dentry = __lookup_hash(&nd->last, parent, nd->flags); mutex_unlock(&parent->d_inode->i_mutex); if (IS_ERR(dentry)) return PTR_ERR(dentry); @@ -1535,7 +1534,7 @@ static inline int walk_component(struct nameidata *nd, struct path *path, if (err < 0) goto out_err; - err = lookup_slow(nd, &nd->last, path); + err = lookup_slow(nd, path); if (err < 0) goto out_err; -- cgit v1.1 From ecf3d1f1aa74da0d632b651a2e05a911f60e92c0 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 20 Feb 2013 11:19:05 -0500 Subject: vfs: kill FS_REVAL_DOT by adding a d_weak_revalidate dentry op The following set of operations on a NFS client and server will cause server# mkdir a client# cd a server# mv a a.bak client# sleep 30 # (or whatever the dir attrcache timeout is) client# stat . stat: cannot stat `.': Stale NFS file handle Obviously, we should not be getting an ESTALE error back there since the inode still exists on the server. The problem is that the lookup code will call d_revalidate on the dentry that "." refers to, because NFS has FS_REVAL_DOT set. nfs_lookup_revalidate will see that the parent directory has changed and will try to reverify the dentry by redoing a LOOKUP. That of course fails, so the lookup code returns ESTALE. The problem here is that d_revalidate is really a bad fit for this case. What we really want to know at this point is whether the inode is still good or not, but we don't really care what name it goes by or whether the dcache is still valid. Add a new d_op->d_weak_revalidate operation and have complete_walk call that instead of d_revalidate. The intent there is to allow for a "weaker" d_revalidate that just checks to see whether the inode is still good. This is also gives us an opportunity to kill off the FS_REVAL_DOT special casing. [AV: changed method name, added note in porting, fixed confusion re having it possibly called from RCU mode (it won't be)] Cc: NeilBrown Signed-off-by: Jeff Layton Signed-off-by: Al Viro --- fs/namei.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'fs/namei.c') diff --git a/fs/namei.c b/fs/namei.c index 052c095..dc984fe 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -600,14 +600,10 @@ static int complete_walk(struct nameidata *nd) if (likely(!(nd->flags & LOOKUP_JUMPED))) return 0; - if (likely(!(dentry->d_flags & DCACHE_OP_REVALIDATE))) + if (likely(!(dentry->d_flags & DCACHE_OP_WEAK_REVALIDATE))) return 0; - if (likely(!(dentry->d_sb->s_type->fs_flags & FS_REVAL_DOT))) - return 0; - - /* Note: we do not d_invalidate() */ - status = d_revalidate(dentry, nd->flags); + status = dentry->d_op->d_weak_revalidate(dentry, nd->flags); if (status > 0) return 0; -- cgit v1.1