diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2015-12-29 21:58:39 +0100 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2015-12-30 19:01:03 +0100 |
commit | fceef393a538134f03b778c5d2519e670269342f (patch) | |
tree | cd43c9afdc07852d286965ad4d11772f6c275d1a /fs | |
parent | kill free_page_put_link() (diff) | |
download | linux-fceef393a538134f03b778c5d2519e670269342f.tar.xz linux-fceef393a538134f03b778c5d2519e670269342f.zip |
switch ->get_link() to delayed_call, kill ->put_link()
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs')
36 files changed, 130 insertions, 180 deletions
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 8ba5a897fc0a..f928f8702f4c 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -1226,11 +1226,12 @@ ino_t v9fs_qid2ino(struct p9_qid *qid) * v9fs_vfs_get_link - follow a symlink path * @dentry: dentry for symlink * @inode: inode for symlink - * @cookie: place to pass the data to put_link() + * @done: delayed call for when we are done with the return value */ static const char *v9fs_vfs_get_link(struct dentry *dentry, - struct inode *inode, void **cookie) + struct inode *inode, + struct delayed_call *done) { struct v9fs_session_info *v9ses; struct p9_fid *fid; @@ -1266,7 +1267,8 @@ static const char *v9fs_vfs_get_link(struct dentry *dentry, p9stat_free(st); kfree(st); - return *cookie = res; + set_delayed_call(done, kfree_link, res); + return res; } /** @@ -1460,7 +1462,6 @@ static const struct inode_operations v9fs_file_inode_operations = { static const struct inode_operations v9fs_symlink_inode_operations = { .readlink = generic_readlink, .get_link = v9fs_vfs_get_link, - .put_link = kfree_put_link, .getattr = v9fs_vfs_getattr, .setattr = v9fs_vfs_setattr, }; diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c index 0cc105d804dd..a34702c998f5 100644 --- a/fs/9p/vfs_inode_dotl.c +++ b/fs/9p/vfs_inode_dotl.c @@ -902,12 +902,13 @@ error: * v9fs_vfs_get_link_dotl - follow a symlink path * @dentry: dentry for symlink * @inode: inode for symlink - * @cookie: place to pass the data to put_link() + * @done: destructor for return value */ static const char * v9fs_vfs_get_link_dotl(struct dentry *dentry, - struct inode *inode, void **cookie) + struct inode *inode, + struct delayed_call *done) { struct p9_fid *fid; char *target; @@ -924,7 +925,8 @@ v9fs_vfs_get_link_dotl(struct dentry *dentry, retval = p9_client_readlink(fid, &target); if (retval) return ERR_PTR(retval); - return *cookie = target; + set_delayed_call(done, kfree_link, target); + return target; } int v9fs_refresh_inode_dotl(struct p9_fid *fid, struct inode *inode) @@ -991,7 +993,6 @@ const struct inode_operations v9fs_file_inode_operations_dotl = { const struct inode_operations v9fs_symlink_inode_operations_dotl = { .readlink = generic_readlink, .get_link = v9fs_vfs_get_link_dotl, - .put_link = kfree_put_link, .getattr = v9fs_vfs_getattr_dotl, .setattr = v9fs_vfs_setattr_dotl, .setxattr = generic_setxattr, diff --git a/fs/affs/symlink.c b/fs/affs/symlink.c index 39d1194445e1..69b03dbb792f 100644 --- a/fs/affs/symlink.c +++ b/fs/affs/symlink.c @@ -72,6 +72,5 @@ const struct address_space_operations affs_symlink_aops = { const struct inode_operations affs_symlink_inode_operations = { .readlink = generic_readlink, .get_link = page_get_link, - .put_link = page_put_link, .setattr = affs_notify_change, }; diff --git a/fs/autofs4/symlink.c b/fs/autofs4/symlink.c index 39e6f0bdf8e3..84e037d1d129 100644 --- a/fs/autofs4/symlink.c +++ b/fs/autofs4/symlink.c @@ -13,7 +13,8 @@ #include "autofs_i.h" static const char *autofs4_get_link(struct dentry *dentry, - struct inode *inode, void **cookie) + struct inode *inode, + struct delayed_call *done) { struct autofs_sb_info *sbi; struct autofs_info *ino; diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 3d4aa69f1e0c..1a41a65fd2ff 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -10097,7 +10097,6 @@ static const struct inode_operations btrfs_special_inode_operations = { static const struct inode_operations btrfs_symlink_inode_operations = { .readlink = generic_readlink, .get_link = page_get_link, - .put_link = page_put_link, .getattr = btrfs_getattr, .setattr = btrfs_setattr, .permission = btrfs_permission, diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 4593f41678ef..90e4e2b398b6 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -901,7 +901,6 @@ const struct inode_operations cifs_file_inode_ops = { const struct inode_operations cifs_symlink_inode_ops = { .readlink = generic_readlink, .get_link = cifs_get_link, - .put_link = kfree_put_link, .permission = cifs_permission, /* BB add the following two eventually */ /* revalidate: cifs_revalidate, diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 6886328cf3c4..26a1187d4323 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -120,7 +120,8 @@ extern struct vfsmount *cifs_dfs_d_automount(struct path *path); #endif /* Functions related to symlinks */ -extern const char *cifs_get_link(struct dentry *, struct inode *, void **); +extern const char *cifs_get_link(struct dentry *, struct inode *, + struct delayed_call *); extern int cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname); extern int cifs_removexattr(struct dentry *, const char *); diff --git a/fs/cifs/link.c b/fs/cifs/link.c index 6f2439b508b5..062c2375549a 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c @@ -627,7 +627,8 @@ cifs_hl_exit: } const char * -cifs_get_link(struct dentry *direntry, struct inode *inode, void **cookie) +cifs_get_link(struct dentry *direntry, struct inode *inode, + struct delayed_call *done) { int rc = -ENOMEM; unsigned int xid; @@ -680,7 +681,8 @@ cifs_get_link(struct dentry *direntry, struct inode *inode, void **cookie) kfree(target_path); return ERR_PTR(rc); } - return *cookie = target_path; + set_delayed_call(done, kfree_link, target_path); + return target_path; } int diff --git a/fs/coda/cnode.c b/fs/coda/cnode.c index f18139c7690a..1bfb7ba4e85e 100644 --- a/fs/coda/cnode.c +++ b/fs/coda/cnode.c @@ -19,7 +19,6 @@ static inline int coda_fideq(struct CodaFid *fid1, struct CodaFid *fid2) static const struct inode_operations coda_symlink_inode_operations = { .readlink = generic_readlink, .get_link = page_get_link, - .put_link = page_put_link, .setattr = coda_setattr, }; diff --git a/fs/configfs/symlink.c b/fs/configfs/symlink.c index e9de962e518d..db6d69289608 100644 --- a/fs/configfs/symlink.c +++ b/fs/configfs/symlink.c @@ -280,31 +280,32 @@ static int configfs_getlink(struct dentry *dentry, char * path) } static const char *configfs_get_link(struct dentry *dentry, - struct inode *inode, void **cookie) + struct inode *inode, + struct delayed_call *done) { - char *page; + char *body; int error; if (!dentry) return ERR_PTR(-ECHILD); - page = kzalloc(PAGE_SIZE, GFP_KERNEL); - if (!page) + body = kzalloc(PAGE_SIZE, GFP_KERNEL); + if (!body) return ERR_PTR(-ENOMEM); - error = configfs_getlink(dentry, page); + error = configfs_getlink(dentry, body); if (!error) { - return *cookie = page; + set_delayed_call(done, kfree_link, body); + return body; } - kfree(page); + kfree(body); return ERR_PTR(error); } const struct inode_operations configfs_symlink_inode_operations = { .get_link = configfs_get_link, .readlink = generic_readlink, - .put_link = kfree_put_link, .setattr = configfs_setattr, }; diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index 5a05559cb23d..a4dddc61594c 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -675,7 +675,8 @@ out: } static const char *ecryptfs_get_link(struct dentry *dentry, - struct inode *inode, void **cookie) + struct inode *inode, + struct delayed_call *done) { size_t len; char *buf; @@ -689,7 +690,8 @@ static const char *ecryptfs_get_link(struct dentry *dentry, fsstack_copy_attr_atime(d_inode(dentry), d_inode(ecryptfs_dentry_to_lower(dentry))); buf[len] = '\0'; - return *cookie = buf; + set_delayed_call(done, kfree_link, buf); + return buf; } /** @@ -1102,7 +1104,6 @@ out: const struct inode_operations ecryptfs_symlink_iops = { .readlink = generic_readlink, .get_link = ecryptfs_get_link, - .put_link = kfree_put_link, .permission = ecryptfs_permission, .setattr = ecryptfs_setattr, .getattr = ecryptfs_getattr_link, diff --git a/fs/ext2/symlink.c b/fs/ext2/symlink.c index 46905119a27c..3495d8ae4b33 100644 --- a/fs/ext2/symlink.c +++ b/fs/ext2/symlink.c @@ -23,7 +23,6 @@ const struct inode_operations ext2_symlink_inode_operations = { .readlink = generic_readlink, .get_link = page_get_link, - .put_link = page_put_link, .setattr = ext2_setattr, #ifdef CONFIG_EXT2_FS_XATTR .setxattr = generic_setxattr, diff --git a/fs/ext4/symlink.c b/fs/ext4/symlink.c index 3b4bfe2ebd75..2281ac27b213 100644 --- a/fs/ext4/symlink.c +++ b/fs/ext4/symlink.c @@ -24,7 +24,8 @@ #ifdef CONFIG_EXT4_FS_ENCRYPTION static const char *ext4_encrypted_get_link(struct dentry *dentry, - struct inode *inode, void **cookie) + struct inode *inode, + struct delayed_call *done) { struct page *cpage = NULL; char *caddr, *paddr = NULL; @@ -80,7 +81,8 @@ static const char *ext4_encrypted_get_link(struct dentry *dentry, paddr[res] = '\0'; if (cpage) page_cache_release(cpage); - return *cookie = paddr; + set_delayed_call(done, kfree_link, paddr); + return paddr; errout: if (cpage) page_cache_release(cpage); @@ -91,7 +93,6 @@ errout: const struct inode_operations ext4_encrypted_symlink_inode_operations = { .readlink = generic_readlink, .get_link = ext4_encrypted_get_link, - .put_link = kfree_put_link, .setattr = ext4_setattr, .setxattr = generic_setxattr, .getxattr = generic_getxattr, @@ -103,7 +104,6 @@ const struct inode_operations ext4_encrypted_symlink_inode_operations = { const struct inode_operations ext4_symlink_inode_operations = { .readlink = generic_readlink, .get_link = page_get_link, - .put_link = page_put_link, .setattr = ext4_setattr, .setxattr = generic_setxattr, .getxattr = generic_getxattr, diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index 2a8d84b727ce..e7587fce1b80 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -316,12 +316,14 @@ fail: } static const char *f2fs_get_link(struct dentry *dentry, - struct inode *inode, void **cookie) + struct inode *inode, + struct delayed_call *done) { - const char *link = page_get_link(dentry, inode, cookie); + const char *link = page_get_link(dentry, inode, done); if (!IS_ERR(link) && !*link) { /* this is broken symlink case */ - page_put_link(NULL, *cookie); + do_delayed_call(done); + clear_delayed_call(done); link = ERR_PTR(-ENOENT); } return link; @@ -926,7 +928,8 @@ static int f2fs_rename2(struct inode *old_dir, struct dentry *old_dentry, #ifdef CONFIG_F2FS_FS_ENCRYPTION static const char *f2fs_encrypted_get_link(struct dentry *dentry, - struct inode *inode, void **cookie) + struct inode *inode, + struct delayed_call *done) { struct page *cpage = NULL; char *caddr, *paddr = NULL; @@ -988,7 +991,8 @@ static const char *f2fs_encrypted_get_link(struct dentry *dentry, paddr[res] = '\0'; page_cache_release(cpage); - return *cookie = paddr; + set_delayed_call(done, kfree_link, paddr); + return paddr; errout: kfree(cstr.name); f2fs_fname_crypto_free_buffer(&pstr); @@ -999,7 +1003,6 @@ errout: const struct inode_operations f2fs_encrypted_symlink_inode_operations = { .readlink = generic_readlink, .get_link = f2fs_encrypted_get_link, - .put_link = kfree_put_link, .getattr = f2fs_getattr, .setattr = f2fs_setattr, .setxattr = generic_setxattr, @@ -1035,7 +1038,6 @@ const struct inode_operations f2fs_dir_inode_operations = { const struct inode_operations f2fs_symlink_inode_operations = { .readlink = generic_readlink, .get_link = f2fs_get_link, - .put_link = page_put_link, .getattr = f2fs_getattr, .setattr = f2fs_setattr, #ifdef CONFIG_F2FS_FS_XATTR diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index def0a4d082bc..712601f299b8 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -1366,7 +1366,8 @@ static int fuse_readdir(struct file *file, struct dir_context *ctx) } static const char *fuse_get_link(struct dentry *dentry, - struct inode *inode, void **cookie) + struct inode *inode, + struct delayed_call *done) { struct fuse_conn *fc = get_fuse_conn(inode); FUSE_ARGS(args); @@ -1392,7 +1393,7 @@ static const char *fuse_get_link(struct dentry *dentry, link = ERR_PTR(ret); } else { link[ret] = '\0'; - *cookie = link; + set_delayed_call(done, kfree_link, link); } fuse_invalidate_atime(inode); return link; @@ -1913,7 +1914,6 @@ static const struct inode_operations fuse_common_inode_operations = { static const struct inode_operations fuse_symlink_inode_operations = { .setattr = fuse_setattr, .get_link = fuse_get_link, - .put_link = kfree_put_link, .readlink = generic_readlink, .getattr = fuse_getattr, .setxattr = fuse_setxattr, diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 1095056046cc..1bae189f3245 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -1715,7 +1715,7 @@ static int gfs2_rename2(struct inode *odir, struct dentry *odentry, * gfs2_get_link - Follow a symbolic link * @dentry: The dentry of the link * @inode: The inode of the link - * @cookie: place to store the information for ->put_link() + * @done: destructor for return value * * This can handle symlinks of any size. * @@ -1723,7 +1723,8 @@ static int gfs2_rename2(struct inode *odir, struct dentry *odentry, */ static const char *gfs2_get_link(struct dentry *dentry, - struct inode *inode, void **cookie) + struct inode *inode, + struct delayed_call *done) { struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_holder i_gh; @@ -1764,7 +1765,7 @@ static const char *gfs2_get_link(struct dentry *dentry, out: gfs2_glock_dq_uninit(&i_gh); if (!IS_ERR(buf)) - *cookie = buf; + set_delayed_call(done, kfree_link, buf); return buf; } @@ -2138,7 +2139,6 @@ const struct inode_operations gfs2_dir_iops = { const struct inode_operations gfs2_symlink_iops = { .readlink = generic_readlink, .get_link = gfs2_get_link, - .put_link = kfree_put_link, .permission = gfs2_permission, .setattr = gfs2_setattr, .getattr = gfs2_getattr, diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c index 6ce5309ecb7b..7db524cc85b6 100644 --- a/fs/hostfs/hostfs_kern.c +++ b/fs/hostfs/hostfs_kern.c @@ -893,12 +893,13 @@ static const struct inode_operations hostfs_dir_iops = { }; static const char *hostfs_get_link(struct dentry *dentry, - struct inode *inode, void **cookie) + struct inode *inode, + struct delayed_call *done) { char *link; if (!dentry) return ERR_PTR(-ECHILD); - link = __getname(); + link = kmalloc(PATH_MAX, GFP_KERNEL); if (link) { char *path = dentry_name(dentry); int err = -ENOMEM; @@ -909,25 +910,20 @@ static const char *hostfs_get_link(struct dentry *dentry, __putname(path); } if (err < 0) { - __putname(link); + kfree(link); return ERR_PTR(err); } } else { return ERR_PTR(-ENOMEM); } - return *cookie = link; -} - -static void hostfs_put_link(struct inode *unused, void *cookie) -{ - __putname(cookie); + set_delayed_call(done, kfree_link, link); + return link; } static const struct inode_operations hostfs_link_iops = { .readlink = generic_readlink, .get_link = hostfs_get_link, - .put_link = hostfs_put_link, }; static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent) diff --git a/fs/jfs/symlink.c b/fs/jfs/symlink.c index 02113282772e..f8db4fde0b0b 100644 --- a/fs/jfs/symlink.c +++ b/fs/jfs/symlink.c @@ -34,7 +34,6 @@ const struct inode_operations jfs_fast_symlink_inode_operations = { const struct inode_operations jfs_symlink_inode_operations = { .readlink = generic_readlink, .get_link = page_get_link, - .put_link = page_put_link, .setattr = jfs_setattr, .setxattr = jfs_setxattr, .getxattr = jfs_getxattr, diff --git a/fs/kernfs/symlink.c b/fs/kernfs/symlink.c index f9efdaeda7b0..117b8b3416f9 100644 --- a/fs/kernfs/symlink.c +++ b/fs/kernfs/symlink.c @@ -113,22 +113,24 @@ static int kernfs_getlink(struct dentry *dentry, char *path) } static const char *kernfs_iop_get_link(struct dentry *dentry, - struct inode *inode, void **cookie) + struct inode *inode, + struct delayed_call *done) { - int error = -ENOMEM; - char *page; + char *body; + int error; if (!dentry) return ERR_PTR(-ECHILD); - page = kzalloc(PAGE_SIZE, GFP_KERNEL); - if (!page) + body = kzalloc(PAGE_SIZE, GFP_KERNEL); + if (!body) return ERR_PTR(-ENOMEM); - error = kernfs_getlink(dentry, page); + error = kernfs_getlink(dentry, body); if (unlikely(error < 0)) { - kfree(page); + kfree(body); return ERR_PTR(error); } - return *cookie = page; + set_delayed_call(done, kfree_link, body); + return body; } const struct inode_operations kernfs_symlink_iops = { @@ -138,7 +140,6 @@ const struct inode_operations kernfs_symlink_iops = { .listxattr = kernfs_iop_listxattr, .readlink = generic_readlink, .get_link = kernfs_iop_get_link, - .put_link = kfree_put_link, .setattr = kernfs_iop_setattr, .getattr = kernfs_iop_getattr, .permission = kernfs_iop_permission, diff --git a/fs/libfs.c b/fs/libfs.c index fec7ab0632dc..01491299f348 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -1019,11 +1019,12 @@ int noop_fsync(struct file *file, loff_t start, loff_t end, int datasync) } EXPORT_SYMBOL(noop_fsync); -void kfree_put_link(struct inode *unused, void *cookie) +/* Because kfree isn't assignment-compatible with void(void*) ;-/ */ +void kfree_link(void *p) { - kfree(cookie); + kfree(p); } -EXPORT_SYMBOL(kfree_put_link); +EXPORT_SYMBOL(kfree_link); /* * nop .set_page_dirty method so that people can use .page_mkwrite on @@ -1087,7 +1088,7 @@ simple_nosetlease(struct file *filp, long arg, struct file_lock **flp, EXPORT_SYMBOL(simple_nosetlease); const char *simple_get_link(struct dentry *dentry, struct inode *inode, - void **cookie) + struct delayed_call *done) { return inode->i_link; } diff --git a/fs/minix/inode.c b/fs/minix/inode.c index 3cce709a8729..cb1789ca1ee6 100644 --- a/fs/minix/inode.c +++ b/fs/minix/inode.c @@ -436,7 +436,6 @@ static const struct address_space_operations minix_aops = { static const struct inode_operations minix_symlink_inode_operations = { .readlink = generic_readlink, .get_link = page_get_link, - .put_link = page_put_link, .getattr = minix_getattr, }; diff --git a/fs/namei.c b/fs/namei.c index 8f517888c3e1..3c909aebef70 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -505,13 +505,13 @@ struct nameidata { int total_link_count; struct saved { struct path link; - void *cookie; + struct delayed_call done; const char *name; - struct inode *inode; unsigned seq; } *stack, internal[EMBEDDED_LEVELS]; struct filename *name; struct nameidata *saved; + struct inode *link_inode; unsigned root_seq; int dfd; }; @@ -592,11 +592,8 @@ static void drop_links(struct nameidata *nd) int i = nd->depth; while (i--) { struct saved *last = nd->stack + i; - struct inode *inode = last->inode; - if (last->cookie && inode->i_op->put_link) { - inode->i_op->put_link(inode, last->cookie); - last->cookie = NULL; - } + do_delayed_call(&last->done); + clear_delayed_call(&last->done); } } @@ -858,9 +855,7 @@ void nd_jump_link(struct path *path) static inline void put_link(struct nameidata *nd) { struct saved *last = nd->stack + --nd->depth; - struct inode *inode = last->inode; - if (last->cookie && inode->i_op->put_link) - inode->i_op->put_link(inode, last->cookie); + do_delayed_call(&last->done); if (!(nd->flags & LOOKUP_RCU)) path_put(&last->link); } @@ -892,7 +887,7 @@ static inline int may_follow_link(struct nameidata *nd) return 0; /* Allowed if owner and follower match. */ - inode = nd->stack[0].inode; + inode = nd->link_inode; if (uid_eq(current_cred()->fsuid, inode->i_uid)) return 0; @@ -983,7 +978,7 @@ const char *get_link(struct nameidata *nd) { struct saved *last = nd->stack + nd->depth - 1; struct dentry *dentry = last->link.dentry; - struct inode *inode = last->inode; + struct inode *inode = nd->link_inode; int error; const char *res; @@ -1004,23 +999,21 @@ const char *get_link(struct nameidata *nd) nd->last_type = LAST_BIND; res = inode->i_link; if (!res) { + const char * (*get)(struct dentry *, struct inode *, + struct delayed_call *); + get = inode->i_op->get_link; if (nd->flags & LOOKUP_RCU) { - res = inode->i_op->get_link(NULL, inode, - &last->cookie); + res = get(NULL, inode, &last->done); if (res == ERR_PTR(-ECHILD)) { if (unlikely(unlazy_walk(nd, NULL, 0))) return ERR_PTR(-ECHILD); - res = inode->i_op->get_link(dentry, inode, - &last->cookie); + res = get(dentry, inode, &last->done); } } else { - res = inode->i_op->get_link(dentry, inode, - &last->cookie); + res = get(dentry, inode, &last->done); } - if (IS_ERR_OR_NULL(res)) { - last->cookie = NULL; + if (IS_ERR_OR_NULL(res)) return res; - } } if (*res == '/') { if (nd->flags & LOOKUP_RCU) { @@ -1699,8 +1692,8 @@ static int pick_link(struct nameidata *nd, struct path *link, last = nd->stack + nd->depth++; last->link = *link; - last->cookie = NULL; - last->inode = inode; + clear_delayed_call(&last->done); + nd->link_inode = inode; last->seq = seq; return 1; } @@ -4508,26 +4501,25 @@ EXPORT_SYMBOL(readlink_copy); */ int generic_readlink(struct dentry *dentry, char __user *buffer, int buflen) { - void *cookie; + DEFINE_DELAYED_CALL(done); struct inode *inode = d_inode(dentry); const char *link = inode->i_link; int res; if (!link) { - link = inode->i_op->get_link(dentry, inode, &cookie); + link = inode->i_op->get_link(dentry, inode, &done); if (IS_ERR(link)) return PTR_ERR(link); } res = readlink_copy(buffer, buflen, link); - if (inode->i_op->put_link) - inode->i_op->put_link(inode, cookie); + do_delayed_call(&done); return res; } EXPORT_SYMBOL(generic_readlink); /* get the link contents into pagecache */ const char *page_get_link(struct dentry *dentry, struct inode *inode, - void **cookie) + struct delayed_call *callback) { char *kaddr; struct page *page; @@ -4546,7 +4538,7 @@ const char *page_get_link(struct dentry *dentry, struct inode *inode, if (IS_ERR(page)) return (char*)page; } - *cookie = page; + set_delayed_call(callback, page_put_link, page); BUG_ON(mapping_gfp_mask(mapping) & __GFP_HIGHMEM); kaddr = page_address(page); nd_terminate_link(kaddr, inode->i_size, PAGE_SIZE - 1); @@ -4555,21 +4547,19 @@ const char *page_get_link(struct dentry *dentry, struct inode *inode, EXPORT_SYMBOL(page_get_link); -void page_put_link(struct inode *unused, void *cookie) +void page_put_link(void *arg) { - struct page *page = cookie; - page_cache_release(page); + put_page(arg); } EXPORT_SYMBOL(page_put_link); int page_readlink(struct dentry *dentry, char __user *buffer, int buflen) { - void *cookie = NULL; + DEFINE_DELAYED_CALL(done); int res = readlink_copy(buffer, buflen, page_get_link(dentry, d_inode(dentry), - &cookie)); - if (cookie) - page_put_link(NULL, cookie); + &done)); + do_delayed_call(&done); return res; } EXPORT_SYMBOL(page_readlink); @@ -4619,6 +4609,5 @@ EXPORT_SYMBOL(page_symlink); const struct inode_operations page_symlink_inode_operations = { .readlink = generic_readlink, .get_link = page_get_link, - .put_link = page_put_link, }; EXPORT_SYMBOL(page_symlink_inode_operations); diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index 3ab6cdbcde60..ce1eb3f9dfe8 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c @@ -245,7 +245,6 @@ static void ncp_set_attr(struct inode *inode, struct ncp_entry_info *nwinfo) static const struct inode_operations ncp_symlink_inode_operations = { .readlink = generic_readlink, .get_link = page_get_link, - .put_link = page_put_link, .setattr = ncp_notify_change, }; #endif diff --git a/fs/nfs/symlink.c b/fs/nfs/symlink.c index 95c69af7e4d0..4fe3eead3868 100644 --- a/fs/nfs/symlink.c +++ b/fs/nfs/symlink.c @@ -43,7 +43,8 @@ error: } static const char *nfs_get_link(struct dentry *dentry, - struct inode *inode, void **cookie) + struct inode *inode, + struct delayed_call *done) { struct page *page; void *err; @@ -68,7 +69,7 @@ static const char *nfs_get_link(struct dentry *dentry, if (IS_ERR(page)) return ERR_CAST(page); } - *cookie = page; + set_delayed_call(done, page_put_link, page); return page_address(page); } @@ -78,7 +79,6 @@ static const char *nfs_get_link(struct dentry *dentry, const struct inode_operations nfs_symlink_inode_operations = { .readlink = generic_readlink, .get_link = nfs_get_link, - .put_link = page_put_link, .getattr = nfs_getattr, .setattr = nfs_setattr, }; diff --git a/fs/nilfs2/namei.c b/fs/nilfs2/namei.c index 63dddb7d4b18..7ccdb961eea9 100644 --- a/fs/nilfs2/namei.c +++ b/fs/nilfs2/namei.c @@ -570,7 +570,6 @@ const struct inode_operations nilfs_special_inode_operations = { const struct inode_operations nilfs_symlink_inode_operations = { .readlink = generic_readlink, .get_link = page_get_link, - .put_link = page_put_link, .permission = nilfs_permission, }; diff --git a/fs/ocfs2/symlink.c b/fs/ocfs2/symlink.c index b4e79bc720f7..6c2a3e3c521c 100644 --- a/fs/ocfs2/symlink.c +++ b/fs/ocfs2/symlink.c @@ -89,7 +89,6 @@ const struct address_space_operations ocfs2_fast_symlink_aops = { const struct inode_operations ocfs2_symlink_inode_operations = { .readlink = generic_readlink, .get_link = page_get_link, - .put_link = page_put_link, .getattr = ocfs2_getattr, .setattr = ocfs2_setattr, .setxattr = generic_setxattr, diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c index 38a0b8b9f8b9..964a60fa7afc 100644 --- a/fs/overlayfs/inode.c +++ b/fs/overlayfs/inode.c @@ -131,19 +131,12 @@ out_dput: return err; } - -struct ovl_link_data { - struct dentry *realdentry; - void *cookie; -}; - static const char *ovl_get_link(struct dentry *dentry, - struct inode *inode, void **cookie) + struct inode *inode, + struct delayed_call *done) { struct dentry *realdentry; struct inode *realinode; - struct ovl_link_data *data = NULL; - const char *ret; if (!dentry) return ERR_PTR(-ECHILD); @@ -154,38 +147,7 @@ static const char *ovl_get_link(struct dentry *dentry, if (WARN_ON(!realinode->i_op->get_link)) return ERR_PTR(-EPERM); - if (realinode->i_op->put_link) { - data = kmalloc(sizeof(struct ovl_link_data), GFP_KERNEL); - if (!data) - return ERR_PTR(-ENOMEM); - data->realdentry = realdentry; - } - - ret = realinode->i_op->get_link(realdentry, realinode, cookie); - if (IS_ERR_OR_NULL(ret)) { - kfree(data); - return ret; - } - - if (data) - data->cookie = *cookie; - - *cookie = data; - - return ret; -} - -static void ovl_put_link(struct inode *unused, void *c) -{ - struct inode *realinode; - struct ovl_link_data *data = c; - - if (!data) - return; - - realinode = data->realdentry->d_inode; - realinode->i_op->put_link(realinode, data->cookie); - kfree(data); + return realinode->i_op->get_link(realdentry, realinode, done); } static int ovl_readlink(struct dentry *dentry, char __user *buf, int bufsiz) @@ -383,7 +345,6 @@ static const struct inode_operations ovl_file_inode_operations = { static const struct inode_operations ovl_symlink_inode_operations = { .setattr = ovl_setattr, .get_link = ovl_get_link, - .put_link = ovl_put_link, .readlink = ovl_readlink, .getattr = ovl_getattr, .setxattr = ovl_setxattr, diff --git a/fs/proc/base.c b/fs/proc/base.c index 1a489e2b9768..71660bb9e9f7 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -1565,7 +1565,8 @@ static int proc_exe_link(struct dentry *dentry, struct path *exe_path) } static const char *proc_pid_get_link(struct dentry *dentry, - struct inode *inode, void **cookie) + struct inode *inode, + struct delayed_call *done) { struct path path; int error = -EACCES; @@ -1949,12 +1950,13 @@ struct map_files_info { */ static const char * proc_map_files_get_link(struct dentry *dentry, - struct inode *inode, void **cookie) + struct inode *inode, + struct delayed_call *done) { if (!capable(CAP_SYS_ADMIN)) return ERR_PTR(-EPERM); - return proc_pid_get_link(dentry, inode, NULL); + return proc_pid_get_link(dentry, inode, done); } /* diff --git a/fs/proc/inode.c b/fs/proc/inode.c index 10360b268794..d0e9b9b6223e 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -393,25 +393,25 @@ static const struct file_operations proc_reg_file_ops_no_compat = { }; #endif +static void proc_put_link(void *p) +{ + unuse_pde(p); +} + static const char *proc_get_link(struct dentry *dentry, - struct inode *inode, void **cookie) + struct inode *inode, + struct delayed_call *done) { struct proc_dir_entry *pde = PDE(inode); if (unlikely(!use_pde(pde))) return ERR_PTR(-EINVAL); - *cookie = pde; + set_delayed_call(done, proc_put_link, pde); return pde->data; } -static void proc_put_link(struct inode *unused, void *p) -{ - unuse_pde(p); -} - const struct inode_operations proc_link_inode_operations = { .readlink = generic_readlink, .get_link = proc_get_link, - .put_link = proc_put_link, }; struct inode *proc_get_inode(struct super_block *sb, struct proc_dir_entry *de) diff --git a/fs/proc/namespaces.c b/fs/proc/namespaces.c index 63861c15e109..1dece8781f91 100644 --- a/fs/proc/namespaces.c +++ b/fs/proc/namespaces.c @@ -31,7 +31,8 @@ static const struct proc_ns_operations *ns_entries[] = { }; static const char *proc_ns_get_link(struct dentry *dentry, - struct inode *inode, void **cookie) + struct inode *inode, + struct delayed_call *done) { const struct proc_ns_operations *ns_ops = PROC_I(inode)->ns_ops; struct task_struct *task; diff --git a/fs/proc/self.c b/fs/proc/self.c index 7a8b19ead3b6..67e8db442cf0 100644 --- a/fs/proc/self.c +++ b/fs/proc/self.c @@ -19,7 +19,8 @@ static int proc_self_readlink(struct dentry *dentry, char __user *buffer, } static const char *proc_self_get_link(struct dentry *dentry, - struct inode *inode, void **cookie) + struct inode *inode, + struct delayed_call *done) { struct pid_namespace *ns = inode->i_sb->s_fs_info; pid_t tgid = task_tgid_nr_ns(current, ns); @@ -32,13 +33,13 @@ static const char *proc_self_get_link(struct dentry *dentry, if (unlikely(!name)) return dentry ? ERR_PTR(-ENOMEM) : ERR_PTR(-ECHILD); sprintf(name, "%d", tgid); - return *cookie = name; + set_delayed_call(done, kfree_link, name); + return name; } static const struct inode_operations proc_self_inode_operations = { .readlink = proc_self_readlink, .get_link = proc_self_get_link, - .put_link = kfree_put_link, }; static unsigned self_inum; diff --git a/fs/proc/thread_self.c b/fs/proc/thread_self.c index 03eaa84604da..9eacd59e0360 100644 --- a/fs/proc/thread_self.c +++ b/fs/proc/thread_self.c @@ -20,7 +20,8 @@ static int proc_thread_self_readlink(struct dentry *dentry, char __user *buffer, } static const char *proc_thread_self_get_link(struct dentry *dentry, - struct inode *inode, void **cookie) + struct inode *inode, + struct delayed_call *done) { struct pid_namespace *ns = inode->i_sb->s_fs_info; pid_t tgid = task_tgid_nr_ns(current, ns); @@ -34,13 +35,13 @@ static const char *proc_thread_self_get_link(struct dentry *dentry, if (unlikely(!name)) return dentry ? ERR_PTR(-ENOMEM) : ERR_PTR(-ECHILD); sprintf(name, "%d/task/%d", tgid, pid); - return *cookie = name; + set_delayed_call(done, kfree_link, name); + return name; } static const struct inode_operations proc_thread_self_inode_operations = { .readlink = proc_thread_self_readlink, .get_link = proc_thread_self_get_link, - .put_link = kfree_put_link, }; static unsigned thread_self_inum; diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c index ecbf11e961ab..2a12d46d7fb4 100644 --- a/fs/reiserfs/namei.c +++ b/fs/reiserfs/namei.c @@ -1666,7 +1666,6 @@ const struct inode_operations reiserfs_dir_inode_operations = { const struct inode_operations reiserfs_symlink_inode_operations = { .readlink = generic_readlink, .get_link = page_get_link, - .put_link = page_put_link, .setattr = reiserfs_setattr, .setxattr = reiserfs_setxattr, .getxattr = reiserfs_getxattr, diff --git a/fs/squashfs/symlink.c b/fs/squashfs/symlink.c index 7c635a5da783..dbcc2f54bad4 100644 --- a/fs/squashfs/symlink.c +++ b/fs/squashfs/symlink.c @@ -120,7 +120,6 @@ const struct address_space_operations squashfs_symlink_aops = { const struct inode_operations squashfs_symlink_inode_ops = { .readlink = generic_readlink, .get_link = page_get_link, - .put_link = page_put_link, .getxattr = generic_getxattr, .listxattr = squashfs_listxattr }; diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c index 80a40bcb721c..07ac18c355e7 100644 --- a/fs/sysv/inode.c +++ b/fs/sysv/inode.c @@ -147,7 +147,6 @@ static inline void write3byte(struct sysv_sb_info *sbi, static const struct inode_operations sysv_symlink_inode_operations = { .readlink = generic_readlink, .get_link = page_get_link, - .put_link = page_put_link, .getattr = sysv_getattr, }; diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c index f638fd58b5b3..06eafafe636e 100644 --- a/fs/xfs/xfs_iops.c +++ b/fs/xfs/xfs_iops.c @@ -417,7 +417,7 @@ STATIC const char * xfs_vn_get_link( struct dentry *dentry, struct inode *inode, - void **cookie) + struct delayed_call *done) { char *link; int error = -ENOMEM; @@ -433,7 +433,8 @@ xfs_vn_get_link( if (unlikely(error)) goto out_kfree; - return *cookie = link; + set_delayed_call(done, kfree_link, link); + return link; out_kfree: kfree(link); @@ -1177,7 +1178,6 @@ static const struct inode_operations xfs_dir_ci_inode_operations = { static const struct inode_operations xfs_symlink_inode_operations = { .readlink = generic_readlink, .get_link = xfs_vn_get_link, - .put_link = kfree_put_link, .getattr = xfs_vn_getattr, .setattr = xfs_vn_setattr, .setxattr = generic_setxattr, |