X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=fs%2Fnamei.c;h=6ec1f0fefc5b017aa321738f7d3581370a91fad3;hb=17566c3c5ed3ea8f941a135cf960387214c4f6ac;hp=411bb3243c36fab5f302e0d055466149e4a55fa5;hpb=4b7b9772e4c3d87e649d4c419d2487aacf1235aa;p=powerpc.git diff --git a/fs/namei.c b/fs/namei.c index 411bb3243c..6ec1f0fefc 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include #include @@ -314,7 +314,7 @@ void path_release(struct nameidata *nd) void path_release_on_umount(struct nameidata *nd) { dput(nd->dentry); - _mntput(nd->mnt); + mntput_no_expire(nd->mnt); } /* @@ -501,19 +501,23 @@ struct path { static inline int __do_follow_link(struct path *path, struct nameidata *nd) { int error; + void *cookie; struct dentry *dentry = path->dentry; - touch_atime(nd->mnt, dentry); + touch_atime(path->mnt, dentry); nd_set_link(nd, NULL); - mntget(path->mnt); - error = dentry->d_inode->i_op->follow_link(dentry, nd); - if (!error) { + if (path->mnt == nd->mnt) + mntget(path->mnt); + cookie = dentry->d_inode->i_op->follow_link(dentry, nd); + error = PTR_ERR(cookie); + if (!IS_ERR(cookie)) { char *s = nd_get_link(nd); + error = 0; if (s) error = __vfs_follow_link(nd, s); if (dentry->d_inode->i_op->put_link) - dentry->d_inode->i_op->put_link(dentry, nd); + dentry->d_inode->i_op->put_link(dentry, nd, cookie); } dput(dentry); mntput(path->mnt); @@ -543,16 +547,14 @@ static inline int do_follow_link(struct path *path, struct nameidata *nd) current->link_count++; current->total_link_count++; nd->depth++; - if (path->mnt != nd->mnt) - mntput(nd->mnt); err = __do_follow_link(path, nd); current->link_count--; nd->depth--; return err; loop: - if (path->mnt != nd->mnt) - mntput(nd->mnt); dput(path->dentry); + if (path->mnt != nd->mnt) + mntput(path->mnt); path_release(nd); return err; } @@ -597,20 +599,17 @@ static int __follow_mount(struct path *path) return res; } -static int follow_mount(struct vfsmount **mnt, struct dentry **dentry) +static void follow_mount(struct vfsmount **mnt, struct dentry **dentry) { - int res = 0; while (d_mountpoint(*dentry)) { struct vfsmount *mounted = lookup_mnt(*mnt, *dentry); if (!mounted) break; + dput(*dentry); mntput(*mnt); *mnt = mounted; - dput(*dentry); *dentry = dget(mounted->mnt_root); - res = 1; } - return res; } /* no need for dcache_lock, as serialization is taken care in @@ -631,41 +630,41 @@ int follow_down(struct vfsmount **mnt, struct dentry **dentry) return 0; } -static inline void follow_dotdot(struct vfsmount **mnt, struct dentry **dentry) +static inline void follow_dotdot(struct nameidata *nd) { while(1) { struct vfsmount *parent; - struct dentry *old = *dentry; + struct dentry *old = nd->dentry; read_lock(¤t->fs->lock); - if (*dentry == current->fs->root && - *mnt == current->fs->rootmnt) { + if (nd->dentry == current->fs->root && + nd->mnt == current->fs->rootmnt) { read_unlock(¤t->fs->lock); break; } read_unlock(¤t->fs->lock); spin_lock(&dcache_lock); - if (*dentry != (*mnt)->mnt_root) { - *dentry = dget((*dentry)->d_parent); + if (nd->dentry != nd->mnt->mnt_root) { + nd->dentry = dget(nd->dentry->d_parent); spin_unlock(&dcache_lock); dput(old); break; } spin_unlock(&dcache_lock); spin_lock(&vfsmount_lock); - parent = (*mnt)->mnt_parent; - if (parent == *mnt) { + parent = nd->mnt->mnt_parent; + if (parent == nd->mnt) { spin_unlock(&vfsmount_lock); break; } mntget(parent); - *dentry = dget((*mnt)->mnt_mountpoint); + nd->dentry = dget(nd->mnt->mnt_mountpoint); spin_unlock(&vfsmount_lock); dput(old); - mntput(*mnt); - *mnt = parent; + mntput(nd->mnt); + nd->mnt = parent; } - follow_mount(mnt, dentry); + follow_mount(&nd->mnt, &nd->dentry); } /* @@ -686,6 +685,7 @@ static int do_lookup(struct nameidata *nd, struct qstr *name, done: path->mnt = mnt; path->dentry = dentry; + __follow_mount(path); return 0; need_lookup: @@ -773,7 +773,7 @@ static fastcall int __link_path_walk(const char * name, struct nameidata *nd) case 2: if (this.name[1] != '.') break; - follow_dotdot(&nd->mnt, &nd->dentry); + follow_dotdot(nd); inode = nd->dentry->d_inode; /* fallthrough */ case 1: @@ -793,8 +793,6 @@ static fastcall int __link_path_walk(const char * name, struct nameidata *nd) err = do_lookup(nd, &this, &next); if (err) break; - /* Check mountpoints.. */ - __follow_mount(&next); err = -ENOENT; inode = next.dentry->d_inode; @@ -840,7 +838,7 @@ last_component: case 2: if (this.name[1] != '.') break; - follow_dotdot(&nd->mnt, &nd->dentry); + follow_dotdot(nd); inode = nd->dentry->d_inode; /* fallthrough */ case 1: @@ -854,7 +852,6 @@ last_component: err = do_lookup(nd, &this, &next); if (err) break; - __follow_mount(&next); inode = next.dentry->d_inode; if ((lookup_flags & LOOKUP_FOLLOW) && inode && inode->i_op && inode->i_op->follow_link) { @@ -906,7 +903,7 @@ return_base: out_dput: dput(next.dentry); if (nd->mnt != next.mnt) - mntput(nd->mnt); + mntput(next.mnt); break; } path_release(nd); @@ -1318,7 +1315,7 @@ int vfs_create(struct inode *dir, struct dentry *dentry, int mode, DQUOT_INIT(dir); error = dir->i_op->create(dir, dentry, mode, nd); if (!error) { - inode_dir_notify(dir, DN_CREATE); + fsnotify_create(dir, dentry->d_name.name); security_inode_post_create(dir, dentry, mode); } return error; @@ -1550,9 +1547,6 @@ do_link: error = security_inode_follow_link(path.dentry, nd); if (error) goto exit_dput; - if (nd->mnt != path.mnt) - mntput(nd->mnt); - nd->mnt = path.mnt; error = __do_follow_link(&path, nd); if (error) return error; @@ -1586,19 +1580,35 @@ do_link: * * Simple function to lookup and return a dentry and create it * if it doesn't exist. Is SMP-safe. + * + * Returns with nd->dentry->d_inode->i_sem locked. */ struct dentry *lookup_create(struct nameidata *nd, int is_dir) { - struct dentry *dentry; + struct dentry *dentry = ERR_PTR(-EEXIST); down(&nd->dentry->d_inode->i_sem); - dentry = ERR_PTR(-EEXIST); + /* + * Yucky last component or no last component at all? + * (foo/., foo/.., /////) + */ if (nd->last_type != LAST_NORM) goto fail; nd->flags &= ~LOOKUP_PARENT; + + /* + * Do the final lookup. + */ dentry = lookup_hash(&nd->last, nd->dentry); if (IS_ERR(dentry)) goto fail; + + /* + * Special case - lookup gave negative, but... we had foo/bar/ + * From the vfs_mknod() POV we just have a negative dentry - + * all is fine. Let's be bastards - you had / on the end, you've + * been asking for (non-existent) directory. -ENOENT for you. + */ if (!is_dir && nd->last.name[nd->last.len] && !dentry->d_inode) goto enoent; return dentry; @@ -1630,7 +1640,7 @@ int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) DQUOT_INIT(dir); error = dir->i_op->mknod(dir, dentry, mode, dev); if (!error) { - inode_dir_notify(dir, DN_CREATE); + fsnotify_create(dir, dentry->d_name.name); security_inode_post_mknod(dir, dentry, mode, dev); } return error; @@ -1703,7 +1713,7 @@ int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) DQUOT_INIT(dir); error = dir->i_op->mkdir(dir, dentry, mode); if (!error) { - inode_dir_notify(dir, DN_CREATE); + fsnotify_mkdir(dir, dentry->d_name.name); security_inode_post_mkdir(dir,dentry, mode); } return error; @@ -1794,7 +1804,6 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry) } up(&dentry->d_inode->i_sem); if (!error) { - inode_dir_notify(dir, DN_DELETE); d_delete(dentry); } dput(dentry); @@ -1868,8 +1877,8 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry) /* We don't d_delete() NFS sillyrenamed files--they still exist. */ if (!error && !(dentry->d_flags & DCACHE_NFSFS_RENAMED)) { d_delete(dentry); - inode_dir_notify(dir, DN_DELETE); } + return error; } @@ -1943,7 +1952,7 @@ int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname, i DQUOT_INIT(dir); error = dir->i_op->symlink(dir, dentry, oldname); if (!error) { - inode_dir_notify(dir, DN_CREATE); + fsnotify_create(dir, dentry->d_name.name); security_inode_post_symlink(dir, dentry, oldname); } return error; @@ -2016,7 +2025,7 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de error = dir->i_op->link(old_dentry, dir, new_dentry); up(&old_dentry->d_inode->i_sem); if (!error) { - inode_dir_notify(dir, DN_CREATE); + fsnotify_create(dir, new_dentry->d_name.name); security_inode_post_link(old_dentry, dir, new_dentry); } return error; @@ -2180,6 +2189,7 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, { int error; int is_dir = S_ISDIR(old_dentry->d_inode->i_mode); + const char *old_name; if (old_dentry->d_inode == new_dentry->d_inode) return 0; @@ -2201,18 +2211,19 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, DQUOT_INIT(old_dir); DQUOT_INIT(new_dir); + old_name = fsnotify_oldname_init(old_dentry->d_name.name); + if (is_dir) error = vfs_rename_dir(old_dir,old_dentry,new_dir,new_dentry); else error = vfs_rename_other(old_dir,old_dentry,new_dir,new_dentry); if (!error) { - if (old_dir == new_dir) - inode_dir_notify(old_dir, DN_RENAME); - else { - inode_dir_notify(old_dir, DN_DELETE); - inode_dir_notify(new_dir, DN_CREATE); - } + const char *new_name = old_dentry->d_name.name; + fsnotify_move(old_dir, new_dir, old_name, new_name, is_dir, + new_dentry->d_inode, old_dentry->d_inode); } + fsnotify_oldname_free(old_name); + return error; } @@ -2336,15 +2347,17 @@ out: int generic_readlink(struct dentry *dentry, char __user *buffer, int buflen) { struct nameidata nd; - int res; + void *cookie; + nd.depth = 0; - res = dentry->d_inode->i_op->follow_link(dentry, &nd); - if (!res) { - res = vfs_readlink(dentry, buffer, buflen, nd_get_link(&nd)); + cookie = dentry->d_inode->i_op->follow_link(dentry, &nd); + if (!IS_ERR(cookie)) { + int res = vfs_readlink(dentry, buffer, buflen, nd_get_link(&nd)); if (dentry->d_inode->i_op->put_link) - dentry->d_inode->i_op->put_link(dentry, &nd); + dentry->d_inode->i_op->put_link(dentry, &nd, cookie); + cookie = ERR_PTR(res); } - return res; + return PTR_ERR(cookie); } int vfs_follow_link(struct nameidata *nd, const char *link) @@ -2387,23 +2400,20 @@ int page_readlink(struct dentry *dentry, char __user *buffer, int buflen) return res; } -int page_follow_link_light(struct dentry *dentry, struct nameidata *nd) +void *page_follow_link_light(struct dentry *dentry, struct nameidata *nd) { - struct page *page; + struct page *page = NULL; nd_set_link(nd, page_getlink(dentry, &page)); - return 0; + return page; } -void page_put_link(struct dentry *dentry, struct nameidata *nd) +void page_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie) { - if (!IS_ERR(nd_get_link(nd))) { - struct page *page; - page = find_get_page(dentry->d_inode->i_mapping, 0); - if (!page) - BUG(); + struct page *page = cookie; + + if (page) { kunmap(page); page_cache_release(page); - page_cache_release(page); } }