Wrapfs: remove obsolete ->readlink, update ->get_link guilt/wrapfs
authorErez Zadok <ezk@cs.sunysb.edu>
Thu, 12 Dec 2019 04:57:22 +0000 (23:57 -0500)
committerErez Zadok <ezk@cs.sunysb.edu>
Thu, 12 Dec 2019 04:57:22 +0000 (23:57 -0500)
Use proper callbacks to free lower/upper symlink buffers.

Signed-off-by: Erez Zadok <ezk@cs.sunysb.edu>
fs/wrapfs/inode.c

index b7ee788a72a119258f4528115bb094f206d55f11..1c124249938dbadf12c9365ec66a0453690b1b95 100644 (file)
@@ -290,60 +290,47 @@ out:
        return err;
 }
 
-static int wrapfs_readlink(struct dentry *dentry, char __user *buf, int bufsiz)
+static const char *wrapfs_get_link(struct dentry *dentry, struct inode *inode,
+                                  struct delayed_call *done)
 {
-       int err;
+       DEFINE_DELAYED_CALL(lower_done);
        struct dentry *lower_dentry;
        struct path lower_path;
+       char *buf;
+       const char *lower_link;
+
+       if (!dentry)
+               return ERR_PTR(-ECHILD);
 
        wrapfs_get_lower_path(dentry, &lower_path);
        lower_dentry = lower_path.dentry;
-       if (!d_inode(lower_dentry)->i_op ||
-           !d_inode(lower_dentry)->i_op->readlink) {
-               err = -EINVAL;
-               goto out;
-       }
 
-       err = d_inode(lower_dentry)->i_op->readlink(lower_dentry,
-                                                   buf, bufsiz);
-       if (err < 0)
+       /*
+        * get link from lower file system, but use a separate
+        * delayed_call callback.
+        */
+       lower_link = vfs_get_link(lower_dentry, &lower_done);
+       if (IS_ERR(lower_link)) {
+               buf = ERR_CAST(lower_link);
                goto out;
-       fsstack_copy_attr_atime(d_inode(dentry), d_inode(lower_dentry));
-
-out:
-       wrapfs_put_lower_path(dentry, &lower_path);
-       return err;
-}
-
-static const char *wrapfs_get_link(struct dentry *dentry, struct inode *inode,
-                                  struct delayed_call *done)
-{
-       char *buf;
-       int len = PAGE_SIZE, err;
-       mm_segment_t old_fs;
-
-       if (!dentry)
-               return ERR_PTR(-ECHILD);
+       }
 
-       /* This is freed by the put_link method assuming a successful call. */
-       buf = kmalloc(len, GFP_KERNEL);
+       /*
+        * we can't pass lower link up: have to make private copy and
+        * pass that.
+        */
+       buf = kstrdup(lower_link, GFP_KERNEL);
+       do_delayed_call(&lower_done);
        if (!buf) {
                buf = ERR_PTR(-ENOMEM);
-               return buf;
+               goto out;
        }
 
-       /* read the symlink, and then we will follow it */
-       old_fs = get_fs();
-       set_fs(KERNEL_DS);
-       err = wrapfs_readlink(dentry, buf, len);
-       set_fs(old_fs);
-       if (err < 0) {
-               kfree(buf);
-               buf = ERR_PTR(err);
-       } else {
-               buf[err] = '\0';
-       }
+       fsstack_copy_attr_atime(d_inode(dentry), d_inode(lower_dentry));
+
        set_delayed_call(done, kfree_link, buf);
+out:
+       wrapfs_put_lower_path(dentry, &lower_path);
        return buf;
 }
 
@@ -553,7 +540,6 @@ out:
 }
 
 const struct inode_operations wrapfs_symlink_iops = {
-       .readlink       = wrapfs_readlink,
        .permission     = wrapfs_permission,
        .setattr        = wrapfs_setattr,
        .getattr        = wrapfs_getattr,