]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - fs/afs/mntpt.c
llseek: automatically add .llseek fop
[mirror_ubuntu-bionic-kernel.git] / fs / afs / mntpt.c
index b3feddc4f7d649d240487fac866a21878f4258cd..6153417caf57e2b9219bbfdd40970c262b65fdcf 100644 (file)
@@ -29,6 +29,7 @@ static void afs_mntpt_expiry_timed_out(struct work_struct *work);
 
 const struct file_operations afs_mntpt_file_operations = {
        .open           = afs_mntpt_open,
+       .llseek         = noop_llseek,
 };
 
 const struct inode_operations afs_mntpt_inode_operations = {
@@ -38,6 +39,11 @@ const struct inode_operations afs_mntpt_inode_operations = {
        .getattr        = afs_getattr,
 };
 
+const struct inode_operations afs_autocell_inode_operations = {
+       .follow_link    = afs_mntpt_follow_link,
+       .getattr        = afs_getattr,
+};
+
 static LIST_HEAD(afs_vfsmounts);
 static DECLARE_DELAYED_WORK(afs_mntpt_expiry_timer, afs_mntpt_expiry_timed_out);
 
@@ -49,9 +55,6 @@ static unsigned long afs_mntpt_expiry_timeout = 10 * 60;
  */
 int afs_mntpt_check_symlink(struct afs_vnode *vnode, struct key *key)
 {
-       struct file file = {
-               .private_data = key,
-       };
        struct page *page;
        size_t size;
        char *buf;
@@ -61,7 +64,8 @@ int afs_mntpt_check_symlink(struct afs_vnode *vnode, struct key *key)
               vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique);
 
        /* read the contents of the symlink into the pagecache */
-       page = read_mapping_page(AFS_VNODE_TO_I(vnode)->i_mapping, 0, &file);
+       page = read_cache_page(AFS_VNODE_TO_I(vnode)->i_mapping, 0,
+                              afs_page_filler, key);
        if (IS_ERR(page)) {
                ret = PTR_ERR(page);
                goto out;
@@ -138,20 +142,16 @@ static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt)
 {
        struct afs_super_info *super;
        struct vfsmount *mnt;
+       struct afs_vnode *vnode;
        struct page *page;
-       size_t size;
-       char *buf, *devname, *options;
+       char *devname, *options;
+       bool rwpath = false;
        int ret;
 
        _enter("{%s}", mntpt->d_name.name);
 
        BUG_ON(!mntpt->d_inode);
 
-       ret = -EINVAL;
-       size = mntpt->d_inode->i_size;
-       if (size > PAGE_SIZE - 1)
-               goto error_no_devname;
-
        ret = -ENOMEM;
        devname = (char *) get_zeroed_page(GFP_KERNEL);
        if (!devname)
@@ -161,28 +161,59 @@ static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt)
        if (!options)
                goto error_no_options;
 
-       /* read the contents of the AFS special symlink */
-       page = read_mapping_page(mntpt->d_inode->i_mapping, 0, NULL);
-       if (IS_ERR(page)) {
-               ret = PTR_ERR(page);
-               goto error_no_page;
+       vnode = AFS_FS_I(mntpt->d_inode);
+       if (test_bit(AFS_VNODE_PSEUDODIR, &vnode->flags)) {
+               /* if the directory is a pseudo directory, use the d_name */
+               static const char afs_root_cell[] = ":root.cell.";
+               unsigned size = mntpt->d_name.len;
+
+               ret = -ENOENT;
+               if (size < 2 || size > AFS_MAXCELLNAME)
+                       goto error_no_page;
+
+               if (mntpt->d_name.name[0] == '.') {
+                       devname[0] = '#';
+                       memcpy(devname + 1, mntpt->d_name.name, size - 1);
+                       memcpy(devname + size, afs_root_cell,
+                              sizeof(afs_root_cell));
+                       rwpath = true;
+               } else {
+                       devname[0] = '%';
+                       memcpy(devname + 1, mntpt->d_name.name, size);
+                       memcpy(devname + size + 1, afs_root_cell,
+                              sizeof(afs_root_cell));
+               }
+       } else {
+               /* read the contents of the AFS special symlink */
+               loff_t size = i_size_read(mntpt->d_inode);
+               char *buf;
+
+               ret = -EINVAL;
+               if (size > PAGE_SIZE - 1)
+                       goto error_no_page;
+
+               page = read_mapping_page(mntpt->d_inode->i_mapping, 0, NULL);
+               if (IS_ERR(page)) {
+                       ret = PTR_ERR(page);
+                       goto error_no_page;
+               }
+
+               ret = -EIO;
+               if (PageError(page))
+                       goto error;
+
+               buf = kmap_atomic(page, KM_USER0);
+               memcpy(devname, buf, size);
+               kunmap_atomic(buf, KM_USER0);
+               page_cache_release(page);
+               page = NULL;
        }
 
-       ret = -EIO;
-       if (PageError(page))
-               goto error;
-
-       buf = kmap_atomic(page, KM_USER0);
-       memcpy(devname, buf, size);
-       kunmap_atomic(buf, KM_USER0);
-       page_cache_release(page);
-       page = NULL;
-
        /* work out what options we want */
        super = AFS_FS_S(mntpt->d_sb);
        memcpy(options, "cell=", 5);
        strcpy(options + 5, super->volume->cell->name);
-       if (super->volume->type == AFSVL_RWVOL)
+       if (super->volume->type == AFSVL_RWVOL || rwpath)
                strcat(options, ",rwpath");
 
        /* try and do the mount */