Merge f5215349f8
into c28f94f32e
This commit is contained in:
commit
25fcb06ec5
|
@ -0,0 +1,27 @@
|
||||||
|
dnl #
|
||||||
|
dnl # Linux 5.10 added the the seq_read_iter helper
|
||||||
|
dnl #
|
||||||
|
AC_DEFUN([ZFS_AC_KERNEL_SRC_SEQ_READ_ITER], [
|
||||||
|
ZFS_LINUX_TEST_SRC([seq_file_has_seq_read_iter], [
|
||||||
|
#include <linux/seq_file.h>
|
||||||
|
#include <linux/fs.h>
|
||||||
|
static const struct file_operations
|
||||||
|
fops __attribute__ ((unused)) = {
|
||||||
|
.read_iter = seq_read_iter
|
||||||
|
};
|
||||||
|
],[])
|
||||||
|
])
|
||||||
|
|
||||||
|
AC_DEFUN([ZFS_AC_KERNEL_SEQ_READ_ITER], [
|
||||||
|
dnl #
|
||||||
|
dnl # Linux 5.10 added the the seq_read_iter helper
|
||||||
|
dnl #
|
||||||
|
AC_MSG_CHECKING([whether seq_file's seq_read_iter() exists])
|
||||||
|
ZFS_LINUX_TEST_RESULT([seq_file_has_seq_read_iter], [
|
||||||
|
AC_MSG_RESULT([yes])
|
||||||
|
AC_DEFINE(HAVE_SEQ_READ_ITER, 1,
|
||||||
|
[seq_file has seq_read_iter()])
|
||||||
|
],[
|
||||||
|
AC_MSG_RESULT([no])
|
||||||
|
])
|
||||||
|
])
|
|
@ -167,6 +167,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [
|
||||||
ZFS_AC_KERNEL_SRC_REGISTER_SYSCTL_TABLE
|
ZFS_AC_KERNEL_SRC_REGISTER_SYSCTL_TABLE
|
||||||
ZFS_AC_KERNEL_SRC_COPY_SPLICE_READ
|
ZFS_AC_KERNEL_SRC_COPY_SPLICE_READ
|
||||||
ZFS_AC_KERNEL_SRC_SYNC_BDEV
|
ZFS_AC_KERNEL_SRC_SYNC_BDEV
|
||||||
|
ZFS_AC_KERNEL_SRC_SEQ_READ_ITER
|
||||||
case "$host_cpu" in
|
case "$host_cpu" in
|
||||||
powerpc*)
|
powerpc*)
|
||||||
ZFS_AC_KERNEL_SRC_CPU_HAS_FEATURE
|
ZFS_AC_KERNEL_SRC_CPU_HAS_FEATURE
|
||||||
|
@ -316,6 +317,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [
|
||||||
ZFS_AC_KERNEL_REGISTER_SYSCTL_TABLE
|
ZFS_AC_KERNEL_REGISTER_SYSCTL_TABLE
|
||||||
ZFS_AC_KERNEL_COPY_SPLICE_READ
|
ZFS_AC_KERNEL_COPY_SPLICE_READ
|
||||||
ZFS_AC_KERNEL_SYNC_BDEV
|
ZFS_AC_KERNEL_SYNC_BDEV
|
||||||
|
ZFS_AC_KERNEL_SEQ_READ_ITER
|
||||||
case "$host_cpu" in
|
case "$host_cpu" in
|
||||||
powerpc*)
|
powerpc*)
|
||||||
ZFS_AC_KERNEL_CPU_HAS_FEATURE
|
ZFS_AC_KERNEL_CPU_HAS_FEATURE
|
||||||
|
|
|
@ -39,6 +39,11 @@
|
||||||
#define ZFS_CTLDIR_NAME ".zfs"
|
#define ZFS_CTLDIR_NAME ".zfs"
|
||||||
#define ZFS_SNAPDIR_NAME "snapshot"
|
#define ZFS_SNAPDIR_NAME "snapshot"
|
||||||
#define ZFS_SHAREDIR_NAME "shares"
|
#define ZFS_SHAREDIR_NAME "shares"
|
||||||
|
#define ZFS_SPACEDIR_NAME "space"
|
||||||
|
#define ZFS_QUOTADIR_NAME "quota"
|
||||||
|
#define ZFS_USERFILE_NAME "user"
|
||||||
|
#define ZFS_GROUPFILE_NAME "group"
|
||||||
|
#define ZFS_PROJECTFILE_NAME "project"
|
||||||
|
|
||||||
#define zfs_has_ctldir(zdp) \
|
#define zfs_has_ctldir(zdp) \
|
||||||
((zdp)->z_id == ZTOZSB(zdp)->z_root && \
|
((zdp)->z_id == ZTOZSB(zdp)->z_root && \
|
||||||
|
@ -48,6 +53,7 @@
|
||||||
(ZTOZSB(zdp)->z_show_ctldir))
|
(ZTOZSB(zdp)->z_show_ctldir))
|
||||||
|
|
||||||
extern int zfs_expire_snapshot;
|
extern int zfs_expire_snapshot;
|
||||||
|
extern int zfs_ctldir_spacefiles;
|
||||||
|
|
||||||
/* zfsctl generic functions */
|
/* zfsctl generic functions */
|
||||||
extern int zfsctl_create(zfsvfs_t *);
|
extern int zfsctl_create(zfsvfs_t *);
|
||||||
|
@ -86,6 +92,16 @@ extern int zfsctl_shares_lookup(struct inode *dip, char *name,
|
||||||
struct inode **ipp, int flags, cred_t *cr, int *direntflags,
|
struct inode **ipp, int flags, cred_t *cr, int *direntflags,
|
||||||
pathname_t *realpnp);
|
pathname_t *realpnp);
|
||||||
|
|
||||||
|
/* zfsctl '.zfs/space' functions */
|
||||||
|
extern int zfsctl_spacedir_lookup(struct inode *dip, char *name,
|
||||||
|
struct inode **ipp, int flags, cred_t *cr, int *direntflags,
|
||||||
|
pathname_t *realpnp);
|
||||||
|
|
||||||
|
/* zfsctl '.zfs/quota' functions */
|
||||||
|
extern int zfsctl_quotadir_lookup(struct inode *dip, char *name,
|
||||||
|
struct inode **ipp, int flags, cred_t *cr, int *direntflags,
|
||||||
|
pathname_t *realpnp);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These inodes numbers are reserved for the .zfs control directory.
|
* These inodes numbers are reserved for the .zfs control directory.
|
||||||
* It is important that they be no larger that 48-bits because only
|
* It is important that they be no larger that 48-bits because only
|
||||||
|
@ -95,8 +111,22 @@ extern int zfsctl_shares_lookup(struct inode *dip, char *name,
|
||||||
*/
|
*/
|
||||||
#define ZFSCTL_INO_ROOT 0x0000FFFFFFFFFFFFULL
|
#define ZFSCTL_INO_ROOT 0x0000FFFFFFFFFFFFULL
|
||||||
#define ZFSCTL_INO_SHARES 0x0000FFFFFFFFFFFEULL
|
#define ZFSCTL_INO_SHARES 0x0000FFFFFFFFFFFEULL
|
||||||
#define ZFSCTL_INO_SNAPDIR 0x0000FFFFFFFFFFFDULL
|
#define ZFSCTL_INO_SPACEDIR 0x0000FFFFFFFFFFFDULL
|
||||||
#define ZFSCTL_INO_SNAPDIRS 0x0000FFFFFFFFFFFCULL
|
#define ZFSCTL_INO_SPACE_USER 0x0000FFFFFFFFFFFCULL
|
||||||
|
#define ZFSCTL_INO_SPACE_GROUP 0x0000FFFFFFFFFFFBULL
|
||||||
|
#define ZFSCTL_INO_SPACE_PROJ 0x0000FFFFFFFFFFFAULL
|
||||||
|
#define ZFSCTL_INO_QUOTADIR 0x0000FFFFFFFFFFF9ULL
|
||||||
|
#define ZFSCTL_INO_QUOTA_USER 0x0000FFFFFFFFFFF8ULL
|
||||||
|
#define ZFSCTL_INO_QUOTA_GROUP 0x0000FFFFFFFFFFF7ULL
|
||||||
|
#define ZFSCTL_INO_QUOTA_PROJ 0x0000FFFFFFFFFFF6ULL
|
||||||
|
/*
|
||||||
|
* snapdir inode numbers must be lowest; each snapshot gets its own
|
||||||
|
* directory and inode number, assigned by decrementing from
|
||||||
|
* ZFSCTL_INO_SNAPDIRS.
|
||||||
|
*/
|
||||||
|
#define ZFSCTL_INO_SNAPDIR 0x0000FFFFFFFFFFF5ULL
|
||||||
|
#define ZFSCTL_INO_SNAPDIRS 0x0000FFFFFFFFFFF4ULL
|
||||||
|
|
||||||
|
|
||||||
#define ZFSCTL_EXPIRE_SNAPSHOT 300
|
#define ZFSCTL_EXPIRE_SNAPSHOT 300
|
||||||
|
|
||||||
|
|
|
@ -118,6 +118,30 @@ extern const struct inode_operations zpl_ops_snapdir;
|
||||||
extern const struct file_operations zpl_fops_shares;
|
extern const struct file_operations zpl_fops_shares;
|
||||||
extern const struct inode_operations zpl_ops_shares;
|
extern const struct inode_operations zpl_ops_shares;
|
||||||
|
|
||||||
|
extern const struct file_operations zpl_fops_spacedir;
|
||||||
|
extern const struct inode_operations zpl_ops_spacedir;
|
||||||
|
|
||||||
|
extern const struct file_operations zpl_fops_userspace_file;
|
||||||
|
extern const struct inode_operations zpl_ops_userspace_file;
|
||||||
|
|
||||||
|
extern const struct file_operations zpl_fops_groupspace_file;
|
||||||
|
extern const struct inode_operations zpl_ops_groupspace_file;
|
||||||
|
|
||||||
|
extern const struct file_operations zpl_fops_projectspace_file;
|
||||||
|
extern const struct inode_operations zpl_ops_projectspace_file;
|
||||||
|
|
||||||
|
extern const struct file_operations zpl_fops_quotadir;
|
||||||
|
extern const struct inode_operations zpl_ops_quotadir;
|
||||||
|
|
||||||
|
extern const struct file_operations zpl_fops_userquota_file;
|
||||||
|
extern const struct inode_operations zpl_ops_userquota_file;
|
||||||
|
|
||||||
|
extern const struct file_operations zpl_fops_groupquota_file;
|
||||||
|
extern const struct inode_operations zpl_ops_groupquota_file;
|
||||||
|
|
||||||
|
extern const struct file_operations zpl_fops_projectquota_file;
|
||||||
|
extern const struct inode_operations zpl_ops_projectquota_file;
|
||||||
|
|
||||||
#if defined(HAVE_VFS_ITERATE) || defined(HAVE_VFS_ITERATE_SHARED)
|
#if defined(HAVE_VFS_ITERATE) || defined(HAVE_VFS_ITERATE_SHARED)
|
||||||
|
|
||||||
#define ZPL_DIR_CONTEXT_INIT(_dirent, _actor, _pos) { \
|
#define ZPL_DIR_CONTEXT_INIT(_dirent, _actor, _pos) { \
|
||||||
|
|
|
@ -1375,6 +1375,20 @@ which have the
|
||||||
.Em no_root_squash
|
.Em no_root_squash
|
||||||
option set.
|
option set.
|
||||||
.
|
.
|
||||||
|
.It Sy zfs_ctldir_spacefiles Ns = Ns Sy 0 Ns | Ns 1 Pq int
|
||||||
|
Enable the existence of (quota|space)/(user|group|project) files in the
|
||||||
|
.Sy .zfs
|
||||||
|
directory.
|
||||||
|
These files can be used in lieu of the
|
||||||
|
.Sy zfs-userspace(8) ,
|
||||||
|
.Sy zfs-groupspace(8) ,
|
||||||
|
and
|
||||||
|
.Sy zfs-projectspace(8)
|
||||||
|
tools to determine space and quota utilization for a given dataset.
|
||||||
|
These would normally be used when the dataset is being accessed over
|
||||||
|
a network, e.g. using NFS, where ZFS command line tools, libzfs,
|
||||||
|
etc. are not available.
|
||||||
|
.
|
||||||
.It Sy zfs_flags Ns = Ns Sy 0 Pq int
|
.It Sy zfs_flags Ns = Ns Sy 0 Pq int
|
||||||
Set additional debugging flags.
|
Set additional debugging flags.
|
||||||
The following flags may be bitwise-ored together:
|
The following flags may be bitwise-ored together:
|
||||||
|
|
|
@ -111,6 +111,7 @@ static krwlock_t zfs_snapshot_lock;
|
||||||
*/
|
*/
|
||||||
int zfs_expire_snapshot = ZFSCTL_EXPIRE_SNAPSHOT;
|
int zfs_expire_snapshot = ZFSCTL_EXPIRE_SNAPSHOT;
|
||||||
static int zfs_admin_snapshot = 0;
|
static int zfs_admin_snapshot = 0;
|
||||||
|
int zfs_ctldir_spacefiles = 0;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char *se_name; /* full snapshot name */
|
char *se_name; /* full snapshot name */
|
||||||
|
@ -818,6 +819,14 @@ zfsctl_root_lookup(struct inode *dip, const char *name, struct inode **ipp,
|
||||||
} else if (strcmp(name, ZFS_SHAREDIR_NAME) == 0) {
|
} else if (strcmp(name, ZFS_SHAREDIR_NAME) == 0) {
|
||||||
*ipp = zfsctl_inode_lookup(zfsvfs, ZFSCTL_INO_SHARES,
|
*ipp = zfsctl_inode_lookup(zfsvfs, ZFSCTL_INO_SHARES,
|
||||||
&zpl_fops_shares, &zpl_ops_shares);
|
&zpl_fops_shares, &zpl_ops_shares);
|
||||||
|
} else if (strcmp(name, ZFS_SPACEDIR_NAME) == 0 &&
|
||||||
|
zfs_ctldir_spacefiles) {
|
||||||
|
*ipp = zfsctl_inode_lookup(zfsvfs, ZFSCTL_INO_SPACEDIR,
|
||||||
|
&zpl_fops_spacedir, &zpl_ops_spacedir);
|
||||||
|
} else if (strcmp(name, ZFS_QUOTADIR_NAME) == 0 &&
|
||||||
|
zfs_ctldir_spacefiles) {
|
||||||
|
*ipp = zfsctl_inode_lookup(zfsvfs, ZFSCTL_INO_QUOTADIR,
|
||||||
|
&zpl_fops_quotadir, &zpl_ops_quotadir);
|
||||||
} else {
|
} else {
|
||||||
*ipp = NULL;
|
*ipp = NULL;
|
||||||
}
|
}
|
||||||
|
@ -1282,6 +1291,74 @@ zfsctl_shares_lookup(struct inode *dip, char *name, struct inode **ipp,
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
zfsctl_spacedir_lookup(struct inode *dip, char *name, struct inode **ipp,
|
||||||
|
int flags, cred_t *cr, int *direntflags, pathname_t *realpnp)
|
||||||
|
{
|
||||||
|
zfsvfs_t *zfsvfs = ITOZSB(dip);
|
||||||
|
int error;
|
||||||
|
|
||||||
|
if ((error = zfs_enter(zfsvfs, FTAG)) != 0)
|
||||||
|
return (error);
|
||||||
|
|
||||||
|
if (strcmp(name, ZFS_USERFILE_NAME) == 0) {
|
||||||
|
*ipp = zfsctl_inode_lookup(zfsvfs, ZFSCTL_INO_SPACE_USER,
|
||||||
|
&zpl_fops_userspace_file, &zpl_ops_userspace_file);
|
||||||
|
(*ipp)->i_mode = (S_IFREG|S_IRUGO);
|
||||||
|
} else if (strcmp(name, ZFS_GROUPFILE_NAME) == 0) {
|
||||||
|
*ipp = zfsctl_inode_lookup(zfsvfs, ZFSCTL_INO_SPACE_GROUP,
|
||||||
|
&zpl_fops_groupspace_file, &zpl_ops_groupspace_file);
|
||||||
|
(*ipp)->i_mode = (S_IFREG|S_IRUGO);
|
||||||
|
} else if (strcmp(name, ZFS_PROJECTFILE_NAME) == 0) {
|
||||||
|
*ipp = zfsctl_inode_lookup(zfsvfs, ZFSCTL_INO_SPACE_PROJ,
|
||||||
|
&zpl_fops_projectspace_file, &zpl_ops_projectspace_file);
|
||||||
|
(*ipp)->i_mode = (S_IFREG|S_IRUGO);
|
||||||
|
} else {
|
||||||
|
*ipp = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*ipp == NULL)
|
||||||
|
error = SET_ERROR(ENOENT);
|
||||||
|
|
||||||
|
zfs_exit(zfsvfs, FTAG);
|
||||||
|
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
zfsctl_quotadir_lookup(struct inode *dip, char *name, struct inode **ipp,
|
||||||
|
int flags, cred_t *cr, int *direntflags, pathname_t *realpnp)
|
||||||
|
{
|
||||||
|
zfsvfs_t *zfsvfs = ITOZSB(dip);
|
||||||
|
int error;
|
||||||
|
|
||||||
|
if ((error = zfs_enter(zfsvfs, FTAG)) != 0)
|
||||||
|
return (error);
|
||||||
|
|
||||||
|
if (strcmp(name, ZFS_USERFILE_NAME) == 0) {
|
||||||
|
*ipp = zfsctl_inode_lookup(zfsvfs, ZFSCTL_INO_QUOTA_USER,
|
||||||
|
&zpl_fops_userquota_file, &zpl_ops_userquota_file);
|
||||||
|
(*ipp)->i_mode = (S_IFREG|S_IRUGO);
|
||||||
|
} else if (strcmp(name, ZFS_GROUPFILE_NAME) == 0) {
|
||||||
|
*ipp = zfsctl_inode_lookup(zfsvfs, ZFSCTL_INO_QUOTA_GROUP,
|
||||||
|
&zpl_fops_groupquota_file, &zpl_ops_groupquota_file);
|
||||||
|
(*ipp)->i_mode = (S_IFREG|S_IRUGO);
|
||||||
|
} else if (strcmp(name, ZFS_PROJECTFILE_NAME) == 0) {
|
||||||
|
*ipp = zfsctl_inode_lookup(zfsvfs, ZFSCTL_INO_QUOTA_PROJ,
|
||||||
|
&zpl_fops_projectquota_file, &zpl_ops_projectquota_file);
|
||||||
|
(*ipp)->i_mode = (S_IFREG|S_IRUGO);
|
||||||
|
} else {
|
||||||
|
*ipp = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*ipp == NULL)
|
||||||
|
error = SET_ERROR(ENOENT);
|
||||||
|
|
||||||
|
zfs_exit(zfsvfs, FTAG);
|
||||||
|
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize the various pieces we'll need to create and manipulate .zfs
|
* Initialize the various pieces we'll need to create and manipulate .zfs
|
||||||
* directories. Currently this is unused but available.
|
* directories. Currently this is unused but available.
|
||||||
|
@ -1315,3 +1392,7 @@ MODULE_PARM_DESC(zfs_admin_snapshot, "Enable mkdir/rmdir/mv in .zfs/snapshot");
|
||||||
|
|
||||||
module_param(zfs_expire_snapshot, int, 0644);
|
module_param(zfs_expire_snapshot, int, 0644);
|
||||||
MODULE_PARM_DESC(zfs_expire_snapshot, "Seconds to expire .zfs/snapshot");
|
MODULE_PARM_DESC(zfs_expire_snapshot, "Seconds to expire .zfs/snapshot");
|
||||||
|
|
||||||
|
module_param(zfs_ctldir_spacefiles, int, 0644);
|
||||||
|
MODULE_PARM_DESC(zfs_ctldir_spacefiles,
|
||||||
|
"Enable user/group/project space/quota files in .zfs/");
|
||||||
|
|
|
@ -1760,13 +1760,37 @@ zfs_vget(struct super_block *sb, struct inode **ipp, fid_t *fidp)
|
||||||
if ((err = zfs_enter(zfsvfs, FTAG)) != 0)
|
if ((err = zfs_enter(zfsvfs, FTAG)) != 0)
|
||||||
return (err);
|
return (err);
|
||||||
/* A zero fid_gen means we are in the .zfs control directories */
|
/* A zero fid_gen means we are in the .zfs control directories */
|
||||||
if (fid_gen == 0 &&
|
if (fid_gen == 0 && object >= ZFSCTL_INO_SNAPDIR &&
|
||||||
(object == ZFSCTL_INO_ROOT || object == ZFSCTL_INO_SNAPDIR)) {
|
object <= ZFSCTL_INO_ROOT && object != ZFSCTL_INO_SHARES) {
|
||||||
*ipp = zfsvfs->z_ctldir;
|
*ipp = zfsvfs->z_ctldir;
|
||||||
ASSERT(*ipp != NULL);
|
ASSERT(*ipp != NULL);
|
||||||
if (object == ZFSCTL_INO_SNAPDIR) {
|
if (object == ZFSCTL_INO_SNAPDIR) {
|
||||||
VERIFY(zfsctl_root_lookup(*ipp, "snapshot", ipp,
|
VERIFY0(zfsctl_root_lookup(*ipp,
|
||||||
0, kcred, NULL, NULL) == 0);
|
ZFS_SNAPDIR_NAME, ipp, 0, kcred, NULL, NULL));
|
||||||
|
} else if (object == ZFSCTL_INO_SPACEDIR) {
|
||||||
|
VERIFY0(zfsctl_root_lookup(*ipp,
|
||||||
|
ZFS_SPACEDIR_NAME, ipp, 0, kcred, NULL, NULL));
|
||||||
|
} else if (object == ZFSCTL_INO_QUOTADIR) {
|
||||||
|
VERIFY0(zfsctl_root_lookup(*ipp,
|
||||||
|
ZFS_QUOTADIR_NAME, ipp, 0, kcred, NULL, NULL));
|
||||||
|
} else if (object == ZFSCTL_INO_SPACE_USER) {
|
||||||
|
VERIFY0(zfsctl_spacedir_lookup(*ipp,
|
||||||
|
ZFS_USERFILE_NAME, ipp, 0, kcred, NULL, NULL));
|
||||||
|
} else if (object == ZFSCTL_INO_SPACE_GROUP) {
|
||||||
|
VERIFY0(zfsctl_spacedir_lookup(*ipp,
|
||||||
|
ZFS_GROUPFILE_NAME, ipp, 0, kcred, NULL, NULL));
|
||||||
|
} else if (object == ZFSCTL_INO_SPACE_PROJ) {
|
||||||
|
VERIFY0(zfsctl_spacedir_lookup(*ipp,
|
||||||
|
ZFS_PROJECTFILE_NAME, ipp, 0, kcred, NULL, NULL));
|
||||||
|
} else if (object == ZFSCTL_INO_QUOTA_USER) {
|
||||||
|
VERIFY0(zfsctl_quotadir_lookup(*ipp,
|
||||||
|
ZFS_USERFILE_NAME, ipp, 0, kcred, NULL, NULL));
|
||||||
|
} else if (object == ZFSCTL_INO_QUOTA_GROUP) {
|
||||||
|
VERIFY0(zfsctl_quotadir_lookup(*ipp,
|
||||||
|
ZFS_GROUPFILE_NAME, ipp, 0, kcred, NULL, NULL));
|
||||||
|
} else if (object == ZFSCTL_INO_QUOTA_PROJ) {
|
||||||
|
VERIFY0(zfsctl_quotadir_lookup(*ipp,
|
||||||
|
ZFS_PROJECTFILE_NAME, ipp, 0, kcred, NULL, NULL));
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* Must have an existing ref, so igrab()
|
* Must have an existing ref, so igrab()
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include <sys/zfs_vfsops.h>
|
#include <sys/zfs_vfsops.h>
|
||||||
#include <sys/zfs_vnops.h>
|
#include <sys/zfs_vnops.h>
|
||||||
#include <sys/zfs_ctldir.h>
|
#include <sys/zfs_ctldir.h>
|
||||||
|
#include <sys/zfs_quota.h>
|
||||||
#include <sys/zpl.h>
|
#include <sys/zpl.h>
|
||||||
#include <sys/dmu.h>
|
#include <sys/dmu.h>
|
||||||
#include <sys/dsl_dataset.h>
|
#include <sys/dsl_dataset.h>
|
||||||
|
@ -60,27 +61,55 @@ zpl_root_iterate(struct file *filp, zpl_dir_context_t *ctx)
|
||||||
if ((error = zpl_enter(zfsvfs, FTAG)) != 0)
|
if ((error = zpl_enter(zfsvfs, FTAG)) != 0)
|
||||||
return (error);
|
return (error);
|
||||||
|
|
||||||
if (!zpl_dir_emit_dots(filp, ctx))
|
if (!zpl_dir_emit_dots(filp, ctx)) {
|
||||||
|
error = SET_ERROR(-EIO);
|
||||||
goto out;
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
if (ctx->pos == 2) {
|
if (ctx->pos == 2) {
|
||||||
if (!zpl_dir_emit(ctx, ZFS_SNAPDIR_NAME,
|
if (!zpl_dir_emit(ctx, ZFS_SNAPDIR_NAME,
|
||||||
strlen(ZFS_SNAPDIR_NAME), ZFSCTL_INO_SNAPDIR, DT_DIR))
|
strlen(ZFS_SNAPDIR_NAME), ZFSCTL_INO_SNAPDIR, DT_DIR)) {
|
||||||
|
error = SET_ERROR(-EIO);
|
||||||
goto out;
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
ctx->pos++;
|
ctx->pos++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx->pos == 3) {
|
if (ctx->pos == 3) {
|
||||||
if (!zpl_dir_emit(ctx, ZFS_SHAREDIR_NAME,
|
if (!zpl_dir_emit(ctx, ZFS_SHAREDIR_NAME,
|
||||||
strlen(ZFS_SHAREDIR_NAME), ZFSCTL_INO_SHARES, DT_DIR))
|
strlen(ZFS_SHAREDIR_NAME), ZFSCTL_INO_SHARES, DT_DIR)) {
|
||||||
|
error = SET_ERROR(-EIO);
|
||||||
goto out;
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
ctx->pos++;
|
ctx->pos++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ctx->pos == 4 && zfs_ctldir_spacefiles) {
|
||||||
|
if (!zpl_dir_emit(ctx, ZFS_SPACEDIR_NAME,
|
||||||
|
strlen(ZFS_SPACEDIR_NAME),
|
||||||
|
ZFSCTL_INO_SPACEDIR, DT_DIR)) {
|
||||||
|
error = SET_ERROR(-EIO);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->pos++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx->pos == 5 && zfs_ctldir_spacefiles) {
|
||||||
|
if (!zpl_dir_emit(ctx, ZFS_QUOTADIR_NAME,
|
||||||
|
strlen(ZFS_QUOTADIR_NAME),
|
||||||
|
ZFSCTL_INO_QUOTADIR, DT_DIR)) {
|
||||||
|
error = SET_ERROR(-EIO);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->pos++;
|
||||||
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
zpl_exit(zfsvfs, FTAG);
|
zpl_exit(zfsvfs, FTAG);
|
||||||
|
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -671,3 +700,551 @@ const struct inode_operations zpl_ops_shares = {
|
||||||
.lookup = zpl_shares_lookup,
|
.lookup = zpl_shares_lookup,
|
||||||
.getattr = zpl_shares_getattr,
|
.getattr = zpl_shares_getattr,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
zpl_spacedir_iterate(struct file *filp, zpl_dir_context_t *ctx)
|
||||||
|
{
|
||||||
|
zfsvfs_t *zfsvfs = ITOZSB(file_inode(filp));
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
if ((error = zpl_enter(zfsvfs, FTAG)) != 0)
|
||||||
|
return (error);
|
||||||
|
|
||||||
|
if (!zpl_dir_emit_dots(filp, ctx)) {
|
||||||
|
error = SET_ERROR(-EIO);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx->pos == 2) {
|
||||||
|
if (!zpl_dir_emit(ctx, ZFS_USERFILE_NAME,
|
||||||
|
strlen(ZFS_USERFILE_NAME), ZFSCTL_INO_SPACE_USER,
|
||||||
|
DT_REG)) {
|
||||||
|
error = SET_ERROR(-EIO);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->pos++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx->pos == 3) {
|
||||||
|
if (!zpl_dir_emit(ctx, ZFS_GROUPFILE_NAME,
|
||||||
|
strlen(ZFS_GROUPFILE_NAME), ZFSCTL_INO_SPACE_GROUP,
|
||||||
|
DT_REG)) {
|
||||||
|
error = SET_ERROR(-EIO);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->pos++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx->pos == 4) {
|
||||||
|
if (!zpl_dir_emit(ctx, ZFS_PROJECTFILE_NAME,
|
||||||
|
strlen(ZFS_PROJECTFILE_NAME), ZFSCTL_INO_SPACE_PROJ,
|
||||||
|
DT_REG)) {
|
||||||
|
error = SET_ERROR(-EIO);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->pos++;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
zpl_exit(zfsvfs, FTAG);
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !defined(HAVE_VFS_ITERATE) && !defined(HAVE_VFS_ITERATE_SHARED)
|
||||||
|
static int
|
||||||
|
zpl_spacedir_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
||||||
|
{
|
||||||
|
zpl_dir_context_t ctx =
|
||||||
|
ZPL_DIR_CONTEXT_INIT(dirent, filldir, filp->f_pos);
|
||||||
|
int error;
|
||||||
|
|
||||||
|
error = zpl_spacedir_iterate(filp, &ctx);
|
||||||
|
filp->f_pos = ctx.pos;
|
||||||
|
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
#endif /* !HAVE_VFS_ITERATE && !HAVE_VFS_ITERATE_SHARED */
|
||||||
|
|
||||||
|
static struct dentry *
|
||||||
|
zpl_spacedir_lookup(struct inode *dip, struct dentry *dentry,
|
||||||
|
unsigned int flags)
|
||||||
|
{
|
||||||
|
cred_t *cr = CRED();
|
||||||
|
struct inode *ip;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
crhold(cr);
|
||||||
|
error = -zfsctl_spacedir_lookup(dip, dname(dentry), &ip, 0, cr,
|
||||||
|
NULL, NULL);
|
||||||
|
ASSERT3S(error, <=, 0);
|
||||||
|
crfree(cr);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
if (error == -ENOENT)
|
||||||
|
return (d_splice_alias(NULL, dentry));
|
||||||
|
else
|
||||||
|
return (ERR_PTR(error));
|
||||||
|
}
|
||||||
|
|
||||||
|
return (d_splice_alias(ip, dentry));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
#ifdef HAVE_USERNS_IOPS_GETATTR
|
||||||
|
zpl_spacedir_getattr_impl(struct user_namespace *user_ns,
|
||||||
|
const struct path *path, struct kstat *stat, u32 request_mask,
|
||||||
|
unsigned int query_flags)
|
||||||
|
#elif defined(HAVE_IDMAP_IOPS_GETATTR)
|
||||||
|
zpl_spacedir_getattr_impl(struct mnt_idmap *user_ns,
|
||||||
|
const struct path *path, struct kstat *stat, u32 request_mask,
|
||||||
|
unsigned int query_flags)
|
||||||
|
#else
|
||||||
|
zpl_spacedir_getattr_impl(const struct path *path, struct kstat *stat,
|
||||||
|
u32 request_mask, unsigned int query_flags)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
(void) request_mask, (void) query_flags;
|
||||||
|
struct inode *ip = path->dentry->d_inode;
|
||||||
|
|
||||||
|
#if (defined(HAVE_USERNS_IOPS_GETATTR) || defined(HAVE_IDMAP_IOPS_GETATTR))
|
||||||
|
#ifdef HAVE_GENERIC_FILLATTR_USERNS
|
||||||
|
generic_fillattr(user_ns, ip, stat);
|
||||||
|
#elif defined(HAVE_GENERIC_FILLATTR_IDMAP)
|
||||||
|
generic_fillattr(user_ns, ip, stat);
|
||||||
|
#elif defined(HAVE_GENERIC_FILLATTR_IDMAP_REQMASK)
|
||||||
|
generic_fillattr(user_ns, request_mask, ip, stat);
|
||||||
|
#else
|
||||||
|
(void) user_ns;
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
generic_fillattr(ip, stat);
|
||||||
|
#endif
|
||||||
|
stat->atime = current_time(ip);
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
ZPL_GETATTR_WRAPPER(zpl_spacedir_getattr);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The '.zfs/space' directory file operations.
|
||||||
|
*/
|
||||||
|
const struct file_operations zpl_fops_spacedir = {
|
||||||
|
.open = zpl_common_open,
|
||||||
|
.llseek = generic_file_llseek,
|
||||||
|
.read = generic_read_dir,
|
||||||
|
#ifdef HAVE_VFS_ITERATE_SHARED
|
||||||
|
.iterate_shared = zpl_spacedir_iterate,
|
||||||
|
#elif defined(HAVE_VFS_ITERATE)
|
||||||
|
.iterate = zpl_spacedir_iterate,
|
||||||
|
#else
|
||||||
|
.readdir = zpl_spacedir_readdir,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The '.zfs/space' directory inode operations.
|
||||||
|
*/
|
||||||
|
const struct inode_operations zpl_ops_spacedir = {
|
||||||
|
.lookup = zpl_spacedir_lookup,
|
||||||
|
.getattr = zpl_spacedir_getattr,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
zpl_quotadir_iterate(struct file *filp, zpl_dir_context_t *ctx)
|
||||||
|
{
|
||||||
|
zfsvfs_t *zfsvfs = ITOZSB(file_inode(filp));
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
if ((error = zpl_enter(zfsvfs, FTAG)) != 0)
|
||||||
|
return (error);
|
||||||
|
|
||||||
|
if (!zpl_dir_emit_dots(filp, ctx)) {
|
||||||
|
error = SET_ERROR(-EIO);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx->pos == 2) {
|
||||||
|
if (!zpl_dir_emit(ctx, ZFS_USERFILE_NAME,
|
||||||
|
strlen(ZFS_USERFILE_NAME), ZFSCTL_INO_QUOTA_USER,
|
||||||
|
DT_REG)) {
|
||||||
|
error = SET_ERROR(-EIO);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->pos++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx->pos == 3) {
|
||||||
|
if (!zpl_dir_emit(ctx, ZFS_GROUPFILE_NAME,
|
||||||
|
strlen(ZFS_GROUPFILE_NAME), ZFSCTL_INO_QUOTA_GROUP,
|
||||||
|
DT_REG)) {
|
||||||
|
error = SET_ERROR(-EIO);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->pos++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx->pos == 4) {
|
||||||
|
if (!zpl_dir_emit(ctx, ZFS_PROJECTFILE_NAME,
|
||||||
|
strlen(ZFS_PROJECTFILE_NAME), ZFSCTL_INO_QUOTA_PROJ,
|
||||||
|
DT_REG)) {
|
||||||
|
error = SET_ERROR(-EIO);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->pos++;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
zpl_exit(zfsvfs, FTAG);
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !defined(HAVE_VFS_ITERATE) && !defined(HAVE_VFS_ITERATE_SHARED)
|
||||||
|
static int
|
||||||
|
zpl_quotadir_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
||||||
|
{
|
||||||
|
zpl_dir_context_t ctx =
|
||||||
|
ZPL_DIR_CONTEXT_INIT(dirent, filldir, filp->f_pos);
|
||||||
|
int error;
|
||||||
|
|
||||||
|
error = zpl_quotadir_iterate(filp, &ctx);
|
||||||
|
filp->f_pos = ctx.pos;
|
||||||
|
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
#endif /* !HAVE_VFS_ITERATE && !HAVE_VFS_ITERATE_SHARED */
|
||||||
|
|
||||||
|
static struct dentry *
|
||||||
|
zpl_quotadir_lookup(struct inode *dip, struct dentry *dentry,
|
||||||
|
unsigned int flags)
|
||||||
|
{
|
||||||
|
cred_t *cr = CRED();
|
||||||
|
struct inode *ip;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
crhold(cr);
|
||||||
|
error = -zfsctl_quotadir_lookup(dip, dname(dentry), &ip, 0, cr,
|
||||||
|
NULL, NULL);
|
||||||
|
ASSERT3S(error, <=, 0);
|
||||||
|
crfree(cr);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
if (error == -ENOENT)
|
||||||
|
return (d_splice_alias(NULL, dentry));
|
||||||
|
else
|
||||||
|
return (ERR_PTR(error));
|
||||||
|
}
|
||||||
|
|
||||||
|
return (d_splice_alias(ip, dentry));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
#ifdef HAVE_USERNS_IOPS_GETATTR
|
||||||
|
zpl_quotadir_getattr_impl(struct user_namespace *user_ns,
|
||||||
|
const struct path *path, struct kstat *stat, u32 request_mask,
|
||||||
|
unsigned int query_flags)
|
||||||
|
#elif defined(HAVE_IDMAP_IOPS_GETATTR)
|
||||||
|
zpl_quotadir_getattr_impl(struct mnt_idmap *user_ns,
|
||||||
|
const struct path *path, struct kstat *stat, u32 request_mask,
|
||||||
|
unsigned int query_flags)
|
||||||
|
#else
|
||||||
|
zpl_quotadir_getattr_impl(const struct path *path, struct kstat *stat,
|
||||||
|
u32 request_mask, unsigned int query_flags)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
(void) request_mask, (void) query_flags;
|
||||||
|
struct inode *ip = path->dentry->d_inode;
|
||||||
|
|
||||||
|
#if (defined(HAVE_USERNS_IOPS_GETATTR) || defined(HAVE_IDMAP_IOPS_GETATTR))
|
||||||
|
#ifdef HAVE_GENERIC_FILLATTR_USERNS
|
||||||
|
generic_fillattr(user_ns, ip, stat);
|
||||||
|
#elif defined(HAVE_GENERIC_FILLATTR_IDMAP)
|
||||||
|
generic_fillattr(user_ns, ip, stat);
|
||||||
|
#elif defined(HAVE_GENERIC_FILLATTR_IDMAP_REQMASK)
|
||||||
|
generic_fillattr(user_ns, request_mask, ip, stat);
|
||||||
|
#else
|
||||||
|
(void) user_ns;
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
generic_fillattr(ip, stat);
|
||||||
|
#endif
|
||||||
|
stat->atime = current_time(ip);
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
ZPL_GETATTR_WRAPPER(zpl_quotadir_getattr);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The '.zfs/quota' directory file operations.
|
||||||
|
*/
|
||||||
|
const struct file_operations zpl_fops_quotadir = {
|
||||||
|
.open = zpl_common_open,
|
||||||
|
.llseek = generic_file_llseek,
|
||||||
|
.read = generic_read_dir,
|
||||||
|
#ifdef HAVE_VFS_ITERATE_SHARED
|
||||||
|
.iterate_shared = zpl_quotadir_iterate,
|
||||||
|
#elif defined(HAVE_VFS_ITERATE)
|
||||||
|
.iterate = zpl_quotadir_iterate,
|
||||||
|
#else
|
||||||
|
.readdir = zpl_quotadir_readdir,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The '.zfs/quota' directory inode operations.
|
||||||
|
*/
|
||||||
|
const struct inode_operations zpl_ops_quotadir = {
|
||||||
|
.lookup = zpl_quotadir_lookup,
|
||||||
|
.getattr = zpl_quotadir_getattr,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Helpers for:
|
||||||
|
* .zfs/(space|quota)user
|
||||||
|
* .zfs/(space|quota)group
|
||||||
|
* .zfs/(space|quota)project
|
||||||
|
*/
|
||||||
|
static int foreach_zfs_useracct(zfsvfs_t *zfsvfs,
|
||||||
|
zfs_userquota_prop_t type, uint64_t cookie,
|
||||||
|
int (*fn)(zfs_useracct_t *zua, zfs_userquota_prop_t type, void *v),
|
||||||
|
void *fn_arg)
|
||||||
|
{
|
||||||
|
uint64_t cbufsize, bufsize = 16 * sizeof (zfs_useracct_t);
|
||||||
|
zfs_useracct_t *buf = (zfs_useracct_t *)kmem_alloc(bufsize, KM_SLEEP);
|
||||||
|
int err = 0;
|
||||||
|
for (;;) {
|
||||||
|
cbufsize = bufsize;
|
||||||
|
if (zfs_userspace_many(zfsvfs, type, &cookie,
|
||||||
|
buf, &cbufsize)) {
|
||||||
|
err = 1;
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
if (cbufsize == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
zfs_useracct_t *zua = buf;
|
||||||
|
while (cbufsize > 0) {
|
||||||
|
if (fn(zua, type, fn_arg)) {
|
||||||
|
err = 1;
|
||||||
|
}
|
||||||
|
zua++;
|
||||||
|
cbufsize -= sizeof (zfs_useracct_t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
kmem_free(buf, bufsize);
|
||||||
|
return (err);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int zua_nvlist_add(zfs_useracct_t *zua,
|
||||||
|
zfs_userquota_prop_t type, void *v)
|
||||||
|
{
|
||||||
|
nvlist_t *ids = (nvlist_t *)v;
|
||||||
|
char name[MAXNAMELEN];
|
||||||
|
(void) snprintf(name, sizeof (name), "%u", zua->zu_rid);
|
||||||
|
nvlist_t *spacelist;
|
||||||
|
if (nvlist_lookup_nvlist(ids, name, &spacelist) ||
|
||||||
|
spacelist == NULL) {
|
||||||
|
VERIFY0(nvlist_alloc(&spacelist, NV_UNIQUE_NAME, KM_NOSLEEP));
|
||||||
|
VERIFY0(nvlist_add_nvlist(ids, name, spacelist));
|
||||||
|
/* lookup again because nvlist_add_nvlist does a deep-copy */
|
||||||
|
VERIFY0(nvlist_lookup_nvlist(ids, name, &spacelist));
|
||||||
|
}
|
||||||
|
VERIFY0(nvlist_add_uint64(spacelist,
|
||||||
|
zfs_userquota_prop_prefixes[type], zua->zu_space));
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void seq_print_spaceval(struct seq_file *seq, nvlist_t *spacelist,
|
||||||
|
zfs_userquota_prop_t type)
|
||||||
|
{
|
||||||
|
uint64_t spaceval;
|
||||||
|
seq_printf(seq, ",");
|
||||||
|
if (!nvlist_lookup_uint64(spacelist,
|
||||||
|
zfs_userquota_prop_prefixes[type],
|
||||||
|
&spaceval)) {
|
||||||
|
seq_printf(seq, "%llu", spaceval);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int zpl_quotaspace_show(struct seq_file *seq)
|
||||||
|
{
|
||||||
|
zfs_userquota_prop_t *props = (zfs_userquota_prop_t *)seq->private;
|
||||||
|
zfsvfs_t *zfsvfs = ITOZSB(file_inode(seq->file));
|
||||||
|
nvlist_t *ids;
|
||||||
|
unsigned int i;
|
||||||
|
VERIFY0(nvlist_alloc(&ids, NV_UNIQUE_NAME, 0));
|
||||||
|
for (i = 0; i < 2; ++i)
|
||||||
|
VERIFY0(foreach_zfs_useracct(zfsvfs, props[i], 0,
|
||||||
|
zua_nvlist_add, ids));
|
||||||
|
for (nvpair_t *idpair = nvlist_next_nvpair(ids, NULL);
|
||||||
|
idpair != NULL; idpair = nvlist_next_nvpair(ids, idpair)) {
|
||||||
|
const char *id = nvpair_name(idpair);
|
||||||
|
seq_printf(seq, "%s", id);
|
||||||
|
nvlist_t *spacelist;
|
||||||
|
VERIFY0(nvpair_value_nvlist(idpair, &spacelist));
|
||||||
|
for (i = 0; i < 2; ++i)
|
||||||
|
seq_print_spaceval(seq, spacelist, props[i]);
|
||||||
|
seq_putc(seq, '\n');
|
||||||
|
}
|
||||||
|
nvlist_free(ids);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int zpl_quota_show(struct seq_file *seq, void *v)
|
||||||
|
{
|
||||||
|
seq_printf(seq, "id,quota,objquota\n");
|
||||||
|
return (zpl_quotaspace_show(seq));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int zpl_space_show(struct seq_file *seq, void *v)
|
||||||
|
{
|
||||||
|
seq_printf(seq, "id,used,objused\n");
|
||||||
|
return (zpl_quotaspace_show(seq));
|
||||||
|
}
|
||||||
|
|
||||||
|
static zfs_userquota_prop_t userspace_props[2] = {
|
||||||
|
ZFS_PROP_USERUSED,
|
||||||
|
ZFS_PROP_USEROBJUSED
|
||||||
|
};
|
||||||
|
|
||||||
|
static zfs_userquota_prop_t groupspace_props[2] = {
|
||||||
|
ZFS_PROP_GROUPUSED,
|
||||||
|
ZFS_PROP_GROUPOBJUSED
|
||||||
|
};
|
||||||
|
|
||||||
|
static zfs_userquota_prop_t projectspace_props[2] = {
|
||||||
|
ZFS_PROP_PROJECTUSED,
|
||||||
|
ZFS_PROP_PROJECTOBJUSED
|
||||||
|
};
|
||||||
|
|
||||||
|
static zfs_userquota_prop_t userquota_props[2] = {
|
||||||
|
ZFS_PROP_USERQUOTA,
|
||||||
|
ZFS_PROP_USEROBJQUOTA
|
||||||
|
};
|
||||||
|
|
||||||
|
static zfs_userquota_prop_t groupquota_props[2] = {
|
||||||
|
ZFS_PROP_GROUPQUOTA,
|
||||||
|
ZFS_PROP_GROUPOBJQUOTA
|
||||||
|
};
|
||||||
|
|
||||||
|
static zfs_userquota_prop_t projectquota_props[2] = {
|
||||||
|
ZFS_PROP_PROJECTQUOTA,
|
||||||
|
ZFS_PROP_PROJECTOBJQUOTA
|
||||||
|
};
|
||||||
|
|
||||||
|
static int zpl_fops_userspace_open(struct inode *inode, struct file *file)
|
||||||
|
{
|
||||||
|
return single_open(file, zpl_space_show,
|
||||||
|
(void *)userspace_props);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int zpl_fops_groupspace_open(struct inode *inode, struct file *file)
|
||||||
|
{
|
||||||
|
return single_open(file, zpl_space_show,
|
||||||
|
(void *)groupspace_props);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int zpl_fops_projectspace_open(struct inode *inode, struct file *file)
|
||||||
|
{
|
||||||
|
return single_open(file, zpl_space_show,
|
||||||
|
(void *)projectspace_props);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int zpl_fops_userquota_open(struct inode *inode, struct file *file)
|
||||||
|
{
|
||||||
|
return single_open(file, zpl_quota_show,
|
||||||
|
(void *)userquota_props);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int zpl_fops_groupquota_open(struct inode *inode, struct file *file)
|
||||||
|
{
|
||||||
|
return single_open(file, zpl_quota_show,
|
||||||
|
(void *)groupquota_props);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int zpl_fops_projectquota_open(struct inode *inode, struct file *file)
|
||||||
|
{
|
||||||
|
return single_open(file, zpl_quota_show,
|
||||||
|
(void *)projectquota_props);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* .zfs/space/user */
|
||||||
|
const struct file_operations zpl_fops_userspace_file = {
|
||||||
|
.open = zpl_fops_userspace_open,
|
||||||
|
#ifdef HAVE_SEQ_READ_ITER
|
||||||
|
.read_iter = seq_read_iter,
|
||||||
|
#endif
|
||||||
|
.read = seq_read,
|
||||||
|
.llseek = seq_lseek,
|
||||||
|
.release = single_release,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* .zfs/space/group */
|
||||||
|
const struct file_operations zpl_fops_groupspace_file = {
|
||||||
|
.open = zpl_fops_groupspace_open,
|
||||||
|
.read = seq_read,
|
||||||
|
#ifdef HAVE_SEQ_READ_ITER
|
||||||
|
.read_iter = seq_read_iter,
|
||||||
|
#endif
|
||||||
|
.llseek = seq_lseek,
|
||||||
|
.release = single_release,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* .zfs/space/project */
|
||||||
|
const struct file_operations zpl_fops_projectspace_file = {
|
||||||
|
.open = zpl_fops_projectspace_open,
|
||||||
|
.read = seq_read,
|
||||||
|
#ifdef HAVE_SEQ_READ_ITER
|
||||||
|
.read_iter = seq_read_iter,
|
||||||
|
#endif
|
||||||
|
.llseek = seq_lseek,
|
||||||
|
.release = single_release,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* .zfs/quota/user */
|
||||||
|
const struct file_operations zpl_fops_userquota_file = {
|
||||||
|
.open = zpl_fops_userquota_open,
|
||||||
|
#ifdef HAVE_SEQ_READ_ITER
|
||||||
|
.read_iter = seq_read_iter,
|
||||||
|
#endif
|
||||||
|
.read = seq_read,
|
||||||
|
.llseek = seq_lseek,
|
||||||
|
.release = single_release,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* .zfs/quota/group */
|
||||||
|
const struct file_operations zpl_fops_groupquota_file = {
|
||||||
|
.open = zpl_fops_groupquota_open,
|
||||||
|
.read = seq_read,
|
||||||
|
#ifdef HAVE_SEQ_READ_ITER
|
||||||
|
.read_iter = seq_read_iter,
|
||||||
|
#endif
|
||||||
|
.llseek = seq_lseek,
|
||||||
|
.release = single_release,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* .zfs/quota/project */
|
||||||
|
const struct file_operations zpl_fops_projectquota_file = {
|
||||||
|
.open = zpl_fops_projectquota_open,
|
||||||
|
.read = seq_read,
|
||||||
|
#ifdef HAVE_SEQ_READ_ITER
|
||||||
|
.read_iter = seq_read_iter,
|
||||||
|
#endif
|
||||||
|
.llseek = seq_lseek,
|
||||||
|
.release = single_release,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const struct inode_operations zpl_ops_userspace_file = {};
|
||||||
|
const struct inode_operations zpl_ops_groupspace_file = {};
|
||||||
|
const struct inode_operations zpl_ops_projectspace_file = {};
|
||||||
|
const struct inode_operations zpl_ops_userquota_file = {};
|
||||||
|
const struct inode_operations zpl_ops_groupquota_file = {};
|
||||||
|
const struct inode_operations zpl_ops_projectquota_file = {};
|
||||||
|
|
|
@ -211,7 +211,7 @@ tags = ['functional', 'user_namespace']
|
||||||
|
|
||||||
[tests/functional/userquota:Linux]
|
[tests/functional/userquota:Linux]
|
||||||
tests = ['groupspace_001_pos', 'groupspace_002_pos', 'groupspace_003_pos',
|
tests = ['groupspace_001_pos', 'groupspace_002_pos', 'groupspace_003_pos',
|
||||||
'userquota_013_pos', 'userspace_003_pos']
|
'userquota_013_pos', 'userspace_003_pos', 'ctldir_files_001']
|
||||||
tags = ['functional', 'userquota']
|
tags = ['functional', 'userquota']
|
||||||
|
|
||||||
[tests/functional/zvol/zvol_misc:Linux]
|
[tests/functional/zvol/zvol_misc:Linux]
|
||||||
|
|
|
@ -2039,6 +2039,7 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
|
||||||
functional/userquota/userspace_encrypted.ksh \
|
functional/userquota/userspace_encrypted.ksh \
|
||||||
functional/userquota/userspace_send_encrypted.ksh \
|
functional/userquota/userspace_send_encrypted.ksh \
|
||||||
functional/userquota/userspace_encrypted_13709.ksh \
|
functional/userquota/userspace_encrypted_13709.ksh \
|
||||||
|
functional/userquota/ctldir_files_001.ksh \
|
||||||
functional/vdev_zaps/cleanup.ksh \
|
functional/vdev_zaps/cleanup.ksh \
|
||||||
functional/vdev_zaps/setup.ksh \
|
functional/vdev_zaps/setup.ksh \
|
||||||
functional/vdev_zaps/vdev_zaps_001_pos.ksh \
|
functional/vdev_zaps/vdev_zaps_001_pos.ksh \
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
#!/bin/ksh -p
|
||||||
|
#
|
||||||
|
# CDDL HEADER START
|
||||||
|
#
|
||||||
|
# The contents of this file are subject to the terms of the
|
||||||
|
# Common Development and Distribution License (the "License").
|
||||||
|
# You may not use this file except in compliance with the License.
|
||||||
|
#
|
||||||
|
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||||
|
# or https://opensource.org/licenses/CDDL-1.0.
|
||||||
|
# See the License for the specific language governing permissions
|
||||||
|
# and limitations under the License.
|
||||||
|
#
|
||||||
|
# When distributing Covered Code, include this CDDL HEADER in each
|
||||||
|
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||||
|
# If applicable, add the following below this CDDL HEADER, with the
|
||||||
|
# fields enclosed by brackets "[]" replaced with your own identifying
|
||||||
|
# information: Portions Copyright [yyyy] [name of copyright owner]
|
||||||
|
#
|
||||||
|
# CDDL HEADER END
|
||||||
|
#
|
||||||
|
|
||||||
|
. $STF_SUITE/include/libtest.shlib
|
||||||
|
. $STF_SUITE/tests/functional/userquota/userquota_common.kshlib
|
||||||
|
|
||||||
|
#
|
||||||
|
# DESCRIPTION:
|
||||||
|
# Check the zfs space files in .zfs directory
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# STRATEGY:
|
||||||
|
# 1. set zfs userquota to a fs
|
||||||
|
# 2. write some data to the fs with specified user and group
|
||||||
|
# 3. use zfs space files in .zfs to check the result
|
||||||
|
#
|
||||||
|
|
||||||
|
function cleanup
|
||||||
|
{
|
||||||
|
log_must cleanup_quota
|
||||||
|
echo 0 >$SPACEFILES_ENABLED_PARAM || log_fail
|
||||||
|
}
|
||||||
|
|
||||||
|
log_onexit cleanup
|
||||||
|
|
||||||
|
log_assert "Check the .zfs space files"
|
||||||
|
|
||||||
|
typeset userquota=104857600
|
||||||
|
typeset groupquota=524288000
|
||||||
|
|
||||||
|
log_must zfs set userquota@$QUSER1=$userquota $QFS
|
||||||
|
log_must zfs set groupquota@$QGROUP=$groupquota $QFS
|
||||||
|
mkmount_writable $QFS
|
||||||
|
log_must user_run $QUSER1 mkfile 50m $QFILE
|
||||||
|
|
||||||
|
typeset SPACEFILES_ENABLED_PARAM=/sys/module/zfs/parameters/zfs_ctldir_spacefiles
|
||||||
|
echo 1 >$SPACEFILES_ENABLED_PARAM || log_fail
|
||||||
|
typeset mntp=$(get_prop mountpoint $QFS)
|
||||||
|
typeset user_id=$(id -u $QUSER1) || log_fail
|
||||||
|
typeset group_id=$(id -g $QUSER1) || log_fail
|
||||||
|
|
||||||
|
sync_all_pools
|
||||||
|
|
||||||
|
log_must eval "grep \"^$user_id,[[:digit:]]*\" $mntp/.zfs/space/user"
|
||||||
|
log_must eval "grep \"^$user_id,$userquota\" $mntp/.zfs/quota/user"
|
||||||
|
log_must eval "grep \"^$group_id,[[:digit:]]*\" $mntp/.zfs/space/group"
|
||||||
|
log_must eval "grep \"^$group_id,$groupquota\" $mntp/.zfs/quota/group"
|
||||||
|
|
||||||
|
log_pass "Check the .zfs space files"
|
||||||
|
|
Loading…
Reference in New Issue