#include <sys/modctl.h>
#include <sys/refstr.h>
#include <sys/zfs_ioctl.h>
+#include <sys/zfs_ctldir.h>
#include <sys/zfs_fuid.h>
#include <sys/bootconf.h>
#include <sys/sunddi.h>
{
zfs_sb_t *zsb = arg;
- if (newval == TRUE)
- zsb->z_flags |= ZSB_XATTR;
- else
+ if (newval == ZFS_XATTR_OFF) {
zsb->z_flags &= ~ZSB_XATTR;
+ } else {
+ zsb->z_flags |= ZSB_XATTR;
+
+ if (newval == ZFS_XATTR_SA)
+ zsb->z_xattr_sa = B_TRUE;
+ else
+ zsb->z_xattr_sa = B_FALSE;
+ }
}
static void
int i, error;
uint64_t sa_obj;
- zsb = kmem_zalloc(sizeof (zfs_sb_t), KM_SLEEP);
+ zsb = kmem_zalloc(sizeof (zfs_sb_t), KM_SLEEP | KM_NODEBUG);
/*
* We claim to always be readonly so we can open snapshots;
error = zap_lookup(os, MASTER_NODE_OBJ, ZFS_SA_ATTRS, 8, 1,
&sa_obj);
if (error)
- return (error);
+ goto out;
+
+ error = zfs_get_zplprop(os, ZFS_PROP_XATTR, &zval);
+ if ((error == 0) && (zval == ZFS_XATTR_SA))
+ zsb->z_xattr_sa = B_TRUE;
} else {
/*
* Pre SA versions file systems should never touch
for (i = 0; i != ZFS_OBJ_MTX_SZ; i++)
mutex_init(&zsb->z_hold_mtx[i], NULL, MUTEX_DEFAULT, NULL);
+ avl_create(&zsb->z_ctldir_snaps, snapentry_compare,
+ sizeof (zfs_snapentry_t), offsetof(zfs_snapentry_t, se_node));
+ mutex_init(&zsb->z_ctldir_lock, NULL, MUTEX_DEFAULT, NULL);
+
*zsbp = zsb;
return (0);
kmem_free(zsb, sizeof (zfs_sb_t));
return (error);
}
+EXPORT_SYMBOL(zfs_sb_create);
-static int
+int
zfs_sb_setup(zfs_sb_t *zsb, boolean_t mounting)
{
int error;
return (0);
}
+EXPORT_SYMBOL(zfs_sb_setup);
void
zfs_sb_free(zfs_sb_t *zsb)
rw_destroy(&zsb->z_fuid_lock);
for (i = 0; i != ZFS_OBJ_MTX_SZ; i++)
mutex_destroy(&zsb->z_hold_mtx[i]);
+ mutex_destroy(&zsb->z_ctldir_lock);
+ avl_destroy(&zsb->z_ctldir_snaps);
kmem_free(zsb, sizeof (zfs_sb_t));
}
+EXPORT_SYMBOL(zfs_sb_free);
static void
zfs_set_fuid_feature(zfs_sb_t *zsb)
}
return (EACCES);
}
+EXPORT_SYMBOL(zfs_check_global_label);
#endif /* HAVE_MLSLABEL */
int
{
zfs_sb_t *zsb = dentry->d_sb->s_fs_info;
uint64_t refdbytes, availbytes, usedobjs, availobjs;
+ uint64_t fsid;
uint32_t bshift;
ZFS_ENTER(zsb);
dmu_objset_space(zsb->z_os,
&refdbytes, &availbytes, &usedobjs, &availobjs);
+ fsid = dmu_objset_fsid_guid(zsb->z_os);
/*
* The underlying storage pool actually uses multiple block
* size. Under Solaris frsize (fragment size) is reported as
* For f_ffree, report the smaller of the number of object available
* and the number of blocks (each object will take at least a block).
*/
- statp->f_ffree = MIN(availobjs, statp->f_bfree);
+ statp->f_ffree = MIN(availobjs, availbytes >> DNODE_SHIFT);
statp->f_files = statp->f_ffree + usedobjs;
- statp->f_fsid.val[0] = dentry->d_sb->s_dev;
- statp->f_fsid.val[1] = 0;
+ statp->f_fsid.val[0] = (uint32_t)fsid;
+ statp->f_fsid.val[1] = (uint32_t)(fsid >> 32);
statp->f_type = ZFS_SUPER_MAGIC;
statp->f_namelen = ZFS_MAXNAMELEN;
}
EXPORT_SYMBOL(zfs_root);
+#ifdef HAVE_SHRINK
+int
+zfs_sb_prune(struct super_block *sb, unsigned long nr_to_scan, int *objects)
+{
+ zfs_sb_t *zsb = sb->s_fs_info;
+ struct shrinker *shrinker = &sb->s_shrink;
+ struct shrink_control sc = {
+ .nr_to_scan = nr_to_scan,
+ .gfp_mask = GFP_KERNEL,
+ };
+
+ ZFS_ENTER(zsb);
+ *objects = (*shrinker->shrink)(shrinker, &sc);
+ ZFS_EXIT(zsb);
+
+ return (0);
+}
+EXPORT_SYMBOL(zfs_sb_prune);
+#endif /* HAVE_SHRINK */
+
/*
* Teardown the zfs_sb_t::z_os.
*
* and 'z_teardown_inactive_lock' held.
*/
int
-zfsvfs_teardown(zfs_sb_t *zsb, boolean_t unmounting)
+zfs_sb_teardown(zfs_sb_t *zsb, boolean_t unmounting)
{
znode_t *zp;
/*
* Evict cached data
*/
- if (dmu_objset_is_dirty_anywhere(zsb->z_os))
- if (!zfs_is_readonly(zsb))
- txg_wait_synced(dmu_objset_pool(zsb->z_os), 0);
+ if (dsl_dataset_is_dirty(dmu_objset_ds(zsb->z_os)) &&
+ !zfs_is_readonly(zsb))
+ txg_wait_synced(dmu_objset_pool(zsb->z_os), 0);
(void) dmu_objset_evict_dbufs(zsb->z_os);
return (0);
}
+EXPORT_SYMBOL(zfs_sb_teardown);
+
+#if defined(HAVE_BDI) && !defined(HAVE_BDI_SETUP_AND_REGISTER)
+atomic_long_t zfs_bdi_seq = ATOMIC_LONG_INIT(0);
+#endif /* HAVE_BDI && !HAVE_BDI_SETUP_AND_REGISTER */
int
zfs_domount(struct super_block *sb, void *data, int silent)
sb->s_blocksize = recordsize;
sb->s_blocksize_bits = ilog2(recordsize);
+#ifdef HAVE_BDI
+ /*
+ * 2.6.32 API change,
+ * Added backing_device_info (BDI) per super block interfaces. A BDI
+ * must be configured when using a non-device backed filesystem for
+ * proper writeback. This is not required for older pdflush kernels.
+ *
+ * NOTE: Linux read-ahead is disabled in favor of zfs read-ahead.
+ */
+ zsb->z_bdi.ra_pages = 0;
+ sb->s_bdi = &zsb->z_bdi;
+
+ error = -bdi_setup_and_register(&zsb->z_bdi, "zfs", BDI_CAP_MAP_COPY);
+ if (error)
+ goto out;
+#endif /* HAVE_BDI */
+
/* Set callback operations for the file system. */
sb->s_op = &zpl_super_operations;
sb->s_xattr = zpl_xattr_handlers;
mutex_exit(&zsb->z_os->os_user_ptr_lock);
} else {
error = zfs_sb_setup(zsb, B_TRUE);
-#ifdef HAVE_SNAPSHOT
- (void) zfs_snap_create(zsb);
-#endif /* HAVE_SNAPSHOT */
}
/* Allocate a root inode for the filesystem. */
}
/* Allocate a root dentry for the filesystem */
- sb->s_root = d_alloc_root(root_inode);
+ sb->s_root = d_make_root(root_inode);
if (sb->s_root == NULL) {
(void) zfs_umount(sb);
error = ENOMEM;
goto out;
}
+
+ if (!zsb->z_issnap)
+ zfsctl_create(zsb);
out:
if (error) {
dmu_objset_disown(zsb->z_os, zsb);
}
EXPORT_SYMBOL(zfs_domount);
+/*
+ * Called when an unmount is requested and certain sanity checks have
+ * already passed. At this point no dentries or inodes have been reclaimed
+ * from their respective caches. We drop the extra reference on the .zfs
+ * control directory to allow everything to be reclaimed. All snapshots
+ * must already have been unmounted to reach this point.
+ */
+void
+zfs_preumount(struct super_block *sb)
+{
+ zfs_sb_t *zsb = sb->s_fs_info;
+
+ if (zsb != NULL && zsb->z_ctldir != NULL)
+ zfsctl_destroy(zsb);
+}
+EXPORT_SYMBOL(zfs_preumount);
+
+/*
+ * Called once all other unmount released tear down has occurred.
+ * It is our responsibility to release any remaining infrastructure.
+ */
/*ARGSUSED*/
int
zfs_umount(struct super_block *sb)
zfs_sb_t *zsb = sb->s_fs_info;
objset_t *os;
- VERIFY(zfsvfs_teardown(zsb, B_TRUE) == 0);
+ VERIFY(zfs_sb_teardown(zsb, B_TRUE) == 0);
os = zsb->z_os;
+#ifdef HAVE_BDI
+ bdi_destroy(sb->s_bdi);
+#endif /* HAVE_BDI */
+
/*
* z_os will be NULL if there was an error in
* attempting to reopen zsb.
ZFS_EXIT(zsb);
-#ifdef HAVE_SNAPSHOT
- err = zfsctl_lookup_objset(vfsp, objsetid, &zsb);
+ err = zfsctl_lookup_objset(sb, objsetid, &zsb);
if (err)
return (EINVAL);
-#endif /* HAVE_SNAPSHOT */
+
ZFS_ENTER(zsb);
}
return (EINVAL);
}
-#ifdef HAVE_SNAPSHOT
/* A zero fid_gen means we are in the .zfs control directories */
if (fid_gen == 0 &&
(object == ZFSCTL_INO_ROOT || object == ZFSCTL_INO_SNAPDIR)) {
*ipp = zsb->z_ctldir;
ASSERT(*ipp != NULL);
if (object == ZFSCTL_INO_SNAPDIR) {
- VERIFY(zfsctl_root_lookup(*ipp, "snapshot", ipp, NULL,
- 0, NULL, NULL, NULL, NULL, NULL) == 0);
+ VERIFY(zfsctl_root_lookup(*ipp, "snapshot", ipp,
+ 0, kcred, NULL, NULL) == 0);
} else {
igrab(*ipp);
}
ZFS_EXIT(zsb);
return (0);
}
-#endif /* HAVE_SNAPSHOT */
gen_mask = -1ULL >> (64 - 8 * i);
{
int error;
- if ((error = zfsvfs_teardown(zsb, B_FALSE)) != 0)
+ if ((error = zfs_sb_teardown(zsb, B_FALSE)) != 0)
return (error);
dmu_objset_disown(zsb->z_os, zsb);
}
return (error);
}
+EXPORT_SYMBOL(zfs_get_zplprop);
void
zfs_init(void)
{
+ zfsctl_init();
zfs_znode_init();
dmu_objset_register_type(DMU_OST_ZFS, zfs_space_delta_cb);
register_filesystem(&zpl_fs_type);
+ (void) arc_add_prune_callback(zpl_prune_sbs, NULL);
}
void
{
unregister_filesystem(&zpl_fs_type);
zfs_znode_fini();
+ zfsctl_fini();
}