#include <lustre_compat.h>
#include "llite_internal.h"
+#ifdef HAVE_FILEATTR_GET
+#include <linux/fileattr.h>
+#endif
+
struct kmem_cache *pcc_inode_slab;
int pcc_super_init(struct pcc_super *super)
return -EINVAL;
cmd->u.pccc_add.pccc_roid = id;
} else if (strcmp(key, "auto_attach") == 0) {
- rc = kstrtoul(val, 10, &id);
+ rc = kstrtobool(val, &enable);
if (rc)
return rc;
- if (id == 0)
+ if (enable)
+ cmd->u.pccc_add.pccc_flags |= PCC_DATASET_AUTO_ATTACH;
+ else
cmd->u.pccc_add.pccc_flags &= ~PCC_DATASET_AUTO_ATTACH;
} else if (strcmp(key, "open_attach") == 0) {
- rc = kstrtoul(val, 10, &id);
+ rc = kstrtobool(val, &enable);
if (rc)
return rc;
- if (id == 0)
+ if (enable)
+ cmd->u.pccc_add.pccc_flags |= PCC_DATASET_OPEN_ATTACH;
+ else
cmd->u.pccc_add.pccc_flags &= ~PCC_DATASET_OPEN_ATTACH;
} else if (strcmp(key, "io_attach") == 0) {
- rc = kstrtoul(val, 10, &id);
+ rc = kstrtobool(val, &enable);
if (rc)
return rc;
- if (id == 0)
+ if (enable)
+ cmd->u.pccc_add.pccc_flags |= PCC_DATASET_IO_ATTACH;
+ else
cmd->u.pccc_add.pccc_flags &= ~PCC_DATASET_IO_ATTACH;
} else if (strcmp(key, "stat_attach") == 0) {
- rc = kstrtoul(val, 10, &id);
+ rc = kstrtobool(val, &enable);
if (rc)
return rc;
- if (id == 0)
+ if (enable)
+ cmd->u.pccc_add.pccc_flags |= PCC_DATASET_STAT_ATTACH;
+ else
cmd->u.pccc_add.pccc_flags &= ~PCC_DATASET_STAT_ATTACH;
} else if (strcmp(key, "rwpcc") == 0 || strcmp(key, "pccrw") == 0) {
- rc = kstrtoul(val, 10, &id);
+ rc = kstrtobool(val, &enable);
if (rc)
return rc;
- if (id > 0)
+ if (enable)
cmd->u.pccc_add.pccc_flags |= PCC_DATASET_PCCRW;
+ else
+ cmd->u.pccc_add.pccc_flags &= ~PCC_DATASET_PCCRW;
} else if (strcmp(key, "ropcc") == 0 || strcmp(key, "pccro") == 0) {
- rc = kstrtoul(val, 10, &id);
+ rc = kstrtobool(val, &enable);
if (rc)
return rc;
- if (id > 0)
+ if (enable)
cmd->u.pccc_add.pccc_flags |= PCC_DATASET_PCCRO;
+ else
+ cmd->u.pccc_add.pccc_flags &= ~PCC_DATASET_PCCRO;
} else if (strcmp(key, "mmap_conv") == 0) {
rc = kstrtobool(val, &enable);
if (rc)
#endif
else
cmd->u.pccc_add.pccc_flags &= ~PCC_DATASET_MMAP_CONV;
+ } else if (strcmp(key, "proj_quota") == 0) {
+ rc = kstrtobool(val, &enable);
+ if (rc)
+ return rc;
+ if (enable)
+ cmd->u.pccc_add.pccc_flags |= PCC_DATASET_PROJ_QUOTA;
+ else
+ cmd->u.pccc_add.pccc_flags &= ~PCC_DATASET_PROJ_QUOTA;
} else if (strcmp(key, "hsmtool") == 0) {
cmd->u.pccc_add.pccc_hsmtool_type = hsmtool_string2type(val);
if (cmd->u.pccc_add.pccc_hsmtool_type != HSMTOOL_POSIX_V1 &&
switch (cmd->pccc_cmd) {
case PCC_ADD_DATASET:
cmd->u.pccc_add.pccc_hsmtool_type = HSMTOOL_UNKNOWN;
- /* Enable auto attach by default */
- cmd->u.pccc_add.pccc_flags |= PCC_DATASET_AUTO_ATTACH;
+ /* Enable these features by default */
+ cmd->u.pccc_add.pccc_flags |= PCC_DATASET_AUTO_ATTACH |
+ PCC_DATASET_PROJ_QUOTA;
break;
case PCC_DEL_DATASET:
case PCC_CLEAR_ALL:
RETURN(-EINVAL);
}
- if (clt.cl_is_released)
+ if (clt.cl_is_released) {
rc = pcc_try_datasets_attach(inode, iot, clt.cl_layout_gen,
LU_PCC_READWRITE, cached);
- else if (clt.cl_is_rdonly)
+ } else if (clt.cl_is_rdonly) {
+ /* Not try read-only attach for data modification operations */
+ if (iot == PIT_WRITE || iot == PIT_SETATTR)
+ RETURN(0);
+
rc = pcc_try_datasets_attach(inode, iot, clt.cl_layout_gen,
LU_PCC_READONLY, cached);
+ }
RETURN(rc);
}
/*
* Reset uid, gid or size for the PCC copy masked by @valid.
- * TODO: Set the project ID for PCC copy.
*/
static int pcc_inode_reset_iattr(struct dentry *dentry, unsigned int valid,
kuid_t uid, kgid_t gid, loff_t size)
RETURN(rc);
}
+static int __pcc_file_reset_projid(struct file *file, __u32 projid)
+{
+#ifdef HAVE_FILEATTR_GET
+ struct fileattr fa = { .fsx_projid = projid };
+ struct dentry *dentry = file->f_path.dentry;
+ struct inode *inode = d_inode(dentry);
+ int rc;
+
+ /* project quota not supported on backing filesystem */
+ if (!inode->i_op->fileattr_set)
+ return -EOPNOTSUPP;
+
+ rc = inode->i_op->fileattr_set(&init_user_ns, dentry, &fa);
+#else
+ struct fsxattr fsx = { .fsx_projid = projid };
+ mm_segment_t old_fs;
+ int rc;
+
+ /* project quota not supported on backing filesystem */
+ if (!file->f_op->unlocked_ioctl)
+ return -EOPNOTSUPP;
+
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ rc = file->f_op->unlocked_ioctl(file, FS_IOC_FSSETXATTR,
+ (unsigned long)&fsx);
+ set_fs(old_fs);
+#endif
+ return rc;
+}
+
+/* Set the project ID for PCC copy.*/
+static int pcc_file_reset_projid(struct pcc_dataset *dataset, struct file *file,
+ __u32 projid)
+{
+ int rc;
+
+ ENTRY;
+
+ if (!(dataset->pccd_flags & PCC_DATASET_PROJ_QUOTA))
+ RETURN(0);
+
+ rc = __pcc_file_reset_projid(file, projid);
+ if (rc == -EOPNOTSUPP || rc == -ENOTTY) {
+ CWARN("%s: cache fs project quota off, disabling: rc = %d\n",
+ dataset->pccd_pathname, rc);
+ dataset->pccd_flags &= ~PCC_DATASET_PROJ_QUOTA;
+ RETURN(0);
+ }
+
+ RETURN(rc);
+}
+
+static int pcc_inode_reset_projid(struct pcc_dataset *dataset,
+ struct dentry *dentry, __u32 projid)
+{
+ struct path path;
+ struct file *file;
+ int rc;
+
+ ENTRY;
+
+ if (!(dataset->pccd_flags & PCC_DATASET_PROJ_QUOTA))
+ RETURN(0);
+
+ path.mnt = dataset->pccd_path.mnt;
+ path.dentry = dentry;
+ file = dentry_open(&path, O_WRONLY | O_LARGEFILE, current_cred());
+ if (IS_ERR_OR_NULL(file)) {
+ rc = file == NULL ? -EINVAL : PTR_ERR(file);
+ RETURN(rc);
+ }
+
+ rc = pcc_file_reset_projid(dataset, file, projid);
+ fput(file);
+ RETURN(rc);
+}
+
int pcc_inode_create(struct super_block *sb, struct pcc_dataset *dataset,
struct lu_fid *fid, struct dentry **pcc_dentry)
{
if (rc)
GOTO(out_put, rc);
+ rc = pcc_inode_reset_projid(pca->pca_dataset, pcc_dentry,
+ ll_i2info(inode)->lli_projid);
+ if (rc)
+ GOTO(out_put, rc);
+
pcc_inode_attach_set(super, pca->pca_dataset, ll_i2info(inode),
pcci, pcc_dentry, LU_PCC_READWRITE);
if (rc)
GOTO(out_fput, rc);
+ rc = pcc_file_reset_projid(dataset, pcc_filp,
+ ll_i2info(inode)->lli_projid);
+ if (rc)
+ GOTO(out_fput, rc);
+
/*
* When attach a file at file open() time with direct I/O mode, the
* data copy from Lustre OSTs to PCC copy in kernel will report
local size=${4:-50}
do_facet $facet mkdir -p $mntpt || error "mkdir -p $mntpt failed"
- stack_trap "do_facet $facet rm -rf $mntpt" EXIT
+ stack_trap "do_facet $facet rmdir $mntpt" EXIT
do_facet $facet dd if=/dev/zero of=$file bs=1M count=$size
stack_trap "do_facet $facet rm -f $file" EXIT
do_facet $facet mount
stack_trap "umount_loopdev $facet $mntpt" EXIT
}
+setup_loopdev_project() {
+ local facet=$1
+ local file=$2
+ local mntpt=$3
+ local size=${4:-50}
+
+ do_facet $facet mkdir -p $mntpt || error "mkdir -p $mntpt failed"
+ stack_trap "do_facet $facet rmdir $mntpt" EXIT
+ do_facet $facet dd if=/dev/zero of=$file bs=1M count=$size
+ stack_trap "do_facet $facet rm -f $file" EXIT
+ do_facet $facet mkfs.ext4 -O project,quota $file ||
+ error "mkfs.ext4 -O project,quota $file failed"
+ do_facet $facet file $file
+ do_facet $facet mount -t ext4 -o loop,prjquota $file $mntpt ||
+ error "mount -o loop,prjquota $file $mntpt failed"
+ stack_trap "umount_loopdev $facet $mntpt" EXIT
+ do_facet $facet mount | grep $mntpt
+}
+
lpcc_rw_test() {
local restore="$1"
local project="$2"
local hsm_root="$mntpt/$tdir"
local file=$DIR/$tdir/$tfile
- ! is_project_quota_supported &&
- skip "project quota is not supported"
+ is_project_quota_supported || skip "project quota is not supported"
enable_project_quota
setup_loopdev $SINGLEAGT $loopfile $mntpt 50
local hsm_root="$mntpt/$tdir"
local agt_host=$(facet_active_host $SINGLEAGT)
- ! is_project_quota_supported &&
- skip "project quota is not supported" && return
+ is_project_quota_supported || skip "project quota is not supported"
enable_project_quota
setup_loopdev $SINGLEAGT $loopfile $mntpt 50
local hsm_root="$mntpt/$tdir"
local excepts="-e 7 -e 8 -e 9"
- ! is_project_quota_supported &&
- skip "project quota is not supported" && return
+ is_project_quota_supported || skip "project quota is not supported"
enable_project_quota
setup_loopdev $SINGLEAGT $loopfile $mntpt 50
local mntpt="/mnt/pcc.$tdir"
local hsm_root="$mntpt/$tdir"
- ! is_project_quota_supported &&
- echo "Skip project quota is not supported" && return 0
+ is_project_quota_supported || skip "project quota is not supported"
enable_project_quota
setup_loopdev $SINGLEAGT $loopfile $mntpt 50
$LCTL get_param -n mdc.*.connect_flags | grep -q pcc_ro ||
skip "Server does not support PCC-RO"
- ! is_project_quota_supported &&
- skip "project quota is not supported"
+ is_project_quota_supported || skip "project quota is not supported"
enable_project_quota
setup_loopdev $SINGLEAGT $loopfile $mntpt 50
}
run_test 38 "Verify LFS pcc state does not trigger prefetch for auto PCC-RO"
+test_39() {
+ $LCTL get_param -n mdc.*.connect_flags | grep -q pcc_ro ||
+ skip "Server does not support PCC-RO"
+
+ quotaon --help |& grep -q 'project quotas' ||
+ skip "Not support project quota on local filesystem"
+
+ is_project_quota_supported || skip "project quota is not supported"
+
+ enable_project_quota
+
+ local loopfile="$TMP/$tfile"
+ local mntpt="/mnt/pcc.$tdir"
+ local hsm_root="$mntpt/$tdir"
+ local dir=$DIR/$tdir
+ local file=$dir/$tfile
+ local id=100
+
+ setup_loopdev_project $SINGLEAGT $loopfile $mntpt 50
+ do_facet $SINGLEAGT quotaon -Ppv $mntpt
+ do_facet $SINGLEAGT setquota -P $id 0 4096 0 0 $mntpt ||
+ error "setquota -P $id on $mntpt failed"
+ do_facet $SINGLEAGT repquota -Pvs $mntpt
+
+ do_facet $SINGLEAGT mkdir $hsm_root || error "mkdir $hsm_root failed"
+ setup_pcc_mapping $SINGLEAGT \
+ "projid={$id}\ roid=$HSM_ARCHIVE_NUMBER\ proj_quota=1\ pccro=1"
+ do_facet $SINGLEAGT $LCTL pcc list $MOUNT
+
+ do_facet $SINGLEAGT mkdir -p $dir || error "mkdir $dir failed"
+ do_facet $SINGLEAGT dd if=/dev/zero of=$file bs=1M count=2 ||
+ error "Write $file failed"
+ $LFS project -p $id $file || error "failed to set project for $file"
+ $LFS project -d $file
+ do_facet $SINGLEAGT dd if=$file of=/dev/null bs=1M count=2 ||
+ error "Read $file failed"
+ do_facet $SINGLEAGT $LFS pcc state $file
+ check_lpcc_state $file "readonly"
+ do_facet $SINGLEAGT repquota -Pvs $mntpt
+ do_facet $SINGLEAGT dd if=/dev/zero of=$file bs=1M count=5 ||
+ error "Write $file failed"
+ check_lpcc_state $file "none"
+ do_facet $SINGLEAGT dd if=$file of=/dev/null bs=1M count=5 ||
+ error "Read $file failed"
+ do_facet $SINGLEAGT repquota -Pvs $mntpt
+ do_facet $SINGLEAGT $LFS pcc state $file
+ check_lpcc_state $file "none"
+}
+run_test 39 "Test Project quota on loop PCC device"
+
test_41() {
local loopfile="$TMP/$tfile"
local mntpt="/mnt/pcc.$tdir"