switch ->get_link() to delayed_call, kill ->put_link()
authorAl Viro <viro@zeniv.linux.org.uk>
Tue, 29 Dec 2015 20:58:39 +0000 (15:58 -0500)
committerAl Viro <viro@zeniv.linux.org.uk>
Wed, 30 Dec 2015 18:01:03 +0000 (13:01 -0500)
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
43 files changed:
Documentation/filesystems/Locking
Documentation/filesystems/porting
Documentation/filesystems/vfs.txt
drivers/staging/lustre/lustre/llite/symlink.c
fs/9p/vfs_inode.c
fs/9p/vfs_inode_dotl.c
fs/affs/symlink.c
fs/autofs4/symlink.c
fs/btrfs/inode.c
fs/cifs/cifsfs.c
fs/cifs/cifsfs.h
fs/cifs/link.c
fs/coda/cnode.c
fs/configfs/symlink.c
fs/ecryptfs/inode.c
fs/ext2/symlink.c
fs/ext4/symlink.c
fs/f2fs/namei.c
fs/fuse/dir.c
fs/gfs2/inode.c
fs/hostfs/hostfs_kern.c
fs/jfs/symlink.c
fs/kernfs/symlink.c
fs/libfs.c
fs/minix/inode.c
fs/namei.c
fs/ncpfs/inode.c
fs/nfs/symlink.c
fs/nilfs2/namei.c
fs/ocfs2/symlink.c
fs/overlayfs/inode.c
fs/proc/base.c
fs/proc/inode.c
fs/proc/namespaces.c
fs/proc/self.c
fs/proc/thread_self.c
fs/reiserfs/namei.c
fs/squashfs/symlink.c
fs/sysv/inode.c
fs/xfs/xfs_iops.c
include/linux/delayed_call.h [new file with mode: 0644]
include/linux/fs.h
mm/shmem.c

index 4fba54b9fcec04815f706cefe6dc1360eae782c3..619af9bfdcb3eb4baceac7824c655fd9ba495950 100644 (file)
@@ -51,7 +51,6 @@ prototypes:
                        struct inode *, struct dentry *, unsigned int);
        int (*readlink) (struct dentry *, char __user *,int);
        const char *(*get_link) (struct dentry *, struct inode *, void **);
-       void (*put_link) (struct inode *, void *);
        void (*truncate) (struct inode *);
        int (*permission) (struct inode *, int, unsigned int);
        int (*get_acl)(struct inode *, int);
@@ -84,7 +83,6 @@ rename:               yes (all)       (see below)
 rename2:       yes (all)       (see below)
 readlink:      no
 get_link:      no
-put_link:      no
 setattr:       yes
 permission:    no (may not block if called in rcu-walk mode)
 get_acl:       no
index cf92a8c55594fe5bca74733114993614a0b455cb..0f88e6020487ff9d08836e28b7e9ae780b4ebc5a 100644 (file)
@@ -515,3 +515,9 @@ in your dentry operations instead.
                * ->get_link() gets inode as a separate argument
                * ->get_link() may be called in RCU mode - in that case NULL
                  dentry is passed
+--
+[mandatory]
+       ->get_link() gets struct delayed_call *done now, and should do
+       set_delayed_call() where it used to set *cookie.
+       ->put_link() is gone - just give the destructor to set_delayed_call()
+       in ->get_link().
index 8c6f07ad373aa6b8402e457e0705cdebd0f3271d..b02a7d598258542e890eae7ab3b4b4503db251e2 100644 (file)
@@ -350,8 +350,8 @@ struct inode_operations {
        int (*rename2) (struct inode *, struct dentry *,
                        struct inode *, struct dentry *, unsigned int);
        int (*readlink) (struct dentry *, char __user *,int);
-       const char *(*follow_link) (struct dentry *, void **);
-       void (*put_link) (struct inode *, void *);
+       const char *(*get_link) (struct dentry *, struct inode *,
+                                struct delayed_call *);
        int (*permission) (struct inode *, int);
        int (*get_acl)(struct inode *, int);
        int (*setattr) (struct dentry *, struct iattr *);
@@ -434,20 +434,19 @@ otherwise noted.
   readlink: called by the readlink(2) system call. Only required if
        you want to support reading symbolic links
 
-  follow_link: called by the VFS to follow a symbolic link to the
+  get_link: called by the VFS to follow a symbolic link to the
        inode it points to.  Only required if you want to support
        symbolic links.  This method returns the symlink body
        to traverse (and possibly resets the current position with
        nd_jump_link()).  If the body won't go away until the inode
        is gone, nothing else is needed; if it needs to be otherwise
-       pinned, the data needed to release whatever we'd grabbed
-       is to be stored in void * variable passed by address to
-       follow_link() instance.
-
-  put_link: called by the VFS to release resources allocated by
-       follow_link().  The cookie stored by follow_link() is passed
-       to this method as the last parameter; only called when
-       cookie isn't NULL.
+       pinned, arrange for its release by having get_link(..., ..., done)
+       do set_delayed_call(done, destructor, argument).
+       In that case destructor(argument) will be called once VFS is
+       done with the body you've returned.
+       May be called in RCU mode; that is indicated by NULL dentry
+       argument.  If request can't be handled without leaving RCU mode,
+       have it return ERR_PTR(-ECHILD).
 
   permission: called by the VFS to check for access rights on a POSIX-like
        filesystem.
index 153fdf908328bc37076481a79927559214b2dc94..e489a3271f0697fe8a9f35708434412072a3f2a1 100644 (file)
@@ -118,8 +118,14 @@ failed:
        return rc;
 }
 
+static void ll_put_link(void *p)
+{
+       ptlrpc_req_finished(p);
+}
+
 static const char *ll_get_link(struct dentry *dentry,
-                              struct inode *inode, void **cookie)
+                              struct inode *inode,
+                              struct delayed_call *done)
 {
        struct ptlrpc_request *request = NULL;
        int rc;
@@ -137,22 +143,16 @@ static const char *ll_get_link(struct dentry *dentry,
        }
 
        /* symname may contain a pointer to the request message buffer,
-        * we delay request releasing until ll_put_link then.
+        * we delay request releasing then.
         */
-       *cookie = request;
+       set_delayed_call(done, ll_put_link, request);
        return symname;
 }
 
-static void ll_put_link(struct inode *unused, void *cookie)
-{
-       ptlrpc_req_finished(cookie);
-}
-
 struct inode_operations ll_fast_symlink_inode_operations = {
        .readlink       = generic_readlink,
        .setattr        = ll_setattr,
        .get_link       = ll_get_link,
-       .put_link       = ll_put_link,
        .getattr        = ll_getattr,
        .permission     = ll_inode_permission,
        .setxattr       = ll_setxattr,
index 8ba5a897fc0a7924b898f12a9daf49700645accb..f928f8702f4cea509ed46c1dcd29c375063ed285 100644 (file)
@@ -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,
 };
index 0cc105d804ddcf05761be66da2c48dad5fb67cb7..a34702c998f593f60515d72fcf093cd556f5d951 100644 (file)
@@ -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,
index 39d1194445e15f5165d8b27f2d03040c345b749c..69b03dbb792f7a080abc70f5d45ff4bf50d458b9 100644 (file)
@@ -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,
 };
index 39e6f0bdf8e318ce9fb88fb7f3f9007ab3aae49d..84e037d1d129336a7d052ad2881db238785bd350 100644 (file)
@@ -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;
index 3d4aa69f1e0cd558a083f5d2a6fa90681f5aa180..1a41a65fd2ff8ebaa94df0182963769373bbb6b6 100644 (file)
@@ -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,
index 4593f41678ef6aa35db85814076c59cf4cd72d3e..90e4e2b398b66b08c9a35ed3448f34c91fbcb1df 100644 (file)
@@ -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,
index 6886328cf3c4ff745d0b3d8892ad4af299743875..26a1187d4323f227ca89072504d94619d8eb5df5 100644 (file)
@@ -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 *);
index 6f2439b508b54aeb8df0fa5d32ce1743793a2f3c..062c2375549a87acf716957593a58f213a972e06 100644 (file)
@@ -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
index f18139c7690af04485dc1542622c208c6d05d94e..1bfb7ba4e85e3ecc05000a3543a01917a7ed40a4 100644 (file)
@@ -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,
 };
 
index e9de962e518daed223abb885af1367b5c7093bdb..db6d692896088ebc9745d9c05c85309280885b38 100644 (file)
@@ -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,
 };
 
index 5a05559cb23de68a3de4ec24af143a722c0900f3..a4dddc61594cbdb7797b1a75cd50fae0ec3a6e77 100644 (file)
@@ -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,
index 46905119a27c96cc241e0381f41e7f9589736d17..3495d8ae4b33b1e8dc5a1d9341fa7d6d9835e4c5 100644 (file)
@@ -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,
index 3b4bfe2ebd756965967b870098645fc4f24b1df9..2281ac27b213b0af4646f20aa669627d50581038 100644 (file)
@@ -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,
index 2a8d84b727ce0de995084bd6bb28676415fda9a5..e7587fce1b8065bf80f35571d4a2c25b40b7c265 100644 (file)
@@ -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
index def0a4d082bc182fd07a9589af5675c1131af1de..712601f299b8a1436d69f0a31362ab57032f24b7 100644 (file)
@@ -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,
index 1095056046cc75e0fdaff3c281ad26234ae228c3..1bae189f32453c5e1bb46c11547768974c49c9ba 100644 (file)
@@ -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,
index 6ce5309ecb7b0a6039dd47556bbd9cd87f473f02..7db524cc85b6bf12358ce2ea1ea7df998b523be0 100644 (file)
@@ -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)
index 02113282772eb6ca347a2bf63177baad7f57fc4b..f8db4fde0b0b65502ce89887efaec7b40c4d8a6e 100644 (file)
@@ -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,
index f9efdaeda7b01bce1703957009c76c1feb3580f9..117b8b3416f9e761dacf36e8a3e3ff1e84f9e29b 100644 (file)
@@ -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,
index fec7ab0632dc55443d841dab41d93c83528d983e..01491299f348c965adc27cbcd70340ab2d980946 100644 (file)
@@ -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;
 }
index 3cce709a87295bf6ad45899eed53667e1a6b40b7..cb1789ca1ee675d1d101fb272ec05c28557b0186 100644 (file)
@@ -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,
 };
 
index 8f517888c3e10779ae551b0410b8d80760620436..3c909aebef70f8a8a091960bd3ba434a15e2f829 100644 (file)
@@ -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);
index 3ab6cdbcde6012699d1ab51ed7eeb94daf62e24a..ce1eb3f9dfe8005e34567bab5cbb04d3f8ce10a5 100644 (file)
@@ -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
index 95c69af7e4d0da1d63c7387b2a01274fdfc2323e..4fe3eead3868ebe418432b4593c10464188fb4ed 100644 (file)
@@ -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,
 };
index 63dddb7d4b181f6f45208635cd6de6a4867c7346..7ccdb961eea90d2ed313ef688feca1451112f5ba 100644 (file)
@@ -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,
 };
 
index b4e79bc720f7a40a3a77474fb47e42bdb74158b0..6c2a3e3c521ce66fbd6085840ae69897628ca45b 100644 (file)
@@ -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,
index 38a0b8b9f8b9b8978abb8ad77dfe9e5c0612adf5..964a60fa7afc53ad902c05b23daac017ba78fc1e 100644 (file)
@@ -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,
index 1a489e2b9768d0e81d081fb84f9f09eb61745c1d..71660bb9e9f788a5fb86060f1909edbc1e390094 100644 (file)
@@ -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);
 }
 
 /*
index 10360b2687943e8965dbded80cac6441d93bcac2..d0e9b9b6223e984879620839effb830fb7937219 100644 (file)
@@ -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)
index 63861c15e109d9eadb09e95438872467170ae796..1dece8781f91687307155c38a4c85a3ffba5c6b9 100644 (file)
@@ -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;
index 7a8b19ead3b65f4fd3ae612e99254029ae83c862..67e8db442cf03802c7758a76dd8adf79b46a3a50 100644 (file)
@@ -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;
index 03eaa84604da98889852719d64dd7eb2b34713f5..9eacd59e0360f1367a084a1e7bfa5dca0e3fe170 100644 (file)
@@ -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;
index ecbf11e961abe2c581e574f47c1e5a3b1fb9dcc7..2a12d46d7fb4154e2119ac94c50a7e74c998c437 100644 (file)
@@ -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,
index 7c635a5da7833e5b406c3119f22e66602d720b0c..dbcc2f54bad46f9af564e37f4e9b153e439d0205 100644 (file)
@@ -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
 };
index 80a40bcb721c7680bfc6eec65d915d3c788024bb..07ac18c355e777e0fe869225a70b5d6d9dba1f24 100644 (file)
@@ -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,
 };
 
index f638fd58b5b3e1687138978165167565b4fd66e3..06eafafe636e20f90e8f696ee20c0bb01b64ea8f 100644 (file)
@@ -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,
diff --git a/include/linux/delayed_call.h b/include/linux/delayed_call.h
new file mode 100644 (file)
index 0000000..f7fa76a
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef _DELAYED_CALL_H
+#define _DELAYED_CALL_H
+
+/*
+ * Poor man's closures; I wish we could've done them sanely polymorphic,
+ * but...
+ */
+
+struct delayed_call {
+       void (*fn)(void *);
+       void *arg;
+};
+
+#define DEFINE_DELAYED_CALL(name) struct delayed_call name = {NULL, NULL}
+
+/* I really wish we had closures with sane typechecking... */
+static inline void set_delayed_call(struct delayed_call *call,
+               void (*fn)(void *), void *arg)
+{
+       call->fn = fn;
+       call->arg = arg;
+}
+
+static inline void do_delayed_call(struct delayed_call *call)
+{
+       if (call->fn)
+               call->fn(call->arg);
+}
+
+static inline void clear_delayed_call(struct delayed_call *call)
+{
+       call->fn = NULL;
+}
+#endif
index 138e206df2fc50b8bd5c13e39f4ca5e170d33f3c..5de5edb01e702ae5bd4b7c4c6aac99e31c3ca7f4 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/blk_types.h>
 #include <linux/workqueue.h>
 #include <linux/percpu-rwsem.h>
+#include <linux/delayed_call.h>
 
 #include <asm/byteorder.h>
 #include <uapi/linux/fs.h>
@@ -1633,12 +1634,11 @@ struct file_operations {
 
 struct inode_operations {
        struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int);
-       const char * (*get_link) (struct dentry *, struct inode *, void **);
+       const char * (*get_link) (struct dentry *, struct inode *, struct delayed_call *);
        int (*permission) (struct inode *, int);
        struct posix_acl * (*get_acl)(struct inode *, int);
 
        int (*readlink) (struct dentry *, char __user *,int);
-       void (*put_link) (struct inode *, void *);
 
        int (*create) (struct inode *,struct dentry *, umode_t, bool);
        int (*link) (struct dentry *,struct inode *,struct dentry *);
@@ -2736,13 +2736,14 @@ extern const struct file_operations generic_ro_fops;
 
 extern int readlink_copy(char __user *, int, const char *);
 extern int page_readlink(struct dentry *, char __user *, int);
-extern const char *page_get_link(struct dentry *, struct inode *, void **);
-extern void page_put_link(struct inode *, void *);
+extern const char *page_get_link(struct dentry *, struct inode *,
+                                struct delayed_call *);
+extern void page_put_link(void *);
 extern int __page_symlink(struct inode *inode, const char *symname, int len,
                int nofs);
 extern int page_symlink(struct inode *inode, const char *symname, int len);
 extern const struct inode_operations page_symlink_inode_operations;
-extern void kfree_put_link(struct inode *, void *);
+extern void kfree_link(void *);
 extern int generic_readlink(struct dentry *, char __user *, int);
 extern void generic_fillattr(struct inode *, struct kstat *);
 int vfs_getattr_nosec(struct path *path, struct kstat *stat);
@@ -2753,7 +2754,8 @@ void __inode_sub_bytes(struct inode *inode, loff_t bytes);
 void inode_sub_bytes(struct inode *inode, loff_t bytes);
 loff_t inode_get_bytes(struct inode *inode);
 void inode_set_bytes(struct inode *inode, loff_t bytes);
-const char *simple_get_link(struct dentry *, struct inode *, void **);
+const char *simple_get_link(struct dentry *, struct inode *,
+                           struct delayed_call *);
 extern const struct inode_operations simple_symlink_inode_operations;
 
 extern int iterate_dir(struct file *, struct dir_context *);
index 0605716aee0626d6a782e81be95d14eddf80cf1a..bab9041b19673389b1c0d21346434f24a349a735 100644 (file)
@@ -2496,8 +2496,15 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s
        return 0;
 }
 
+static void shmem_put_link(void *arg)
+{
+       mark_page_accessed(arg);
+       put_page(arg);
+}
+
 static const char *shmem_get_link(struct dentry *dentry,
-                                 struct inode *inode, void **cookie)
+                                 struct inode *inode,
+                                 struct delayed_call *done)
 {
        struct page *page = NULL;
        int error;
@@ -2515,17 +2522,10 @@ static const char *shmem_get_link(struct dentry *dentry,
                        return ERR_PTR(error);
                unlock_page(page);
        }
-       *cookie = page;
+       set_delayed_call(done, shmem_put_link, page);
        return page_address(page);
 }
 
-static void shmem_put_link(struct inode *unused, void *cookie)
-{
-       struct page *page = cookie;
-       mark_page_accessed(page);
-       page_cache_release(page);
-}
-
 #ifdef CONFIG_TMPFS_XATTR
 /*
  * Superblocks without xattr inode operations may get some security.* xattr
@@ -2680,7 +2680,6 @@ static const struct inode_operations shmem_short_symlink_operations = {
 static const struct inode_operations shmem_symlink_inode_operations = {
        .readlink       = generic_readlink,
        .get_link       = shmem_get_link,
-       .put_link       = shmem_put_link,
 #ifdef CONFIG_TMPFS_XATTR
        .setxattr       = shmem_setxattr,
        .getxattr       = shmem_getxattr,