]> git.proxmox.com Git - mirror_zfs.git/blobdiff - module/zfs/zpl_super.c
Fix typo/etc in module/zfs/zfs_ctldir.c
[mirror_zfs.git] / module / zfs / zpl_super.c
index bcdbbd69e2808e56d8b6588f9ed77aab19b5b745..216c79401526c3eff541fd0a333e15670fb5a67b 100644 (file)
@@ -36,7 +36,7 @@ zpl_inode_alloc(struct super_block *sb)
        struct inode *ip;
 
        VERIFY3S(zfs_inode_alloc(sb, &ip), ==, 0);
-       ip->i_version = 1;
+       inode_set_iversion(ip, 1);
 
        return (ip);
 }
@@ -181,214 +181,40 @@ zpl_statfs(struct dentry *dentry, struct kstatfs *statp)
        spl_fstrans_unmark(cookie);
        ASSERT3S(error, <=, 0);
 
-       return (error);
-}
-
-enum {
-       TOKEN_RO,
-       TOKEN_RW,
-       TOKEN_SETUID,
-       TOKEN_NOSETUID,
-       TOKEN_EXEC,
-       TOKEN_NOEXEC,
-       TOKEN_DEVICES,
-       TOKEN_NODEVICES,
-       TOKEN_DIRXATTR,
-       TOKEN_SAXATTR,
-       TOKEN_XATTR,
-       TOKEN_NOXATTR,
-       TOKEN_ATIME,
-       TOKEN_NOATIME,
-       TOKEN_RELATIME,
-       TOKEN_NORELATIME,
-       TOKEN_NBMAND,
-       TOKEN_NONBMAND,
-       TOKEN_MNTPOINT,
-       TOKEN_LAST,
-};
-
-static const match_table_t zpl_tokens = {
-       { TOKEN_RO,             MNTOPT_RO },
-       { TOKEN_RW,             MNTOPT_RW },
-       { TOKEN_SETUID,         MNTOPT_SETUID },
-       { TOKEN_NOSETUID,       MNTOPT_NOSETUID },
-       { TOKEN_EXEC,           MNTOPT_EXEC },
-       { TOKEN_NOEXEC,         MNTOPT_NOEXEC },
-       { TOKEN_DEVICES,        MNTOPT_DEVICES },
-       { TOKEN_NODEVICES,      MNTOPT_NODEVICES },
-       { TOKEN_DIRXATTR,       MNTOPT_DIRXATTR },
-       { TOKEN_SAXATTR,        MNTOPT_SAXATTR },
-       { TOKEN_XATTR,          MNTOPT_XATTR },
-       { TOKEN_NOXATTR,        MNTOPT_NOXATTR },
-       { TOKEN_ATIME,          MNTOPT_ATIME },
-       { TOKEN_NOATIME,        MNTOPT_NOATIME },
-       { TOKEN_RELATIME,       MNTOPT_RELATIME },
-       { TOKEN_NORELATIME,     MNTOPT_NORELATIME },
-       { TOKEN_NBMAND,         MNTOPT_NBMAND },
-       { TOKEN_NONBMAND,       MNTOPT_NONBMAND },
-       { TOKEN_MNTPOINT,       MNTOPT_MNTPOINT "=%s" },
-       { TOKEN_LAST,           NULL },
-};
-
-static int
-zpl_parse_option(char *option, int token, substring_t *args, zfs_mntopts_t *zmo)
-{
-       switch (token) {
-       case TOKEN_RO:
-               zmo->z_readonly = B_TRUE;
-               zmo->z_do_readonly = B_TRUE;
-               break;
-       case TOKEN_RW:
-               zmo->z_readonly = B_FALSE;
-               zmo->z_do_readonly = B_TRUE;
-               break;
-       case TOKEN_SETUID:
-               zmo->z_setuid = B_TRUE;
-               zmo->z_do_setuid = B_TRUE;
-               break;
-       case TOKEN_NOSETUID:
-               zmo->z_setuid = B_FALSE;
-               zmo->z_do_setuid = B_TRUE;
-               break;
-       case TOKEN_EXEC:
-               zmo->z_exec = B_TRUE;
-               zmo->z_do_exec = B_TRUE;
-               break;
-       case TOKEN_NOEXEC:
-               zmo->z_exec = B_FALSE;
-               zmo->z_do_exec = B_TRUE;
-               break;
-       case TOKEN_DEVICES:
-               zmo->z_devices = B_TRUE;
-               zmo->z_do_devices = B_TRUE;
-               break;
-       case TOKEN_NODEVICES:
-               zmo->z_devices = B_FALSE;
-               zmo->z_do_devices = B_TRUE;
-               break;
-       case TOKEN_DIRXATTR:
-               zmo->z_xattr = ZFS_XATTR_DIR;
-               zmo->z_do_xattr = B_TRUE;
-               break;
-       case TOKEN_SAXATTR:
-               zmo->z_xattr = ZFS_XATTR_SA;
-               zmo->z_do_xattr = B_TRUE;
-               break;
-       case TOKEN_XATTR:
-               zmo->z_xattr = ZFS_XATTR_DIR;
-               zmo->z_do_xattr = B_TRUE;
-               break;
-       case TOKEN_NOXATTR:
-               zmo->z_xattr = ZFS_XATTR_OFF;
-               zmo->z_do_xattr = B_TRUE;
-               break;
-       case TOKEN_ATIME:
-               zmo->z_atime = B_TRUE;
-               zmo->z_do_atime = B_TRUE;
-               break;
-       case TOKEN_NOATIME:
-               zmo->z_atime = B_FALSE;
-               zmo->z_do_atime = B_TRUE;
-               break;
-       case TOKEN_RELATIME:
-               zmo->z_relatime = B_TRUE;
-               zmo->z_do_relatime = B_TRUE;
-               break;
-       case TOKEN_NORELATIME:
-               zmo->z_relatime = B_FALSE;
-               zmo->z_do_relatime = B_TRUE;
-               break;
-       case TOKEN_NBMAND:
-               zmo->z_nbmand = B_TRUE;
-               zmo->z_do_nbmand = B_TRUE;
-               break;
-       case TOKEN_NONBMAND:
-               zmo->z_nbmand = B_FALSE;
-               zmo->z_do_nbmand = B_TRUE;
-               break;
-       case TOKEN_MNTPOINT:
-               zmo->z_mntpoint = match_strdup(&args[0]);
-               if (zmo->z_mntpoint == NULL)
-                       return (-ENOMEM);
-
-               break;
-       default:
-               break;
-       }
-
-       return (0);
-}
-
-/*
- * Parse the mntopts string storing the results in provided zmo argument.
- * If an error occurs the zmo argument will not be modified.  The caller
- * needs to set isremount when recycling an existing zfs_mntopts_t.
- */
-static int
-zpl_parse_options(char *osname, char *mntopts, zfs_mntopts_t *zmo,
-    boolean_t isremount)
-{
-       zfs_mntopts_t *tmp_zmo;
-       int error;
-
-       tmp_zmo = zfs_mntopts_alloc();
-       tmp_zmo->z_osname = strdup(osname);
-
-       if (mntopts) {
-               substring_t args[MAX_OPT_ARGS];
-               char *tmp_mntopts, *p;
-               int token;
-
-               tmp_mntopts = strdup(mntopts);
-
-               while ((p = strsep(&tmp_mntopts, ",")) != NULL) {
-                       if (!*p)
-                               continue;
-
-                       args[0].to = args[0].from = NULL;
-                       token = match_token(p, zpl_tokens, args);
-                       error = zpl_parse_option(p, token, args, tmp_zmo);
-                       if (error) {
-                               zfs_mntopts_free(tmp_zmo);
-                               strfree(tmp_mntopts);
-                               return (error);
-                       }
+       /*
+        * If required by a 32-bit system call, dynamically scale the
+        * block size up to 16MiB and decrease the block counts.  This
+        * allows for a maximum size of 64EiB to be reported.  The file
+        * counts must be artificially capped at 2^32-1.
+        */
+       if (unlikely(zpl_is_32bit_api())) {
+               while (statp->f_blocks > UINT32_MAX &&
+                   statp->f_bsize < SPA_MAXBLOCKSIZE) {
+                       statp->f_frsize <<= 1;
+                       statp->f_bsize <<= 1;
+
+                       statp->f_blocks >>= 1;
+                       statp->f_bfree >>= 1;
+                       statp->f_bavail >>= 1;
                }
 
-               strfree(tmp_mntopts);
+               uint64_t usedobjs = statp->f_files - statp->f_ffree;
+               statp->f_ffree = MIN(statp->f_ffree, UINT32_MAX - usedobjs);
+               statp->f_files = statp->f_ffree + usedobjs;
        }
 
-       if (isremount == B_TRUE) {
-               if (zmo->z_osname)
-                       strfree(zmo->z_osname);
-
-               if (zmo->z_mntpoint)
-                       strfree(zmo->z_mntpoint);
-       } else {
-               ASSERT3P(zmo->z_osname, ==, NULL);
-               ASSERT3P(zmo->z_mntpoint, ==, NULL);
-       }
-
-       memcpy(zmo, tmp_zmo, sizeof (zfs_mntopts_t));
-       kmem_free(tmp_zmo, sizeof (zfs_mntopts_t));
-
-       return (0);
+       return (error);
 }
 
 static int
 zpl_remount_fs(struct super_block *sb, int *flags, char *data)
 {
-       zfs_sb_t *zsb = sb->s_fs_info;
+       zfs_mnt_t zm = { .mnt_osname = NULL, .mnt_data = data };
        fstrans_cookie_t cookie;
        int error;
 
-       error = zpl_parse_options(zsb->z_mntopts->z_osname, data,
-           zsb->z_mntopts, B_TRUE);
-       if (error)
-               return (error);
-
        cookie = spl_fstrans_mark();
-       error = -zfs_remount(sb, flags, zsb->z_mntopts);
+       error = -zfs_remount(sb, flags, &zm);
        spl_fstrans_unmark(cookie);
        ASSERT3S(error, <=, 0);
 
@@ -396,12 +222,13 @@ zpl_remount_fs(struct super_block *sb, int *flags, char *data)
 }
 
 static int
-__zpl_show_options(struct seq_file *seq, zfs_sb_t *zsb)
+__zpl_show_options(struct seq_file *seq, zfsvfs_t *zfsvfs)
 {
-       seq_printf(seq, ",%s", zsb->z_flags & ZSB_XATTR ? "xattr" : "noxattr");
+       seq_printf(seq, ",%s",
+           zfsvfs->z_flags & ZSB_XATTR ? "xattr" : "noxattr");
 
 #ifdef CONFIG_FS_POSIX_ACL
-       switch (zsb->z_acl_type) {
+       switch (zfsvfs->z_acl_type) {
        case ZFS_ACLTYPE_POSIXACL:
                seq_puts(seq, ",posixacl");
                break;
@@ -431,51 +258,99 @@ zpl_show_options(struct seq_file *seq, struct vfsmount *vfsp)
 static int
 zpl_fill_super(struct super_block *sb, void *data, int silent)
 {
-       zfs_mntopts_t *zmo = (zfs_mntopts_t *)data;
+       zfs_mnt_t *zm = (zfs_mnt_t *)data;
        fstrans_cookie_t cookie;
        int error;
 
        cookie = spl_fstrans_mark();
-       error = -zfs_domount(sb, zmo, silent);
+       error = -zfs_domount(sb, zm, silent);
        spl_fstrans_unmark(cookie);
        ASSERT3S(error, <=, 0);
 
        return (error);
 }
 
-#ifdef HAVE_MOUNT_NODEV
+static int
+zpl_test_super(struct super_block *s, void *data)
+{
+       zfsvfs_t *zfsvfs = s->s_fs_info;
+       objset_t *os = data;
+
+       if (zfsvfs == NULL)
+               return (0);
+
+       return (os == zfsvfs->z_os);
+}
+
+static struct super_block *
+zpl_mount_impl(struct file_system_type *fs_type, int flags, zfs_mnt_t *zm)
+{
+       struct super_block *s;
+       objset_t *os;
+       int err;
+
+       err = dmu_objset_hold(zm->mnt_osname, FTAG, &os);
+       if (err)
+               return (ERR_PTR(-err));
+
+       /*
+        * The dsl pool lock must be released prior to calling sget().
+        * It is possible sget() may block on the lock in grab_super()
+        * while deactivate_super() holds that same lock and waits for
+        * a txg sync.  If the dsl_pool lock is held over over sget()
+        * this can prevent the pool sync and cause a deadlock.
+        */
+       dsl_pool_rele(dmu_objset_pool(os), FTAG);
+       s = zpl_sget(fs_type, zpl_test_super, set_anon_super, flags, os);
+       dsl_dataset_rele(dmu_objset_ds(os), FTAG);
+
+       if (IS_ERR(s))
+               return (ERR_CAST(s));
+
+       if (s->s_root == NULL) {
+               err = zpl_fill_super(s, zm, flags & SB_SILENT ? 1 : 0);
+               if (err) {
+                       deactivate_locked_super(s);
+                       return (ERR_PTR(err));
+               }
+               s->s_flags |= SB_ACTIVE;
+       } else if ((flags ^ s->s_flags) & SB_RDONLY) {
+               deactivate_locked_super(s);
+               return (ERR_PTR(-EBUSY));
+       }
+
+       return (s);
+}
+
+#ifdef HAVE_FST_MOUNT
 static struct dentry *
 zpl_mount(struct file_system_type *fs_type, int flags,
     const char *osname, void *data)
 {
-       zfs_mntopts_t *zmo = zfs_mntopts_alloc();
-       int error;
+       zfs_mnt_t zm = { .mnt_osname = osname, .mnt_data = data };
 
-       error = zpl_parse_options((char *)osname, (char *)data, zmo, B_FALSE);
-       if (error) {
-               zfs_mntopts_free(zmo);
-               return (ERR_PTR(error));
-       }
+       struct super_block *sb = zpl_mount_impl(fs_type, flags, &zm);
+       if (IS_ERR(sb))
+               return (ERR_CAST(sb));
 
-       return (mount_nodev(fs_type, flags, zmo, zpl_fill_super));
+       return (dget(sb->s_root));
 }
 #else
 static int
 zpl_get_sb(struct file_system_type *fs_type, int flags,
     const char *osname, void *data, struct vfsmount *mnt)
 {
-       zfs_mntopts_t *zmo = zfs_mntopts_alloc();
-       int error;
+       zfs_mnt_t zm = { .mnt_osname = osname, .mnt_data = data };
 
-       error = zpl_parse_options((char *)osname, (char *)data, zmo, B_FALSE);
-       if (error) {
-               zfs_mntopts_free(zmo);
-               return (error);
-       }
+       struct super_block *sb = zpl_mount_impl(fs_type, flags, &zm);
+       if (IS_ERR(sb))
+               return (PTR_ERR(sb));
 
-       return (get_sb_nodev(fs_type, flags, zmo, zpl_fill_super, mnt));
+       (void) simple_set_mnt(mnt, sb);
+
+       return (0);
 }
-#endif /* HAVE_MOUNT_NODEV */
+#endif /* HAVE_FST_MOUNT */
 
 static void
 zpl_kill_sb(struct super_block *sb)
@@ -494,7 +369,7 @@ zpl_prune_sb(int64_t nr_to_scan, void *arg)
        struct super_block *sb = (struct super_block *)arg;
        int objects = 0;
 
-       (void) -zfs_sb_prune(sb, nr_to_scan, &objects);
+       (void) -zfs_prune(sb, nr_to_scan, &objects);
 }
 
 #ifdef HAVE_NR_CACHED_OBJECTS
@@ -542,10 +417,10 @@ const struct super_operations zpl_super_operations = {
 struct file_system_type zpl_fs_type = {
        .owner                  = THIS_MODULE,
        .name                   = ZFS_DRIVER,
-#ifdef HAVE_MOUNT_NODEV
+#ifdef HAVE_FST_MOUNT
        .mount                  = zpl_mount,
 #else
        .get_sb                 = zpl_get_sb,
-#endif /* HAVE_MOUNT_NODEV */
+#endif /* HAVE_FST_MOUNT */
        .kill_sb                = zpl_kill_sb,
 };