From: Qian Yingjin Date: Thu, 11 Apr 2019 02:41:38 +0000 (+0800) Subject: LU-10092 pcc: security and permission for non-root user access X-Git-Tag: 2.12.55~20^2~3 X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=commitdiff_plain;h=2102c86e0d0ae735aed9ee8c1c6a77b63eda6037 LU-10092 pcc: security and permission for non-root user access For current PCC, if a file is left on the PCC cache, it may be accessible to other jobs/users who would not normally be able to access it. (That is, they access it directly on the PCC mount via FID as the local PCC mount is basically just a normal local file system.) This patch solves this by restricting access on the PCC side and just depending on the Lustre side permissions for opening a file. So PCC files on the local mount fs are created with some minimal (zero) set of permissions. Then, when accessing a PCC cached file, we do the permission check on the Lustre file, then do not do it on the PCC file. This should render the PCC files inaccessible except to root or via Lustre. Test-Parameters: clientcount=3 testlist=sanity-pcc,sanity-pcc,sanity-pcc Signed-off-by: Qian Yingjin Change-Id: I059fa3e479fe97ef6b65db1cbeb8b7f3ea611880 Reviewed-on: https://review.whamcloud.com/34637 Tested-by: Jenkins Tested-by: Maloo Reviewed-by: Li Xi Reviewed-by: Patrick Farrell Reviewed-by: Oleg Drokin --- diff --git a/lustre/llite/file.c b/lustre/llite/file.c index c0941d6..45248a3 100644 --- a/lustre/llite/file.c +++ b/lustre/llite/file.c @@ -839,6 +839,7 @@ restart: if (rc) GOTO(out_och_free, rc); } + rc = pcc_file_open(inode, file); if (rc) GOTO(out_och_free, rc); @@ -1775,7 +1776,7 @@ static ssize_t ll_file_write_iter(struct kiocb *iocb, struct iov_iter *from) * from PCC cache automatically. */ result = pcc_file_write_iter(iocb, from, &cached); - if (cached && result != -ENOSPC) + if (cached && result != -ENOSPC && result != -EDQUOT) return result; /* NB: we can't do direct IO for tiny writes because they use the page diff --git a/lustre/llite/llite_lib.c b/lustre/llite/llite_lib.c index 7f696c8..0ce8f2e 100644 --- a/lustre/llite/llite_lib.c +++ b/lustre/llite/llite_lib.c @@ -73,12 +73,18 @@ static struct ll_sb_info *ll_init_sbi(void) unsigned long pages; unsigned long lru_page_max; struct sysinfo si; + int rc; int i; + ENTRY; OBD_ALLOC_PTR(sbi); if (sbi == NULL) - RETURN(NULL); + RETURN(ERR_PTR(-ENOMEM)); + + rc = pcc_super_init(&sbi->ll_pcc_super); + if (rc < 0) + GOTO(out_sbi, rc); spin_lock_init(&sbi->ll_lock); mutex_init(&sbi->ll_lco.lco_lock); @@ -92,10 +98,8 @@ static struct ll_sb_info *ll_init_sbi(void) /* initialize ll_cache data */ sbi->ll_cache = cl_cache_init(lru_page_max); - if (sbi->ll_cache == NULL) { - OBD_FREE(sbi, sizeof(*sbi)); - RETURN(NULL); - } + if (sbi->ll_cache == NULL) + GOTO(out_pcc, rc = -ENOMEM); sbi->ll_ra_info.ra_max_pages_per_file = min(pages / 32, SBI_DEFAULT_READAHEAD_MAX); @@ -138,12 +142,16 @@ static struct ll_sb_info *ll_init_sbi(void) sbi->ll_squash.rsi_gid = 0; INIT_LIST_HEAD(&sbi->ll_squash.rsi_nosquash_nids); init_rwsem(&sbi->ll_squash.rsi_sem); - pcc_super_init(&sbi->ll_pcc_super); /* Per-filesystem file heat */ sbi->ll_heat_decay_weight = SBI_DEFAULT_HEAT_DECAY_WEIGHT; sbi->ll_heat_period_second = SBI_DEFAULT_HEAT_PERIOD_SECOND; RETURN(sbi); +out_pcc: + pcc_super_fini(&sbi->ll_pcc_super); +out_sbi: + OBD_FREE_PTR(sbi); + RETURN(ERR_PTR(rc)); } static void ll_free_sbi(struct super_block *sb) @@ -1059,8 +1067,8 @@ int ll_fill_super(struct super_block *sb, struct vfsmount *mnt) /* client additional sb info */ lsi->lsi_llsbi = sbi = ll_init_sbi(); - if (!sbi) - GOTO(out_free_cfg, err = -ENOMEM); + if (IS_ERR(sbi)) + GOTO(out_free_cfg, err = PTR_ERR(sbi)); err = ll_options(lsi->lsi_lmd->lmd_opts, sbi); if (err) @@ -1190,7 +1198,7 @@ void ll_put_super(struct super_block *sb) int next, force = 1, rc = 0; ENTRY; - if (!sbi) + if (IS_ERR(sbi)) GOTO(out_no_sbi, 0); /* Should replace instance_id with something better for ASLR */ diff --git a/lustre/llite/namei.c b/lustre/llite/namei.c index e0dc6c5..0464951 100644 --- a/lustre/llite/namei.c +++ b/lustre/llite/namei.c @@ -842,7 +842,7 @@ static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry, if (rc) GOTO(out, retval = ERR_PTR(rc)); - rc = pcc_inode_create(dataset, &op_data->op_fid2, + rc = pcc_inode_create(parent->i_sb, dataset, &op_data->op_fid2, &pca->pca_dentry); if (rc) GOTO(out, retval = ERR_PTR(rc)); diff --git a/lustre/llite/pcc.c b/lustre/llite/pcc.c index be3a9db..eca1f16 100644 --- a/lustre/llite/pcc.c +++ b/lustre/llite/pcc.c @@ -112,10 +112,20 @@ struct kmem_cache *pcc_inode_slab; -void pcc_super_init(struct pcc_super *super) +int pcc_super_init(struct pcc_super *super) { + struct cred *cred; + + super->pccs_cred = cred = prepare_creds(); + if (!cred) + return -ENOMEM; + + /* Never override disk quota limits or use reserved space */ + cap_lower(cred->cap_effective, CAP_SYS_RESOURCE); spin_lock_init(&super->pccs_lock); INIT_LIST_HEAD(&super->pccs_datasets); + + return 0; } /** @@ -250,7 +260,7 @@ pcc_super_dump(struct pcc_super *super, struct seq_file *m) return 0; } -void pcc_super_fini(struct pcc_super *super) +static void pcc_remove_datasets(struct pcc_super *super) { struct pcc_dataset *dataset, *tmp; @@ -261,6 +271,11 @@ void pcc_super_fini(struct pcc_super *super) } } +void pcc_super_fini(struct pcc_super *super) +{ + pcc_remove_datasets(super); + put_cred(super->pccs_cred); +} static bool pathname_is_valid(const char *pathname) { @@ -361,7 +376,7 @@ int pcc_cmd_handle(char *buffer, unsigned long count, rc = pcc_dataset_del(super, cmd->pccc_pathname); break; case PCC_CLEAR_ALL: - pcc_super_fini(super); + pcc_remove_datasets(super); break; default: rc = -EINVAL; @@ -444,6 +459,11 @@ static int pcc_fid2dataset_path(char *buf, int sz, struct lu_fid *fid) PFID(fid)); } +static inline const struct cred *pcc_super_cred(struct super_block *sb) +{ + return ll_s2sbi(sb)->ll_pcc_super.pccs_cred; +} + void pcc_file_init(struct pcc_file *pccf) { pccf->pccf_file = NULL; @@ -486,11 +506,13 @@ int pcc_file_open(struct inode *inode, struct file *file) dname = &path->dentry->d_name; CDEBUG(D_CACHE, "opening pcc file '%.*s'\n", dname->len, dname->name); + #ifdef HAVE_DENTRY_OPEN_USE_PATH - pcc_file = dentry_open(path, file->f_flags, current_cred()); + pcc_file = dentry_open(path, file->f_flags, + pcc_super_cred(inode->i_sb)); #else - pcc_file = dentry_open(path->dentry, path->mnt, - file->f_flags, current_cred()); + pcc_file = dentry_open(path->dentry, path->mnt, file->f_flags, + pcc_super_cred(inode->i_sb)); #endif if (IS_ERR_OR_NULL(pcc_file)) { rc = pcc_file == NULL ? -EINVAL : PTR_ERR(pcc_file); @@ -716,6 +738,7 @@ int pcc_inode_setattr(struct inode *inode, struct iattr *attr, bool *cached) { int rc; + const struct cred *old_cred; struct iattr attr2 = *attr; struct dentry *pcc_dentry; struct pcc_inode *pcci; @@ -733,11 +756,13 @@ int pcc_inode_setattr(struct inode *inode, struct iattr *attr, attr2.ia_valid = attr->ia_valid & (ATTR_SIZE | ATTR_ATIME | ATTR_ATIME_SET | ATTR_MTIME | ATTR_MTIME_SET | - ATTR_CTIME); + ATTR_CTIME | ATTR_UID | ATTR_GID); pcci = ll_i2pcci(inode); pcc_dentry = pcci->pcci_path.dentry; inode_lock(pcc_dentry->d_inode); + old_cred = override_creds(pcc_super_cred(inode->i_sb)); rc = pcc_dentry->d_inode->i_op->setattr(pcc_dentry, &attr2); + revert_creds(old_cred); inode_unlock(pcc_dentry->d_inode); pcc_io_fini(inode); @@ -747,6 +772,7 @@ int pcc_inode_setattr(struct inode *inode, struct iattr *attr, int pcc_inode_getattr(struct inode *inode, bool *cached) { struct ll_inode_info *lli = ll_i2info(inode); + const struct cred *old_cred; struct kstat stat; s64 atime; s64 mtime; @@ -764,7 +790,9 @@ int pcc_inode_getattr(struct inode *inode, bool *cached) if (!*cached) RETURN(0); + old_cred = override_creds(pcc_super_cred(inode->i_sb)); rc = ll_vfs_getattr(&ll_i2pcci(inode)->pcci_path, &stat); + revert_creds(old_cred); if (rc) GOTO(out, rc); @@ -1215,14 +1243,14 @@ static int __pcc_inode_create(struct pcc_dataset *dataset, pcc_fid2dataset_path(path, MAX_PCC_DATABASE_PATH, fid); - base = pcc_mkdir_p(dataset->pccd_path.dentry, path, 0700); + base = pcc_mkdir_p(dataset->pccd_path.dentry, path, 0); if (IS_ERR(base)) { rc = PTR_ERR(base); GOTO(out, rc); } snprintf(path, MAX_PCC_DATABASE_PATH, DFID_NOBRACE, PFID(fid)); - child = pcc_create(base, path, 0600); + child = pcc_create(base, path, 0); if (IS_ERR(child)) { rc = PTR_ERR(child); GOTO(out_base, rc); @@ -1236,26 +1264,59 @@ out: return rc; } -int pcc_inode_create(struct pcc_dataset *dataset, struct lu_fid *fid, - struct dentry **pcc_dentry) +/* TODO: Set the project ID for PCC copy */ +int pcc_inode_store_ugpid(struct dentry *dentry, kuid_t uid, kgid_t gid) +{ + struct inode *inode = dentry->d_inode; + struct iattr attr; + int rc; + + ENTRY; + + attr.ia_valid = ATTR_UID | ATTR_GID; + attr.ia_uid = uid; + attr.ia_gid = gid; + + inode_lock(inode); + rc = notify_change(dentry, &attr, NULL); + inode_unlock(inode); + + RETURN(rc); +} + +int pcc_inode_create(struct super_block *sb, struct pcc_dataset *dataset, + struct lu_fid *fid, struct dentry **pcc_dentry) { - return __pcc_inode_create(dataset, fid, pcc_dentry); + const struct cred *old_cred; + int rc; + + old_cred = override_creds(pcc_super_cred(sb)); + rc = __pcc_inode_create(dataset, fid, pcc_dentry); + revert_creds(old_cred); + return rc; } int pcc_inode_create_fini(struct pcc_dataset *dataset, struct inode *inode, struct dentry *pcc_dentry) { + const struct cred *old_cred; struct pcc_inode *pcci; int rc = 0; ENTRY; + old_cred = override_creds(pcc_super_cred(inode->i_sb)); pcc_inode_lock(inode); LASSERT(ll_i2pcci(inode) == NULL); OBD_SLAB_ALLOC_PTR_GFP(pcci, pcc_inode_slab, GFP_NOFS); if (pcci == NULL) GOTO(out_unlock, rc = -ENOMEM); + rc = pcc_inode_store_ugpid(pcc_dentry, old_cred->suid, + old_cred->sgid); + if (rc) + GOTO(out_unlock, rc); + pcc_inode_init(pcci, ll_i2info(inode)); pcc_inode_attach_init(dataset, pcci, pcc_dentry, LU_PCC_READWRITE); /* Set the layout generation of newly created file with 0 */ @@ -1273,6 +1334,10 @@ out_unlock: } pcc_inode_unlock(inode); + revert_creds(old_cred); + if (rc && pcci) + OBD_SLAB_FREE_PTR(pcci, pcc_inode_slab); + RETURN(rc); } @@ -1357,6 +1422,7 @@ int pcc_readwrite_attach(struct file *file, struct inode *inode, struct pcc_dataset *dataset; struct ll_inode_info *lli = ll_i2info(inode); struct pcc_inode *pcci; + const struct cred *old_cred; struct dentry *dentry; struct file *pcc_filp; struct path path; @@ -1373,9 +1439,12 @@ int pcc_readwrite_attach(struct file *file, struct inode *inode, if (dataset == NULL) RETURN(-ENOENT); + old_cred = override_creds(pcc_super_cred(inode->i_sb)); rc = __pcc_inode_create(dataset, &lli->lli_fid, &dentry); - if (rc) + if (rc) { + revert_creds(old_cred); GOTO(out_dataset_put, rc); + } path.mnt = dataset->pccd_path.mnt; path.dentry = dentry; @@ -1389,9 +1458,15 @@ int pcc_readwrite_attach(struct file *file, struct inode *inode, #endif if (IS_ERR_OR_NULL(pcc_filp)) { rc = pcc_filp == NULL ? -EINVAL : PTR_ERR(pcc_filp); + revert_creds(old_cred); GOTO(out_dentry, rc); } + rc = pcc_inode_store_ugpid(dentry, old_cred->uid, old_cred->gid); + revert_creds(old_cred); + if (rc) + GOTO(out_fput, rc); + rc = pcc_copy_data(file, pcc_filp); if (rc) GOTO(out_fput, rc); @@ -1416,7 +1491,9 @@ out_dentry: if (rc) { int rc2; + old_cred = override_creds(pcc_super_cred(inode->i_sb)); rc2 = ll_vfs_unlink(dentry->d_parent->d_inode, dentry); + revert_creds(old_cred); if (rc2) CWARN("failed to unlink PCC file, rc = %d\n", rc2); @@ -1432,6 +1509,7 @@ int pcc_readwrite_attach_fini(struct file *file, struct inode *inode, bool attached) { struct ll_inode_info *lli = ll_i2info(inode); + const struct cred *old_cred; struct pcc_inode *pcci; __u32 gen2; @@ -1440,7 +1518,7 @@ int pcc_readwrite_attach_fini(struct file *file, struct inode *inode, pcc_inode_lock(inode); pcci = ll_i2pcci(inode); lli->lli_pcc_state &= ~PCC_STATE_FL_ATTACHING; - if ((rc || lease_broken)) { + if (rc || lease_broken) { if (attached && pcci) pcc_inode_put(pcci); @@ -1466,7 +1544,9 @@ int pcc_readwrite_attach_fini(struct file *file, struct inode *inode, out_put: if (rc) { + old_cred = override_creds(pcc_super_cred(inode->i_sb)); pcc_inode_remove(pcci); + revert_creds(old_cred); pcc_inode_put(pcci); } out_unlock: diff --git a/lustre/llite/pcc.h b/lustre/llite/pcc.h index d79fe19..7e4996e 100644 --- a/lustre/llite/pcc.h +++ b/lustre/llite/pcc.h @@ -52,8 +52,12 @@ struct pcc_dataset { }; struct pcc_super { - spinlock_t pccs_lock; /* Protect pccs_datasets */ - struct list_head pccs_datasets; /* List of datasets */ + /* Protect pccs_datasets */ + spinlock_t pccs_lock; + /* List of datasets */ + struct list_head pccs_datasets; + /* creds of process who forced instantiation of super block */ + const struct cred *pccs_cred; }; struct pcc_inode { @@ -107,7 +111,7 @@ struct pcc_cmd { } u; }; -void pcc_super_init(struct pcc_super *super); +int pcc_super_init(struct pcc_super *super); void pcc_super_fini(struct pcc_super *super); int pcc_cmd_handle(char *buffer, unsigned long count, struct pcc_super *super); @@ -140,10 +144,10 @@ void pcc_vm_close(struct vm_area_struct *vma); int pcc_fault(struct vm_area_struct *mva, struct vm_fault *vmf, bool *cached); int pcc_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf, bool *cached); -int pcc_inode_create(struct pcc_dataset *dataset, struct lu_fid *fid, - struct dentry **pcc_dentry); +int pcc_inode_create(struct super_block *sb, struct pcc_dataset *dataset, + struct lu_fid *fid, struct dentry **pcc_dentry); int pcc_inode_create_fini(struct pcc_dataset *dataset, struct inode *inode, - struct dentry *pcc_dentry); + struct dentry *pcc_dentry); struct pcc_dataset *pcc_dataset_get(struct pcc_super *super, __u32 projid, __u32 archive_id); void pcc_dataset_put(struct pcc_dataset *dataset); diff --git a/lustre/tests/sanity-pcc.sh b/lustre/tests/sanity-pcc.sh index ed2ec57..32c4ec6 100644 --- a/lustre/tests/sanity-pcc.sh +++ b/lustre/tests/sanity-pcc.sh @@ -176,7 +176,7 @@ setup_pcc_mapping() { local param="$2" [ -z "$param" ] && param="$HSM_ARCHIVE_NUMBER\ 100" - cleanup_pcc_mapping $facet + stack_trap "cleanup_pcc_mapping $facet" EXIT do_facet $facet $LCTL pcc add $MOUNT $hsm_root -p $param } @@ -270,8 +270,6 @@ lpcc_rw_test() { # HSM released exists archived status check_hsm_flags $file "0x0000000d" check_file_data $SINGLEAGT $file "attach_detach" - - cleanup_pcc_mapping } test_1a() { @@ -294,6 +292,126 @@ test_1d() { } run_test 1d "Test Project ID with remote access" +test_1e() { + local file=$DIR/$tdir/$tfile + local hsm_root=$(hsm_root) + local -a lpcc_path + + copytool setup -m "$MOUNT" -a "$HSM_ARCHIVE_NUMBER" + setup_pcc_mapping + mkdir $DIR/$tdir || error "mkdir $DIR/$tdir failed" + chmod 777 $DIR/$tdir || error "chmod 777 $DIR/$tdir failed" + + do_facet $SINGLEAGT $RUNAS dd if=/dev/zero of=$file bs=1024 count=1 || + error "failed to dd write to $file" + do_facet $SINGLEAGT $RUNAS $LFS pcc attach -i $HSM_ARCHIVE_NUMBER \ + $file || error "failed to attach file $file" + check_lpcc_state $file "readwrite" + do_facet $SINGLEAGT $RUNAS dd if=$file of=/dev/null bs=1024 count=1 || + error "failed to dd read from $file" + do_facet $SINGLEAGT $RUNAS $TRUNCATE $file 256 || + error "failed to truncate $file" + do_facet $SINGLEAGT $RUNAS $TRUNCATE $file 2048 || + error "failed to truncate $file" + do_facet $SINGLEAGT $RUNAS dd if=/dev/zero of=$file bs=1024 count=1 || + error "failed to dd write to $file" + check_lpcc_state $file "readwrite" + + # non-root user is forbidden to access PCC file directly + lpcc_path=$(lpcc_fid2path $hsm_root $file) + do_facet $SINGLEAGT $RUNAS touch $lpcc_path && + error "non-root user can touch access PCC file $lpcc_path" + do_facet $SINGLEAGT $RUNAS dd if=$lpcc_path of=/dev/null bs=1024 \ + count=1 && error "non-root user can read PCC file $lpcc_path" + do_facet $SINGLEAGT $RUNAS dd if=/dev/zero of=$lpcc_path bs=1024 \ + count=1 && error "non-root user can write PCC file $lpcc_path" + + local perm=$(do_facet $SINGLEAGT stat -c %a $lpcc_path) + + [[ $perm == "0" ]] || error "PCC file permission ($perm) is not zero" + + do_facet $SINGLEAGT $RUNAS $LFS pcc detach $file || + error "failed to detach file $file" + check_lpcc_state $file "none" +} +run_test 1e "Test RW-PCC with non-root user" + +test_1f() { + local project_id=100 + local agt_facet=$SINGLEAGT + local hsm_root=$(hsm_root) + local file=$DIR/$tdir/$tfile + + ! is_project_quota_supported && + skip "project quota is not supported" + + enable_project_quota + copytool setup -m "$MOUNT" -a "$HSM_ARCHIVE_NUMBER" + setup_pcc_mapping + do_facet $SINGLEAGT mkdir -p $DIR/$tdir + chmod 777 $DIR/$tdir || error "chmod 0777 $DIR/$tdir failed" + $LFS project -sp $project_id $DIR/$tdir || + error "failed to set project for $DIR/$tdir" + + do_facet $SINGLEAGT $RUNAS dd if=/dev/zero of=$file bs=1024 count=1 || + error "failed to dd write to $file" + + check_lpcc_state $file "readwrite" + do_facet $SINGLEAGT $RUNAS dd if=$file of=/dev/null bs=1024 count=1 || + error "failed to dd read from $file" + do_facet $SINGLEAGT $RUNAS $TRUNCATE $file 256 || + error "failed to truncate $file" + do_facet $SINGLEAGT $RUNAS $TRUNCATE $file 2048 || + error "failed to truncate $file" + do_facet $SINGLEAGT $RUNAS dd if=/dev/zero of=$file bs=1024 count=1 || + error "failed to dd write from $file" + check_lpcc_state $file "readwrite" + + # non-root user is forbidden to access PCC file directly + lpcc_path=$(lpcc_fid2path $hsm_root $file) + do_facet $SINGLEAGT $RUNAS touch $lpcc_path && + error "non-root user can touch access PCC file $lpcc_path" + do_facet $SINGLEAGT $RUNAS dd if=$lpcc_path of=/dev/null bs=1024 \ + count=1 && error "non-root user can read PCC file $lpcc_path" + do_facet $SINGLEAGT $RUNAS dd if=/dev/zero of=$lpcc_path bs=1024 \ + count=1 && error "non-root user can write PCC file $lpcc_path" + + do_facet $SINGLEAGT $RUNAS $LFS pcc detach $file || + error "failed to detach file $file" + check_lpcc_state $file "none" +} +run_test 1f "Test auto RW-PCC cache with non-root user" + +test_1g() { + local file=$DIR/$tfile + + copytool setup -m "$MOUNT" -a "$HSM_ARCHIVE_NUMBER" + setup_pcc_mapping + + dd if=/dev/zero of=$file bs=1024 count=1 || + error "failed to dd write to $file" + do_facet $SINGLEAGT $RUNAS dd if=/dev/zero of=$file bs=1024 count=1 && + error "non-root user can dd write to $file" + do_facet $SINGLEAGT $LFS pcc attach -i $HSM_ARCHIVE_NUMBER $file || + error "failed to attach file $file" + check_lpcc_state $file "readwrite" + do_facet $SINGLEAGT $RUNAS dd if=/dev/zero of=$file bs=1024 count=1 && + error "non-root user can dd write to $file" + chmod 777 $file || error "chmod 777 $file failed" + do_facet $SINGLEAGT $RUNAS dd if=/dev/zero of=$file bs=1024 count=1 || + error "non-root user cannot write $file with permission (777)" + + do_facet $SINGLEAGT $RUNAS $LFS pcc detach $file && + error "non-root user or non owner can detach $file" + chown $RUNAS_ID $file || error "chown $RUNAS_ID $file failed" + do_facet $SINGLEAGT $RUNAS $LFS pcc detach $file || + error "failed to detach file $file" + check_lpcc_state $file "none" + do_facet $SINGLEAGT $RUNAS dd if=$file of=/dev/null bs=1024 count=1 || + error "non-root user cannot read to $file with permisson (777)" +} +run_test 1g "General permission test for RW-PCC" + # # When a process created a LPCC file and holding the open, # another process on the same client should be able to open the file. @@ -330,7 +448,6 @@ test_2a() { check_hsm_flags $file "0x0000000d" rmultiop_stop $agt_host || error "close $file failed" - cleanup_pcc_mapping } run_test 2a "Test multi open when creating" @@ -387,7 +504,6 @@ test_2b() { "cat $file on remote client failed" do_node $remote_client echo -n "multiopen_data" > $file \ || error "write $file on remote client failed" - cleanup_pcc_mapping } run_test 2b "Test multi remote open when creating" @@ -421,8 +537,6 @@ test_2c() { cat $file2 || error "cat $file on mount $MOUNT2 failed" echo -n "multiopen_data" > $file2 || error "write $file on mount $MOUNT2 failed" - - cleanup_pcc_mapping } run_test 2c "Test multi open on different mount points when creating" @@ -451,8 +565,6 @@ test_3a() { do_facet $SINGLEAGT $LFS pcc detach $file || error "failed to detach file $file" check_lpcc_state $file "none" - - cleanup_pcc_mapping } run_test 3a "Repeat attach/detach operations" @@ -501,10 +613,6 @@ test_3b() { do_facet agt2 $LFS pcc detach $file || error "failed to detach file $file" check_lpcc_state $file "none" agt2 - - for n in $(seq $AGTCOUNT); do - cleanup_pcc_mapping agt$n - done } run_test 3b "Repeat attach/detach operations on multiple clients" @@ -528,8 +636,6 @@ test_4() { $LUSTRE/tests/mmap_sanity -d $DIR/$tdir -m $DIR2/$tdir -e 7 || error "mmap_sanity test failed" sync; sleep 1; sync - - cleanup_pcc_mapping } run_test 4 "Auto cache test for mmap" @@ -559,8 +665,6 @@ test_5() { content=$($MMAP_CAT $file) [[ $content == "attach_mmap_data" ]] || error "mmap cat data mismatch: $content" - - cleanup_pcc_mapping } run_test 5 "Mmap & cat a RW-PCC cached file" @@ -594,8 +698,6 @@ test_6() { content=$(do_facet $SINGLEAGT $MMAP_CAT $file) [[ $content == "nmap_write_data" ]] || error "mmap write data mismatch: $content" - - cleanup_pcc_mapping } run_test 6 "Test mmap write on RW-PCC " @@ -623,8 +725,6 @@ test_7a() { check_lpcc_state $file "none" content=$(do_facet $SINGLEAGT $MMAP_CAT $file) [[ $content == "RQQQQ" ]] || error "data mismatch: $content" - - cleanup_pcc_mapping } run_test 7a "Fake file detached between fault() and page_mkwrite() for RW-PCC" @@ -658,8 +758,6 @@ test_7b() { check_lpcc_state $file "none" content=$(do_facet $SINGLEAGT $MMAP_CAT $file) [[ $content == "RQQQQ" ]] || error "data mismatch: $content" - - cleanup_pcc_mapping } run_test 7b "Test the race with concurrent mkwrite and detach" @@ -684,8 +782,6 @@ test_8() { # IO path. It will restore the HSM released file. check_lpcc_state $file "none" check_file_data $SINGLEAGT $file "ENOSPC_write" - - cleanup_pcc_mapping } run_test 8 "Test fake -ENOSPC tolerance for RW-PCC" @@ -728,12 +824,71 @@ test_9() { error "fail to dd write $file" check_lpcc_state $file "none" check_file_size $SINGLEAGT $file 62914560 - - cleanup_pcc_mapping } run_test 9 "Test -ENOSPC tolerance on loop PCC device for RW-PCC" -test_10() { +test_usrgrp_quota() { + local loopfile="$TMP/$tfile" + local mntpt="/mnt/pcc.$tdir" + local hsm_root="$mntpt/$tdir" + local ug=$1 + local id=$RUNAS_ID + + [[ $ug == "g" ]] && id=$RUNAS_GID + + setup_loopdev $SINGLEAGT $loopfile $mntpt 50 + do_facet $SINGLEAGT quotacheck -c$ug $mntpt || + error "quotacheck -c$ug $mntpt failed" + do_facet $SINGLEAGT quotaon -$ug $mntpt || + error "quotaon -$ug $mntpt failed" + do_facet $SINGLEAGT setquota -$ug $id 0 20480 0 0 $mntpt || + error "setquota -$ug $id on $mntpt failed" + do_facet $SINGLEAGT repquota -${ug}vs $mntpt + + copytool setup -m "$MOUNT" -a "$HSM_ARCHIVE_NUMVER" -h "$hsm_root" + setup_pcc_mapping + do_facet $SINGLEAGT $LCTL pcc list $MOUNT + + mkdir $DIR/$tdir || error "mkdir $DIR/$tdir failed" + + local file1=$DIR/$tdir/${ug}quotaA + local file2=$DIR/$tdir/${ug}quotaB + + dd if=/dev/zero of=$file1 bs=1M count=15 || + error "dd write $file1 failed" + dd if=/dev/zero of=$file2 bs=1M count=15 || + error "dd write $file2 failed" + chown $RUNAS_ID:$RUNAS_GID $file1 || + error "chown $RUNAS_ID:$RUNAS_GID $file1 failed" + chown $RUNAS_ID:$RUNAS_GID $file2 || + error "chown $RUNAS_ID:$RUNAS_GID $file2 failed" + do_facet $SINGLEAGT $RUNAS $LFS pcc attach -i $HSM_ARCHIVE_NUMBER \ + $file1 || error "attach $file1 failed" + do_facet $SINGLEAGT $RUNAS $LFS pcc attach -i $HSM_ARCHIVE_NUMBER \ + $file2 && error "attach $file2 should fail due to quota limit" + check_lpcc_state $file1 "readwrite" + check_lpcc_state $file2 "none" + + do_facet $SINGLEAGT $RUNAS dd if=/dev/zero of=$file1 bs=1M count=30 || + error "dd write $file1 failed" + # -EDQUOT error should be tolerated via fallback to normal Lustre path. + check_lpcc_state $file1 "none" + do_facet $SINGLEAGT $LFS pcc detach $file1 || + error "failed to detach file $file" + rm $file1 $file2 +} + +test_10a() { + test_usrgrp_quota "u" +} +run_test 10a "Test RW-PCC with user quota on loop PCC device" + +test_10b() { + test_usrgrp_quota "g" +} +run_test 10b "Test RW-PCC with group quota on loop PCC device" + +test_11() { local file=$DIR/$tdir/$tfile local hsm_root=$(hsm_root) local file=$DIR/$tdir/$tfile @@ -781,12 +936,10 @@ test_10() { do_facet $SINGLEAGT $LFS pcc attach -i $HSM_ARCHIVE_NUMBER $file && error "attach $file should fail as PCC path is a directory" rm $file || error "rm $file failed" - - cleanup_pcc_mapping } -run_test 10 "Test attach fault injection with simulated PCC file path" +run_test 11 "Test attach fault injection with simulated PCC file path" -test_11() { +test_12() { local file=$DIR/$tfile local pid @@ -809,9 +962,9 @@ test_11() { $LFS hsm_remove $file || error "hsm remove $file failed" wait $pid && error "RW-PCC attach $file should fail" - cleanup_pcc_mapping + return 0 } -run_test 11 "RW-PCC attach races with concurrent HSM remove" +run_test 12 "RW-PCC attach races with concurrent HSM remove" complete $SECONDS check_and_cleanup_lustre