diff options
author | NeilBrown <neilb@suse.de> | 2015-03-23 13:37:40 +1100 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2015-05-15 01:06:27 -0400 |
commit | 8fa9dd24667f2d6997ec21341019657342859d31 (patch) | |
tree | cb7dcfaa0346a06e527cd4d095d7305eda6686ad /fs/namei.c | |
parent | bc40aee053be1c2c443e812034f41e1a3cf34752 (diff) | |
download | op-kernel-dev-8fa9dd24667f2d6997ec21341019657342859d31.zip op-kernel-dev-8fa9dd24667f2d6997ec21341019657342859d31.tar.gz |
VFS/namei: make the use of touch_atime() in get_link() RCU-safe.
touch_atime is not RCU-safe, and so cannot be called on an RCU walk.
However, in situations where RCU-walk makes a difference, the symlink
will likely to accessed much more often than it is useful to update
the atime.
So split out the test of "Does the atime actually need to be updated"
into atime_needs_update(), and have get_link() unlazy if it finds that
it will need to do that update.
Signed-off-by: NeilBrown <neilb@suse.de>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/namei.c')
-rw-r--r-- | fs/namei.c | 12 |
1 files changed, 9 insertions, 3 deletions
@@ -966,13 +966,19 @@ const char *get_link(struct nameidata *nd) int error; const char *res; - if (nd->flags & LOOKUP_RCU) { + if (!(nd->flags & LOOKUP_RCU)) { + touch_atime(&last->link); + cond_resched(); + } else if (atime_needs_update(&last->link, inode)) { if (unlikely(unlazy_walk(nd, NULL, 0))) return ERR_PTR(-ECHILD); + touch_atime(&last->link); } - cond_resched(); - touch_atime(&last->link); + if (nd->flags & LOOKUP_RCU) { + if (unlikely(unlazy_walk(nd, NULL, 0))) + return ERR_PTR(-ECHILD); + } error = security_inode_follow_link(dentry, inode, nd->flags & LOOKUP_RCU); |