X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=fs%2Fnamei.c;h=21d85f1ac8395f82376e2dd5073494d568080e78;hb=b01ef8ffafc5239a871bc24af74f604654e7de2b;hp=4a27eb798118957544d52c9edbe013f30ce9cc43;hpb=8066eff0a1a0703ad901dbe5646a47dbfc089ef2;p=linux-2.6 diff --git a/fs/namei.c b/fs/namei.c index 4a27eb7981..21d85f1ac8 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -501,6 +501,7 @@ 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(path->mnt, dentry); @@ -508,13 +509,15 @@ static inline int __do_follow_link(struct path *path, struct nameidata *nd) if (path->mnt == nd->mnt) mntget(path->mnt); - error = dentry->d_inode->i_op->follow_link(dentry, nd); - if (!error) { + 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); @@ -522,6 +525,22 @@ static inline int __do_follow_link(struct path *path, struct nameidata *nd) return error; } +static inline void dput_path(struct path *path, struct nameidata *nd) +{ + dput(path->dentry); + if (path->mnt != nd->mnt) + mntput(path->mnt); +} + +static inline void path_to_nameidata(struct path *path, struct nameidata *nd) +{ + dput(nd->dentry); + if (nd->mnt != path->mnt) + mntput(nd->mnt); + nd->mnt = path->mnt; + nd->dentry = path->dentry; +} + /* * This limits recursive symlink follows to 8, while * limiting consecutive symlinks to 40. @@ -549,9 +568,7 @@ static inline int do_follow_link(struct path *path, struct nameidata *nd) nd->depth--; return err; loop: - dput(path->dentry); - if (path->mnt != nd->mnt) - mntput(path->mnt); + dput_path(path, nd); path_release(nd); return err; } @@ -810,13 +827,8 @@ static fastcall int __link_path_walk(const char * name, struct nameidata *nd) err = -ENOTDIR; if (!inode->i_op) break; - } else { - dput(nd->dentry); - if (nd->mnt != next.mnt) - mntput(nd->mnt); - nd->mnt = next.mnt; - nd->dentry = next.dentry; - } + } else + path_to_nameidata(&next, nd); err = -ENOTDIR; if (!inode->i_op->lookup) break; @@ -856,13 +868,8 @@ last_component: if (err) goto return_err; inode = nd->dentry->d_inode; - } else { - dput(nd->dentry); - if (nd->mnt != next.mnt) - mntput(nd->mnt); - nd->mnt = next.mnt; - nd->dentry = next.dentry; - } + } else + path_to_nameidata(&next, nd); err = -ENOENT; if (!inode) break; @@ -898,9 +905,7 @@ return_reval: return_base: return 0; out_dput: - dput(next.dentry); - if (nd->mnt != next.mnt) - mntput(next.mnt); + dput_path(&next, nd); break; } path_release(nd); @@ -1311,10 +1316,8 @@ int vfs_create(struct inode *dir, struct dentry *dentry, int mode, return error; DQUOT_INIT(dir); error = dir->i_op->create(dir, dentry, mode, nd); - if (!error) { + if (!error) fsnotify_create(dir, dentry->d_name.name); - security_inode_post_create(dir, dentry, mode); - } return error; } @@ -1504,11 +1507,7 @@ do_last: if (path.dentry->d_inode->i_op && path.dentry->d_inode->i_op->follow_link) goto do_link; - dput(nd->dentry); - nd->dentry = path.dentry; - if (nd->mnt != path.mnt) - mntput(nd->mnt); - nd->mnt = path.mnt; + path_to_nameidata(&path, nd); error = -EISDIR; if (path.dentry->d_inode && S_ISDIR(path.dentry->d_inode->i_mode)) goto exit; @@ -1519,9 +1518,7 @@ ok: return 0; exit_dput: - dput(path.dentry); - if (nd->mnt != path.mnt) - mntput(path.mnt); + dput_path(&path, nd); exit: path_release(nd); return error; @@ -1636,10 +1633,8 @@ 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) { + if (!error) fsnotify_create(dir, dentry->d_name.name); - security_inode_post_mknod(dir, dentry, mode, dev); - } return error; } @@ -1709,10 +1704,8 @@ int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) DQUOT_INIT(dir); error = dir->i_op->mkdir(dir, dentry, mode); - if (!error) { + if (!error) fsnotify_mkdir(dir, dentry->d_name.name); - security_inode_post_mkdir(dir,dentry, mode); - } return error; } @@ -1801,7 +1794,6 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry) } up(&dentry->d_inode->i_sem); if (!error) { - fsnotify_rmdir(dentry, dentry->d_inode, dir); d_delete(dentry); } dput(dentry); @@ -1874,7 +1866,6 @@ 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)) { - fsnotify_unlink(dentry, dir); d_delete(dentry); } @@ -1950,10 +1941,8 @@ 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) { + if (!error) fsnotify_create(dir, dentry->d_name.name); - security_inode_post_symlink(dir, dentry, oldname); - } return error; } @@ -2023,10 +2012,8 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de DQUOT_INIT(dir); error = dir->i_op->link(old_dentry, dir, new_dentry); up(&old_dentry->d_inode->i_sem); - if (!error) { + if (!error) fsnotify_create(dir, new_dentry->d_name.name); - security_inode_post_link(old_dentry, dir, new_dentry); - } return error; } @@ -2145,11 +2132,8 @@ static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry, d_rehash(new_dentry); dput(new_dentry); } - if (!error) { + if (!error) d_move(old_dentry,new_dentry); - security_inode_post_rename(old_dir, old_dentry, - new_dir, new_dentry); - } return error; } @@ -2175,7 +2159,6 @@ static int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry, /* The following d_move() should become unconditional */ if (!(old_dir->i_sb->s_type->fs_flags & FS_ODD_RENAME)) d_move(old_dentry, new_dentry); - security_inode_post_rename(old_dir, old_dentry, new_dir, new_dentry); } if (target) up(&target->i_sem); @@ -2218,7 +2201,8 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, error = vfs_rename_other(old_dir,old_dentry,new_dir,new_dentry); if (!error) { 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); + 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); @@ -2345,15 +2329,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) @@ -2396,23 +2382,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); } }