dnl # ZFS 0.7.0 feature: SPA_FEATURE_USEROBJ_ACCOUNTING
dnl #
LB_CHECK_COMPILE([if zfs has native dnode accounting supported],
- dmu_objset_userobjspace_upgrade, [
+ dmu_objset_id_quota_upgrade, [
#include <sys/dmu_objset.h>
],[
- dmu_objset_userobjspace_upgrade(NULL);
+ dmu_objset_id_quota_upgrade(NULL);
],[
AC_DEFINE(HAVE_DMU_USEROBJ_ACCOUNTING, 1,
[Have native dnode accounting in ZFS])
struct lu_fid qid_fid; /* FID for per-directory quota */
__u64 qid_uid; /* user identifier */
__u64 qid_gid; /* group identifier */
+ __u64 qid_projid; /* project identifier */
};
/* quotactl management */
struct lquota_acct_rec lqr_acct_rec;
};
+/* flags for inode/block quota accounting */
+enum osd_qid_declare_flags {
+ OSD_QID_INODE = 1 << 0,
+ OSD_QID_BLK = 1 << 1,
+ OSD_QID_FORCE = 1 << 2,
+};
+
/* Index features supported by the global index objects
* Only used for migration purpose and should be removed once on-disk migration
* is no longer needed */
unsigned int oti_declare_ops_used[OSD_OT_MAX];
};
-/* flags for inode/block quota accounting */
-enum osd_qid_declare_flags {
- OSD_QID_INODE = 1 << 0,
- OSD_QID_BLK = 1 << 1,
- OSD_QID_FORCE = 1 << 2,
-};
-
extern int ldiskfs_pdo;
static inline int __osd_xattr_get(struct inode *inode, struct dentry *dentry,
{
struct osd_thread_info *info = osd_oti_get(env);
struct lquota_id_info *qi = &info->oti_qi;
- int rcu, rcg, rcp; /* user & group & project rc */
- int force = osd_qid_declare_flags & OSD_QID_FORCE;
+ int rcu, rcg, rcp = 0; /* user & group & project rc */
+ bool force = !!(osd_qid_declare_flags & OSD_QID_FORCE);
ENTRY;
/* let's start with user quota */
if (force && (rcg == -EDQUOT || rcg == -EINPROGRESS))
/* as before, ignore EDQUOT & EINPROGRESS for root */
rcg = 0;
+
+#ifdef HAVE_PROJECT_QUOTA
if (rcg && (rcg != -EDQUOT || flags == NULL))
RETURN(rcg);
/* and now project quota */
- qi->lqi_id.qid_gid = projid;
- qi->lqi_type = PRJQUOTA;
+ qi->lqi_id.qid_projid = projid;
+ qi->lqi_type = PRJQUOTA;
rcp = osd_declare_qid(env, oh, qi, obj, true, flags);
if (force && (rcp == -EDQUOT || rcp == -EINPROGRESS))
/* as before, ignore EDQUOT & EINPROGRESS for root */
rcp = 0;
+#endif
- if (rcu)
- RETURN(rcu);
- if (rcg)
- RETURN(rcg);
- if (rcp)
- RETURN(rcp);
-
- RETURN(0);
+ RETURN(rcu ? rcu : (rcg ? rcg : rcp));
}
if (rc)
GOTO(err, rc);
+#ifdef ZFS_PROJINHERIT
+ if (dmu_objset_projectquota_enabled(o->od_os)) {
+ rc = __osd_obj2dnode(o->od_os, DMU_PROJECTUSED_OBJECT,
+ &o->od_projectused_dn);
+ if (rc && rc != -ENOENT)
+ GOTO(err, rc);
+ }
+#endif
+
/* 1. initialize oi before any file create or file open */
rc = osd_oi_init(env, o);
if (rc)
o->od_groupused_dn = NULL;
}
+#ifdef ZFS_PROJINHERIT
+ if (o->od_projectused_dn) {
+ osd_dnode_rele(o->od_projectused_dn);
+ o->od_projectused_dn = NULL;
+ }
+#endif
+
if (o->od_os != NULL) {
if (!o->od_dt_dev.dd_rdonly)
/* force a txg sync to get all commit callbacks */
uint64_t mode;
uint64_t gid;
uint64_t uid;
+#ifdef ZFS_PROJINHERIT
+ uint64_t projid;
+#endif
uint64_t nlink;
uint64_t rdev;
uint64_t flags;
oic_remote:1; /* FID isn't local */
};
-/* max.number of regular attrubites the callers may ask for */
-#define OSD_MAX_IN_BULK 13
+/* max.number of regular attributes the callers may ask for */
+# define OSD_MAX_IN_BULK (sizeof(struct osa_attr)/sizeof(uint64_t))
struct osd_thread_info {
const struct lu_env *oti_env;
int od_connects;
struct lu_site od_site;
- dnode_t *od_groupused_dn;
- dnode_t *od_userused_dn;
+ dnode_t *od_groupused_dn;
+ dnode_t *od_userused_dn;
+#ifdef ZFS_PROJINHERIT
+ dnode_t *od_projectused_dn;
+#endif
/* quota slave instance */
struct qsd_instance *od_quota_slave;
__u32 oo_destroyed:1,
oo_late_xattr:1,
+#ifdef ZFS_PROJINHERIT
+ oo_with_projid:1,
+#endif
oo_late_attr_set:1;
/* the i_flags in LMA */
extern struct lu_device_operations osd_lu_ops;
extern struct dt_index_operations osd_dir_ops;
int osd_declare_quota(const struct lu_env *env, struct osd_device *osd,
- qid_t uid, qid_t gid, long long space,
- struct osd_thandle *oh, bool is_blk, int *flags,
- bool force);
+ qid_t uid, qid_t gid, qid_t projid, long long space,
+ struct osd_thandle *oh, int *flags,
+ enum osd_qid_declare_flags osd_qid_declare_flags);
uint64_t osd_objs_count_estimate(uint64_t refdbytes, uint64_t usedobjs,
uint64_t nrblocks, uint64_t est_maxblockshift);
int osd_unlinked_object_free(const struct lu_env *env, struct osd_device *osd,
int __osd_object_create(const struct lu_env *env, struct osd_object *obj,
dnode_t **dnp, dmu_tx_t *tx, struct lu_attr *la);
int __osd_attr_init(const struct lu_env *env, struct osd_device *osd,
- sa_handle_t *sa_hdl, dmu_tx_t *tx,
+ struct osd_object *obj, sa_handle_t *sa_hdl, dmu_tx_t *tx,
struct lu_attr *la, uint64_t parent, nvlist_t *);
/* osd_oi.c */
{
return (flags & LUSTRE_APPEND_FL ? ZFS_APPENDONLY : 0) |
(flags & LUSTRE_NODUMP_FL ? ZFS_NODUMP : 0) |
+#ifdef ZFS_PROJINHERIT
+ (flags & LUSTRE_PROJINHERIT_FL ? ZFS_PROJINHERIT : 0) |
+#endif
(flags & LUSTRE_IMMUTABLE_FL ? ZFS_IMMUTABLE : 0);
}
{
return (flags & ZFS_APPENDONLY ? LUSTRE_APPEND_FL : 0) |
(flags & ZFS_NODUMP ? LUSTRE_NODUMP_FL : 0) |
+#ifdef ZFS_PROJINHERIT
+ (flags & ZFS_PROJINHERIT ? LUSTRE_PROJINHERIT_FL : 0) |
+#endif
(flags & ZFS_IMMUTABLE ? LUSTRE_IMMUTABLE_FL : 0);
}
#include <lustre_disk.h>
#include <lustre_fid.h>
#include <lustre/lustre_idl.h> /* LLOG_MIN_CHUNK_SIZE definition */
+#include <lustre_quota.h>
#include "osd_internal.h"
* as llog or last_rcvd files. We needn't enforce quota on those
* objects, so always set the lqi_space as 0. */
RETURN(osd_declare_quota(env, osd, obj->oo_attr.la_uid,
- obj->oo_attr.la_gid, 0, oh, true, NULL,
- false));
+ obj->oo_attr.la_gid, obj->oo_attr.la_projid,
+ 0, oh, NULL, OSD_QID_BLK));
}
static ssize_t osd_write(const struct lu_env *env, struct dt_object *dt,
uint32_t size = 0;
uint32_t blksz = obj->oo_dn->dn_datablksz;
int i, rc, flags = 0;
- bool ignore_quota = false, synced = false;
+ bool synced = false;
long long space = 0;
struct page *last_page = NULL;
unsigned long discont_pages = 0;
+ enum osd_qid_declare_flags declare_flags = OSD_QID_BLK;
ENTRY;
LASSERT(dt_object_exists(dt));
if ((lnb[i].lnb_flags & OBD_BRW_NOQUOTA) ||
(lnb[i].lnb_flags & (OBD_BRW_FROM_GRANT | OBD_BRW_SYNC)) ==
OBD_BRW_FROM_GRANT)
- ignore_quota = true;
+ declare_flags |= OSD_QID_FORCE;
+
if (size == 0) {
/* first valid lnb */
offset = lnb[i].lnb_file_offset;
retry:
/* acquire quota space if needed */
rc = osd_declare_quota(env, osd, obj->oo_attr.la_uid,
- obj->oo_attr.la_gid, space, oh, true, &flags,
- ignore_quota);
+ obj->oo_attr.la_gid, obj->oo_attr.la_projid,
+ space, oh, &flags, declare_flags);
if (!synced && rc == -EDQUOT && (flags & QUOTA_FL_SYNC) != 0) {
dt_sync(env, th->th_dev);
lnb[0].lnb_flags |= OBD_BRW_OVER_USRQUOTA;
if (flags & QUOTA_FL_OVER_GRPQUOTA)
lnb[0].lnb_flags |= OBD_BRW_OVER_GRPQUOTA;
+#ifdef ZFS_PROJINHERIT
+ if (flags & QUOTA_FL_OVER_PRJQUOTA)
+ lnb[0].lnb_flags |= OBD_BRW_OVER_PRJQUOTA;
+#endif
RETURN(rc);
}
}
RETURN(osd_declare_quota(env, osd, obj->oo_attr.la_uid,
- obj->oo_attr.la_gid, 0, oh, true, NULL,
- false));
+ obj->oo_attr.la_gid, obj->oo_attr.la_projid,
+ 0, oh, NULL, OSD_QID_BLK));
}
static int osd_ladvise(const struct lu_env *env, struct dt_object *dt,
if (rc)
GOTO(out_sa, rc);
+#ifdef ZFS_PROJINHERIT
+ if (o->od_projectused_dn && osa->flags & ZFS_PROJID) {
+ rc = -sa_lookup(obj->oo_sa_hdl, SA_ZPL_PROJID(o),
+ &osa->projid, 8);
+ if (rc)
+ GOTO(out_sa, rc);
+
+ la->la_projid = osa->projid;
+ la->la_valid |= LA_PROJID;
+ obj->oo_with_projid = 1;
+ } else {
+ la->la_projid = ZFS_DEFAULT_PROJID;
+ la->la_valid &= ~LA_PROJID;
+ }
+#else
+ la->la_projid = 0;
+ la->la_valid &= ~LA_PROJID;
+#endif
+
la->la_atime = osa->atime[0];
la->la_mtime = osa->mtime[0];
la->la_ctime = osa->ctime[0];
case ACCT_GROUP_OID:
dn = osd->od_groupused_dn;
break;
+#ifdef ZFS_PROJINHERIT
+ case ACCT_PROJECT_OID:
+ dn = osd->od_projectused_dn;
+ break;
+#endif
default:
break;
}
/* one less inode */
rc = osd_declare_quota(env, osd, obj->oo_attr.la_uid,
- obj->oo_attr.la_gid, -1, oh, false, NULL, false);
+ obj->oo_attr.la_gid, obj->oo_attr.la_projid,
+ -1, oh, NULL, OSD_QID_INODE);
if (rc)
RETURN(rc);
/* data to be truncated */
rc = osd_declare_quota(env, osd, obj->oo_attr.la_uid,
- obj->oo_attr.la_gid, 0, oh, true, NULL, false);
+ obj->oo_attr.la_gid, obj->oo_attr.la_projid,
+ 0, oh, NULL, OSD_QID_BLK);
if (rc)
RETURN(rc);
* anything else */
}
- if (attr && (attr->la_valid & (LA_UID | LA_GID))) {
+ if (attr && (attr->la_valid & (LA_UID | LA_GID | LA_PROJID))) {
sa_object_size(obj->oo_sa_hdl, &blksize, &bspace);
bspace = toqb(bspace * blksize);
}
GOTO(out, rc);
}
}
-
+#ifdef ZFS_PROJINHERIT
+ if (attr && attr->la_valid & LA_PROJID) {
+ if (!osd->od_projectused_dn)
+ GOTO(out, rc = -EOPNOTSUPP);
+
+ /* Usually, if project quota is upgradable for the device,
+ * then the upgrade will be done before or when mount the
+ * device. So when we come here, this project should have
+ * project ID attribute already (that is zero by default).
+ * Otherwise, there was something wrong during the former
+ * upgrade, let's return failure to report that.
+ *
+ * Please note that, different from other attributes, you
+ * can NOT simply set the project ID attribute under such
+ * case, because adding (NOT change) project ID attribute
+ * needs to change the object's attribute layout to match
+ * zfs backend quota accounting requirement. */
+ if (unlikely(!obj->oo_with_projid))
+ GOTO(out, rc = -ENXIO);
+
+ /* quota enforcement for project */
+ if (attr->la_projid != obj->oo_attr.la_projid) {
+ rc = qsd_transfer(env, osd->od_quota_slave,
+ &oh->ot_quota_trans, PRJQUOTA,
+ obj->oo_attr.la_projid,
+ attr->la_projid, bspace,
+ &info->oti_qi);
+ if (rc)
+ GOTO(out, rc);
+ }
+ }
+#endif
out:
up_read(&obj->oo_guard);
RETURN(rc);
if (rc < 0) {
CWARN("%s: failed to set LMA flags: rc = %d\n",
osd->od_svname, rc);
- RETURN(rc);
+ GOTO(out, rc);
}
}
}
write_lock(&obj->oo_attr_lock);
cnt = 0;
+
+ if (valid & LA_PROJID) {
+#ifdef ZFS_PROJINHERIT
+ /* osd_declare_attr_set() must be called firstly.
+ * If osd::od_projectused_dn is not set, then we
+ * can not arrive at here. */
+ LASSERT(osd->od_projectused_dn);
+ LASSERT(obj->oo_with_projid);
+
+ osa->projid = obj->oo_attr.la_projid = la->la_projid;
+ SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_PROJID(osd), NULL,
+ &osa->projid, 8);
+#else
+ valid &= ~LA_PROJID;
+#endif
+ }
+
if (valid & LA_ATIME) {
osa->atime[0] = obj->oo_attr.la_atime = la->la_atime;
SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_ATIME(osd), NULL,
/* many flags are not supported by zfs, so ensure a good cached
* copy */
obj->oo_attr.la_flags = attrs_zfs2fs(osa->flags);
+#ifdef ZFS_PROJINHERIT
+ if (obj->oo_with_projid)
+ osa->flags |= ZFS_PROJID;
+#endif
SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_FLAGS(osd), NULL,
&osa->flags, 8);
}
/* will help to find FID->ino mapping at dt_insert() */
osd_idc_find_and_init(env, osd, obj);
- rc = osd_declare_quota(env, osd, attr->la_uid, attr->la_gid, 1, oh,
- false, NULL, false);
+ rc = osd_declare_quota(env, osd, attr->la_uid, attr->la_gid,
+ attr->la_projid, 1, oh, NULL, OSD_QID_INODE);
RETURN(rc);
}
int __osd_attr_init(const struct lu_env *env, struct osd_device *osd,
- sa_handle_t *sa_hdl, dmu_tx_t *tx,
+ struct osd_object *obj, sa_handle_t *sa_hdl, dmu_tx_t *tx,
struct lu_attr *la, uint64_t parent,
nvlist_t *xattr)
{
osa->gid = la->la_gid;
osa->rdev = la->la_rdev;
osa->nlink = la->la_nlink;
- osa->flags = attrs_fs2zfs(la->la_flags);
+ if (la->la_valid & LA_FLAGS)
+ osa->flags = attrs_fs2zfs(la->la_flags);
+ else
+ osa->flags = 0;
osa->size = la->la_size;
+#ifdef ZFS_PROJINHERIT
+ if (osd->od_projectused_dn) {
+ if (la->la_valid & LA_PROJID)
+ osa->projid = la->la_projid;
+ else
+ osa->projid = ZFS_DEFAULT_PROJID;
+ osa->flags |= ZFS_PROJID;
+ if (obj)
+ obj->oo_with_projid = 1;
+ } else {
+ osa->flags &= ~ZFS_PROJID;
+ }
+#endif
/*
* we need to create all SA below upon object create.
*
* XXX The attribute order matters since the accounting callback relies
* on static offsets (i.e. SA_*_OFFSET, see zfs_space_delta_cb()) to
- * look up the UID/GID attributes. Moreover, the callback does not seem
- * to support the spill block.
+ * look up the UID/GID/PROJID attributes. Moreover, the callback does
+ * not seem to support the spill block.
* We define attributes in the same order as SA_*_OFFSET in order to
* work around the problem. See ORI-610.
*/
SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_CTIME(osd), NULL, osa->ctime, 16);
SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_CRTIME(osd), NULL, crtime, 16);
SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_LINKS(osd), NULL, &osa->nlink, 8);
+#ifdef ZFS_PROJINHERIT
+ if (osd->od_projectused_dn)
+ SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_PROJID(osd), NULL,
+ &osa->projid, 8);
+#endif
SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_RDEV(osd), NULL, &osa->rdev, 8);
LASSERT(cnt <= ARRAY_SIZE(osd_oti_get(env)->oti_attr_bulk));
obj->oo_attr = *attr;
obj->oo_attr.la_valid |= LA_SIZE | LA_NLINK | LA_TYPE;
+#ifdef ZFS_PROJINHERIT
+ if (osd->od_projectused_dn) {
+ if (!(obj->oo_attr.la_valid & LA_PROJID))
+ obj->oo_attr.la_projid = ZFS_DEFAULT_PROJID;
+ obj->oo_with_projid = 1;
+ }
+#endif
+
dn = osd_create_type_f(dof->dof_type)(env, obj, &obj->oo_attr, oh);
if (IS_ERR(dn)) {
rc = PTR_ERR(dn);
rc = -sa_handle_get(o->od_os, oid, NULL, SA_HDL_PRIVATE, &sa_hdl);
if (rc)
goto commit;
+ memset(la, 0, sizeof(*la));
la->la_valid = LA_MODE | LA_UID | LA_GID;
la->la_mode = S_IFDIR | S_IRUGO | S_IWUSR | S_IXUGO;
- la->la_uid = la->la_gid = 0;
- rc = __osd_attr_init(env, o, sa_hdl, tx, la, parent, NULL);
+ rc = __osd_attr_init(env, o, NULL, sa_hdl, tx, la, parent, NULL);
sa_handle_destroy(sa_hdl);
if (rc)
goto commit;
/**
* Helper function to estimate the number of inodes in use for the given
- * uid/gid from the block usage
+ * uid/gid/projid from the block usage
*/
static uint64_t osd_objset_user_iused(struct osd_device *osd, uint64_t uidbytes)
{
*/
/**
- * Return space usage consumed by a given uid or gid.
+ * Return space usage consumed by a given uid or gid or projid.
* Block usage is accurrate since it is maintained by DMU itself.
* However, DMU does not provide inode accounting, so the #inodes in use
* is estimated from the block usage and statfs information.
rec->bspace = rec->ispace = 0;
- /* convert the 64-bit uid/gid into a string */
+ /* convert the 64-bit uid/gid/projid into a string */
snprintf(buf, buflen, "%llx", *((__u64 *)dtkey));
if (unlikely(!dn)) {
CDEBUG(D_QUOTA, "%s: miss accounting obj for %s\n",
rc = osd_zap_lookup(osd, dn->dn_object, dn, buf, sizeof(uint64_t), 1,
&rec->bspace);
if (rc == -ENOENT) {
- /* user/group has not created anything yet */
+ /* user/group/project has not created anything yet */
CDEBUG(D_QUOTA, "%s: id %s not found in DMU accounting ZAP\n",
osd->od_svname, buf);
/* -ENOENT is normal case, convert it as 1. */
* move to the first valid record.
*
* \param di - osd iterator
- * \param key - uid or gid
+ * \param key - uid or gid or projid
*
* \retval +ve - di points to exact matched key
* \retval 0 - di points to the first valid record
* \param osd - is the osd_device
* \param uid - user id of the inode
* \param gid - group id of the inode
+ * \param projid - project id of the inode
* \param space - how many blocks/inodes will be consumed/released
* \param oh - osd transaction handle
- * \param is_blk - block quota or inode quota?
* \param flags - if the operation is write, return no user quota, no
* group quota, or sync commit flags to the caller
- * \param force - set to 1 when changes are performed by root user and thus
- * can't failed with EDQUOT
+ * \param osd_qid_declare_flags - indicate this is a inode/block accounting
+ * and whether changes are performed by root user
*
* \retval 0 - success
* \retval -ve - failure
*/
int osd_declare_quota(const struct lu_env *env, struct osd_device *osd,
- qid_t uid, qid_t gid, long long space,
- struct osd_thandle *oh, bool is_blk, int *flags,
- bool force)
+ qid_t uid, qid_t gid, qid_t projid, long long space,
+ struct osd_thandle *oh, int *flags,
+ enum osd_qid_declare_flags osd_qid_declare_flags)
{
- struct osd_thread_info *info = osd_oti_get(env);
- struct lquota_id_info *qi = &info->oti_qi;
- struct qsd_instance *qsd = osd->od_quota_slave;
- int rcu, rcg; /* user & group rc */
+ struct osd_thread_info *info = osd_oti_get(env);
+ struct lquota_id_info *qi = &info->oti_qi;
+ struct qsd_instance *qsd = osd->od_quota_slave;
+ int rcu, rcg, rcp = 0; /* user & group & project rc */
+ bool force = !!(osd_qid_declare_flags & OSD_QID_FORCE);
ENTRY;
if (unlikely(qsd == NULL))
qi->lqi_id.qid_uid = uid;
qi->lqi_type = USRQUOTA;
qi->lqi_space = space;
- qi->lqi_is_blk = is_blk;
+ qi->lqi_is_blk = !!(osd_qid_declare_flags & OSD_QID_BLK);
rcu = qsd_op_begin(env, qsd, &oh->ot_quota_trans, qi, flags);
-
if (force && (rcu == -EDQUOT || rcu == -EINPROGRESS))
/* ignore EDQUOT & EINPROGRESS when changes are done by root */
rcu = 0;
qi->lqi_id.qid_gid = gid;
qi->lqi_type = GRPQUOTA;
rcg = qsd_op_begin(env, qsd, &oh->ot_quota_trans, qi, flags);
-
if (force && (rcg == -EDQUOT || rcg == -EINPROGRESS))
/* as before, ignore EDQUOT & EINPROGRESS for root */
rcg = 0;
- RETURN(rcu ? rcu : rcg);
+#ifdef ZFS_PROJINHERIT
+ if (rcg && (rcg != -EDQUOT || flags == NULL))
+ RETURN(rcg);
+
+ /* for project quota */
+ if (osd->od_projectused_dn) {
+ qi->lqi_id.qid_projid = projid;
+ qi->lqi_type = PRJQUOTA;
+ rcp = qsd_op_begin(env, qsd, &oh->ot_quota_trans, qi, flags);
+ if (force && (rcp == -EDQUOT || rcp == -EINPROGRESS))
+ rcp = 0;
+ }
+#endif
+
+ RETURN(rcu ? rcu : (rcg ? rcg : rcp));
}
osa->nlink = obj->oo_attr.la_nlink;
osa->flags = attrs_fs2zfs(obj->oo_attr.la_flags);
osa->size = obj->oo_attr.la_size;
+#ifdef ZFS_PROJINHERIT
+ if (osd->od_projectused_dn) {
+ if (obj->oo_attr.la_valid & LA_PROJID)
+ osa->projid = obj->oo_attr.la_projid;
+ else
+ osa->projid = ZFS_DEFAULT_PROJID;
+ osa->flags |= ZFS_PROJID;
+ obj->oo_with_projid = 1;
+ }
+#endif
cnt = 0;
SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_MODE(osd), NULL, &osa->mode, 8);
SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_GEN(osd), NULL, &gen, 8);
SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_UID(osd), NULL, &osa->uid, 8);
SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_GID(osd), NULL, &osa->gid, 8);
+ SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_PARENT(osd), NULL,
+ &obj->oo_parent, 8);
SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_FLAGS(osd), NULL, &osa->flags, 8);
SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_ATIME(osd), NULL, osa->atime, 16);
SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_MTIME(osd), NULL, osa->mtime, 16);
SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_CTIME(osd), NULL, osa->ctime, 16);
SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_CRTIME(osd), NULL, crtime, 16);
SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_LINKS(osd), NULL, &osa->nlink, 8);
+#ifdef ZFS_PROJINHERIT
+ if (osd->od_projectused_dn)
+ SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_PROJID(osd), NULL,
+ &osa->projid, 8);
+#endif
SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_RDEV(osd), NULL, &osa->rdev, 8);
- SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_PARENT(osd), NULL,
- &obj->oo_parent, 8);
LASSERT(cnt <= ARRAY_SIZE(osd_oti_get(env)->oti_attr_bulk));
/* Update the SA for additions, modifications, and removals. */
check_and_setup_lustre
is_project_quota_supported() {
+ lsattr -dp > /dev/null 2>&1 || return 1
+
[ "$(facet_fstype $SINGLEMDS)" == "ldiskfs" ] &&
- [ $(lustre_version_code $SINGLEMDS) -gt $(version_code 2.9.55) ] &&
- egrep -q "7." /etc/redhat-release &&
- man chattr | grep project >&/dev/null
+ [ $(lustre_version_code $SINGLEMDS) -gt \
+ $(version_code 2.9.55) ] &&
+ egrep -q "7." /etc/redhat-release && return 0
+
+ if [ "$(facet_fstype $SINGLEMDS)" == "zfs" ]; then
+ [ $(lustre_version_code $SINGLEMDS) -le \
+ $(version_code 2.10.53) ] && return 1
+
+ $ZPOOL upgrade -v | grep project_quota && return 0
+ fi
+
+ return 1
}
SHOW_QUOTA_USER="$LFS quota -v -u $TSTUSR $DIR"
local spec
local uuid
+ sync_all_data > /dev/null 2>&1 || true
+
[ "$#" != 4 ] && error "getquota: wrong number of arguments: $#"
[ "$1" != "-u" -a "$1" != "-g" -a "$1" != "-p" ] &&
error "getquota: wrong u/g/p specifier $1 passed"
disable_project_quota() {
is_project_quota_supported || return 0
+ [ "$(facet_fstype $SINGLEMDS)" != "ldiskfs" ] && return 0
stopall || error "failed to stopall (1)"
for num in $(seq $MDSCOUNT); do
}
enable_project_quota() {
- is_project_quota_supported || return 0
+ is_project_quota_supported || return 0
+ [ "$(facet_fstype $SINGLEMDS)" != "ldiskfs" ] && return 0
stopall || error "failed to stopall (1)"
for num in $(seq $MDSCOUNT); do
# test for Project
log "--------------------------------------"
- log "project quota (block hardlimit:$LIMIT mb)"
+ log "Project quota (block hardlimit:$LIMIT mb)"
$LFS setquota -p $TSTPRJID -b 0 -B ${LIMIT}M -i 0 -I 0 $DIR ||
error "set project quota failed"
cancel_lru_locks osc
sync; sync_all_data || true
$RUNAS $DD of=$TESTFILE count=10 seek=$LIMIT && quota_error p \
- $TSTPRJID "project write success, but expect edquot"
+ $TSTPRJID "project write success, but expect EDQUOT"
# cleanup
cleanup_quota_test
USED=$(getquota -g $TSTUSR global curspace)
[ $USED -ne 0 ] && error "Used block($USED) for group $TSTUSR isn't 0."
if is_project_quota_supported; then
+ USED=$(getquota -p $TSTPRJID global curinodes)
+ [ $USED -ne 0 ] &&
+ error "Used inode($USED) for project $TSTPRJID isn't 0."
USED=$(getquota -p $TSTPRJID global curspace)
[ $USED -ne 0 ] &&
error "Used block($USED) for project $TSTPRJID isn't 0."
USED=$(getquota -g $TSTID global curinodes)
[ $USED -eq 0 ] || error "Used inodes for group $TSTID isn't 0. $USED"
if is_project_quota_supported; then
+ USED=$(getquota -p $TSTPRJID global curspace)
+ [ $USED -eq 0 ] ||
+ error "Used space for project $TSTPRJID isn't 0. $USED"
USED=$(getquota -p $TSTPRJID global curinodes)
[ $USED -eq 0 ] ||
error "Used inodes for project $TSTPRJID isn't 0. $USED"
mkdir $dir && change_project -dp 1 $dir && change_project +P $dir
local used=$(getquota -p 1 global curinodes)
- [ $used != "1" ] && error "expected 1 got $used"
+ [ $used != "1" ] && error "expected 1 got $used"
touch $dir/1
touch $dir/2
cp $dir/2 $dir/3
used=$(getquota -p 1 global curinodes)
- [ $used != "4" ] && error "expected 4 got $used"
+ [ $used != "4" ] && error "expected 4 got $used"
$DD if=/dev/zero of=$DIR/$tdir/6 bs=1M count=1
#try cp to dir
cp $DIR/$tdir/6 $dir/6
used=$(getquota -p 1 global curinodes)
- [ $used != "5" ] && error "expected 5 got $used"
+ [ $used != "5" ] && error "expected 5 got $used"
#try mv to dir
mv $DIR/$tdir/6 $dir/7
used=$(getquota -p 1 global curinodes)
- [ $used != "6" ] && error "expected 6 got $used"
+ [ $used != "6" ] && error "expected 6 got $used"
rm -rf $dir
cleanup_quota_test