(10/19)
In open_namei(), __follow_down() loop turned into __follow_mount().
Instead of
if we are on a mountpoint dentry
if O_NOFOLLOW checks fail
drop path.dentry
drop nd
return
do equivalent of follow_mount(&path.mnt, &path.dentry)
nd->mnt = path.mnt
we do
if __follow_mount(path) had, indeed, traversed mountpoint
/* now both nd->mnt and path.mnt are pinned down */
if O_NOFOLLOW checks fail
drop path.dentry
drop path.mnt
drop nd
return
mntput(nd->mnt)
nd->mnt = path.mnt
Now __follow_down() can be folded into follow_down() - no other callers
left. We need to reorder dput()/mntput() there - same problem as in
follow_mount().
Equivalent transformation + fix for a bug in O_NOFOLLOW handling - we
used to get -ELOOP if we had the same fs mounted on /foo and /bar, had
something bound on /bar/baz and tried to open /foo/baz with O_NOFOLLOW.
And fix of too-early-mntput() race in follow_down()
Signed-off-by: Al Viro <[email protected]>
----
diff -urN RC12-rc4-9/fs/namei.c RC12-rc4-10/fs/namei.c
--- RC12-rc4-9/fs/namei.c 2005-05-19 16:39:38.069917746 -0400
+++ RC12-rc4-10/fs/namei.c 2005-05-19 16:39:39.207691029 -0400
@@ -612,26 +612,21 @@
/* no need for dcache_lock, as serialization is taken care in
* namespace.c
*/
-static inline int __follow_down(struct vfsmount **mnt, struct dentry **dentry)
+int follow_down(struct vfsmount **mnt, struct dentry **dentry)
{
struct vfsmount *mounted;
mounted = lookup_mnt(*mnt, *dentry);
if (mounted) {
+ dput(*dentry);
mntput(*mnt);
*mnt = mounted;
- dput(*dentry);
*dentry = dget(mounted->mnt_root);
return 1;
}
return 0;
}
-int follow_down(struct vfsmount **mnt, struct dentry **dentry)
-{
- return __follow_down(mnt,dentry);
-}
-
static inline void follow_dotdot(struct vfsmount **mnt, struct dentry **dentry)
{
while(1) {
@@ -1498,11 +1493,14 @@
if (flag & O_EXCL)
goto exit_dput;
- if (d_mountpoint(path.dentry)) {
+ if (__follow_mount(&path)) {
error = -ELOOP;
- if (flag & O_NOFOLLOW)
- goto exit_dput;
- while (__follow_down(&path.mnt,&path.dentry) && d_mountpoint(path.dentry));
+ if (flag & O_NOFOLLOW) {
+ dput(path.dentry);
+ mntput(path.mnt);
+ goto exit;
+ }
+ mntput(nd->mnt);
nd->mnt = path.mnt;
}
error = -ENOENT;
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[Index of Archives]
[Kernel Newbies]
[Netfilter]
[Bugtraq]
[Photo]
[Stuff]
[Gimp]
[Yosemite News]
[MIPS Linux]
[ARM Linux]
[Linux Security]
[Linux RAID]
[Video 4 Linux]
[Linux for the blind]
[Linux Resources]