bool cl_is_composite;
/** Whether layout is a HSM released one */
bool cl_is_released;
+ /** Whether layout is a readonly one */
+ bool cl_is_rdonly;
};
enum coo_inode_opc {
*/
ci_need_write_intent:1,
/**
+ * File is in PCC-RO state, need MDS intervention to complete
+ * a data modifying operation.
+ */
+ ci_need_pccro_clear:1,
+ /**
* Check if layout changed after the IO finishes. Mainly for HSM
* requirement. If IO occurs to openning files, it doesn't need to
* verify layout because HSM won't release openning files.
rc = ll_heat_set(inode, flags);
RETURN(rc);
}
+ case LL_IOC_PCC_ATTACH: {
+ struct lu_pcc_attach *attach;
+
+ if (!S_ISREG(inode->i_mode))
+ RETURN(-EINVAL);
+
+ if (!inode_owner_or_capable(&init_user_ns, inode))
+ RETURN(-EPERM);
+
+ OBD_ALLOC_PTR(attach);
+ if (attach == NULL)
+ RETURN(-ENOMEM);
+
+ if (copy_from_user(attach,
+ (const struct lu_pcc_attach __user *)arg,
+ sizeof(*attach)))
+ GOTO(out_pcc, rc = -EFAULT);
+
+ rc = pcc_ioctl_attach(file, inode, attach);
+out_pcc:
+ OBD_FREE_PTR(attach);
+ RETURN(rc);
+ }
case LL_IOC_PCC_DETACH: {
struct lu_pcc_detach *detach;
*/
static struct cl_io *
ll_fault_io_init(struct lu_env *env, struct vm_area_struct *vma,
- pgoff_t index, bool mkwrite)
+ pgoff_t index, bool mkwrite)
{
struct file *file = vma->vm_file;
struct inode *inode = file_inode(file);
return -EINVAL;
/*
* By default, a PCC backend can provide caching service for
- * both RW-PCC and RO-PCC.
+ * both PCC-RW and PCC-RO.
*/
if ((cmd->u.pccc_add.pccc_flags & PCC_DATASET_PCC_ALL) == 0)
cmd->u.pccc_add.pccc_flags |= PCC_DATASET_PCC_ALL;
- /* For RW-PCC, the value of @rwid must be non zero. */
- if (cmd->u.pccc_add.pccc_flags & PCC_DATASET_RWPCC &&
- cmd->u.pccc_add.pccc_rwid == 0)
+ if (cmd->u.pccc_add.pccc_rwid == 0 &&
+ cmd->u.pccc_add.pccc_roid == 0)
return -EINVAL;
+ if (cmd->u.pccc_add.pccc_rwid == 0 &&
+ cmd->u.pccc_add.pccc_flags & PCC_DATASET_RWPCC)
+ cmd->u.pccc_add.pccc_rwid = cmd->u.pccc_add.pccc_roid;
+
+ if (cmd->u.pccc_add.pccc_roid == 0 &&
+ cmd->u.pccc_add.pccc_flags & PCC_DATASET_ROPCC)
+ cmd->u.pccc_add.pccc_roid = cmd->u.pccc_add.pccc_rwid;
+
break;
case PCC_DEL_DATASET:
case PCC_CLEAR_ALL:
if (type == LU_PCC_READWRITE && (dataset->pccd_rwid != id ||
!(dataset->pccd_flags & PCC_DATASET_RWPCC)))
continue;
+ if (type == LU_PCC_READONLY && (dataset->pccd_roid != id ||
+ !(dataset->pccd_flags & PCC_DATASET_ROPCC)))
+ continue;
atomic_inc(&dataset->pccd_refcount);
selected = dataset;
break;
!(dataset->pccd_flags & PCC_DATASET_RWPCC))
RETURN(0);
+ if (type == LU_PCC_READONLY &&
+ !(dataset->pccd_flags & PCC_DATASET_ROPCC))
+ RETURN(0);
+
rc = pcc_fid2dataset_path(pathname, PCC_DATASET_MAX_PATH,
&lli->lli_fid);
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)
+ rc = pcc_try_datasets_attach(inode, iot, clt.cl_layout_gen,
+ LU_PCC_READONLY, cached);
RETURN(rc);
}
struct ll_inode_info *lli = ll_i2info(inode);
struct pcc_super *super = ll_i2pccs(inode);
+ ENTRY;
+
/* Known the file was not in any PCC backend. */
if (lli->lli_pcc_dsflags & PCC_DATASET_NONE)
- return false;
+ RETURN(false);
/*
* lli_pcc_generation == 0 means that the file was never attached into
* immediately in pcc_try_auto_attach().
*/
if (super->pccs_generation != lli->lli_pcc_generation)
- return true;
+ RETURN(true);
/* The cached setting @lli_pcc_dsflags is valid */
if (iot == PIT_OPEN)
- return lli->lli_pcc_dsflags & PCC_DATASET_OPEN_ATTACH;
+ RETURN(lli->lli_pcc_dsflags & PCC_DATASET_OPEN_ATTACH);
if (iot == PIT_GETATTR)
- return lli->lli_pcc_dsflags & PCC_DATASET_STAT_ATTACH;
+ RETURN(lli->lli_pcc_dsflags & PCC_DATASET_STAT_ATTACH);
- return lli->lli_pcc_dsflags & PCC_DATASET_IO_ATTACH;
+ RETURN(lli->lli_pcc_dsflags & PCC_DATASET_IO_ATTACH);
}
int pcc_file_open(struct inode *inode, struct file *file)
RETURN_EXIT;
}
+/* Tolerate the IO failure on PCC and fall back to normal Lustre IO path */
+static bool pcc_io_tolerate(struct pcc_inode *pcci,
+ enum pcc_io_type iot, int rc)
+{
+ if (pcci->pcci_type == LU_PCC_READWRITE) {
+ if (iot == PIT_WRITE && (rc == -ENOSPC || rc == -EDQUOT))
+ return false;
+ /* Handle the ->page_mkwrite failure tolerance separately
+ * in pcc_page_mkwrite().
+ */
+ } else if (pcci->pcci_type == LU_PCC_READONLY) {
+ if ((iot == PIT_READ || iot == PIT_GETATTR ||
+ iot == PIT_SPLICE_READ) && rc < 0 && rc != -ENOMEM)
+ return false;
+ if (iot == PIT_FAULT && (rc & VM_FAULT_SIGBUS) &&
+ !(rc & VM_FAULT_OOM))
+ return false;
+ }
+
+ return true;
+}
+
static void pcc_io_init(struct inode *inode, enum pcc_io_type iot, bool *cached)
{
struct pcc_inode *pcci;
pcci = ll_i2pcci(inode);
if (pcci && pcc_inode_has_layout(pcci)) {
LASSERT(atomic_read(&pcci->pcci_refcount) > 0);
- atomic_inc(&pcci->pcci_active_ios);
- *cached = true;
+ if (pcci->pcci_type == LU_PCC_READONLY &&
+ (iot == PIT_WRITE || iot == PIT_SETATTR ||
+ iot == PIT_PAGE_MKWRITE)) {
+ /* Fall back to normal I/O path */
+ *cached = false;
+ /* For mmap write, we need to detach the file from
+ * RO-PCC, release the page got from ->fault(), and
+ * then retry the memory fault handling (->fault()
+ * and ->page_mkwrite()).
+ * These are done in pcc_page_mkwrite();
+ */
+ } else {
+ atomic_inc(&pcci->pcci_active_ios);
+ *cached = true;
+ }
} else {
*cached = false;
if (pcc_may_auto_attach(inode, iot)) {
pcc_inode_unlock(inode);
}
-static void pcc_io_fini(struct inode *inode)
+static void pcc_io_fini(struct inode *inode, enum pcc_io_type iot,
+ int rc, bool *cached)
{
struct pcc_inode *pcci = ll_i2pcci(inode);
- LASSERT(pcci && atomic_read(&pcci->pcci_active_ios) > 0);
+ LASSERT(pcci && atomic_read(&pcci->pcci_active_ios) > 0 && *cached);
+
+ *cached = pcc_io_tolerate(pcci, iot, rc);
if (atomic_dec_and_test(&pcci->pcci_active_ios))
wake_up(&pcci->pcci_waitq);
}
if (!*cached)
RETURN(0);
+ /* Fake I/O error on RO-PCC */
+ if (CFS_FAIL_CHECK(OBD_FAIL_LLITE_PCC_FAKE_ERROR))
+ GOTO(out, result = -EIO);
+
iocb->ki_filp = pccf->pccf_file;
/* generic_file_aio_read does not support ext4-dax,
* __pcc_file_read_iter uses ->aio_read hook directly
*/
result = __pcc_file_read_iter(iocb, iter);
iocb->ki_filp = file;
-
- pcc_io_fini(inode);
+out:
+ pcc_io_fini(inode, PIT_READ, result, cached);
RETURN(result);
}
result = __pcc_file_write_iter(iocb, iter);
iocb->ki_filp = file;
out:
- pcc_io_fini(inode);
+ pcc_io_fini(inode, PIT_WRITE, result, cached);
RETURN(result);
}
revert_creds(old_cred);
inode_unlock(pcc_dentry->d_inode);
- pcc_io_fini(inode);
+ pcc_io_fini(inode, PIT_SETATTR, rc, cached);
RETURN(rc);
}
ll_inode_size_unlock(inode);
out:
- pcc_io_fini(inode);
+ pcc_io_fini(inode, PIT_GETATTR, rc, cached);
RETURN(rc);
}
result = default_file_splice_read(pcc_file, ppos, pipe, count, flags);
- pcc_io_fini(inode);
+ pcc_io_fini(inode, PIT_SPLICE_READ, result, &cached);
RETURN(result);
}
#endif /* HAVE_DEFAULT_FILE_SPLICE_READ_EXPORT */
{
struct inode *inode = file_inode(file);
struct ll_file_data *fd = file->private_data;
- struct file *pcc_file = fd->fd_pcc_file.pccf_file;
+ struct pcc_file *pccf = &fd->fd_pcc_file;
+ struct file *pcc_file = pccf->pccf_file;
int rc;
ENTRY;
RETURN(0);
}
+ if (!S_ISREG(inode->i_mode)) {
+ *cached = false;
+ RETURN(0);
+ }
+
+ /*
+ * After the file is attached into RO-PCC, its dirty pages on this
+ * client may not be flushed. So fsync() should fall back to normal
+ * Lustre I/O path flushing dirty data to OSTs. And flush on RO-PCC
+ * copy is meaningless.
+ */
+ if (pccf->pccf_type == LU_PCC_READONLY) {
+ *cached = false;
+ RETURN(-EAGAIN);
+ }
+
pcc_io_init(inode, PIT_FSYNC, cached);
if (!*cached)
RETURN(0);
rc = file_inode(pcc_file)->i_fop->fsync(pcc_file,
start, end, datasync);
- pcc_io_fini(inode);
+ pcc_io_fini(inode, PIT_FSYNC, rc, cached);
RETURN(rc);
}
* __do_page_fault and retry the memory fault handling.
*/
if (page->mapping == pcc_file->f_mapping) {
+ pcc_ioctl_detach(inode, PCC_DETACH_OPT_UNCACHE);
*cached = true;
mmap_read_unlock(mm);
RETURN(VM_FAULT_RETRY | VM_FAULT_NOPAGE);
* This fault injection can also be used to simulate -ENOSPC and
* -EDQUOT failure of underlying PCC backend fs.
*/
- if (CFS_FAIL_CHECK(OBD_FAIL_LLITE_PCC_DETACH_MKWRITE)) {
- pcc_io_fini(inode);
- pcc_ioctl_detach(inode, PCC_DETACH_OPT_UNCACHE);
- mmap_read_unlock(mm);
- RETURN(VM_FAULT_RETRY | VM_FAULT_NOPAGE);
- }
+ if (CFS_FAIL_CHECK(OBD_FAIL_LLITE_PCC_DETACH_MKWRITE))
+ GOTO(out, rc = VM_FAULT_SIGBUS);
vma->vm_file = pcc_file;
#ifdef HAVE_VM_OPS_USE_VM_FAULT_ONLY
#endif
vma->vm_file = file;
- pcc_io_fini(inode);
+out:
+ pcc_io_fini(inode, PIT_PAGE_MKWRITE, rc, cached);
+
+ /* VM_FAULT_SIGBUG usually means that underlying PCC backend fs returns
+ * -EIO, -ENOSPC or -EDQUOT. Thus we can retry this IO from the normal
+ * Lustre I/O path.
+ */
+ if (rc & VM_FAULT_SIGBUS) {
+ pcc_ioctl_detach(inode, PCC_DETACH_OPT_UNCACHE);
+ mmap_read_unlock(mm);
+ RETURN(VM_FAULT_RETRY | VM_FAULT_NOPAGE);
+ }
RETURN(rc);
}
RETURN(0);
}
+ if (!S_ISREG(inode->i_mode)) {
+ *cached = false;
+ RETURN(0);
+ }
+
pcc_io_init(inode, PIT_FAULT, cached);
if (!*cached)
RETURN(0);
+ /* Tolerate the mmap read failure for RO-PCC */
+ if (CFS_FAIL_CHECK(OBD_FAIL_LLITE_PCC_FAKE_ERROR))
+ GOTO(out, rc = VM_FAULT_SIGBUS);
+
vma->vm_file = pcc_file;
#ifdef HAVE_VM_OPS_USE_VM_FAULT_ONLY
rc = pcc_vm_ops->fault(vmf);
rc = pcc_vm_ops->fault(vma, vmf);
#endif
vma->vm_file = file;
-
- pcc_io_fini(inode);
+out:
+ pcc_io_fini(inode, PIT_FAULT, rc, cached);
RETURN(rc);
}
rc = pcc_layout_xattr_set(pcci, 0);
if (rc) {
- (void) pcc_inode_remove(inode, pcci->pcci_path.dentry);
+ if (!pcci->pcci_unlinked)
+ (void) pcc_inode_remove(inode, pcci->pcci_path.dentry);
pcc_inode_put(pcci);
GOTO(out_unlock, rc);
}
RETURN(rc);
}
-int pcc_readwrite_attach(struct file *file, struct inode *inode,
- __u32 archive_id)
+static int pcc_attach_data_archive(struct file *file, struct inode *inode,
+ struct pcc_dataset *dataset,
+ struct dentry **dentry)
{
- struct pcc_dataset *dataset;
- struct ll_inode_info *lli = ll_i2info(inode);
- struct pcc_super *super = ll_i2pccs(inode);
- struct pcc_inode *pcci;
const struct cred *old_cred;
- struct dentry *dentry;
struct file *pcc_filp;
struct path path;
ssize_t ret;
ENTRY;
- rc = pcc_attach_allowed_check(inode);
- if (rc)
- RETURN(rc);
-
- dataset = pcc_dataset_get(&ll_i2sbi(inode)->ll_pcc_super,
- LU_PCC_READWRITE, archive_id);
- if (dataset == NULL)
- RETURN(-ENOENT);
-
- old_cred = override_creds(super->pccs_cred);
- rc = __pcc_inode_create(dataset, &lli->lli_fid, &dentry);
+ old_cred = override_creds(pcc_super_cred(inode->i_sb));
+ rc = __pcc_inode_create(dataset, &ll_i2info(inode)->lli_fid, dentry);
if (rc)
- GOTO(out_dataset_put, rc);
+ GOTO(out_cred, rc);
path.mnt = dataset->pccd_path.mnt;
- path.dentry = dentry;
+ path.dentry = *dentry;
pcc_filp = dentry_open(&path, O_WRONLY | O_LARGEFILE, current_cred());
if (IS_ERR_OR_NULL(pcc_filp)) {
rc = pcc_filp == NULL ? -EINVAL : PTR_ERR(pcc_filp);
GOTO(out_dentry, rc);
}
- rc = pcc_inode_reset_iattr(dentry, ATTR_UID | ATTR_GID,
+ rc = pcc_inode_reset_iattr(*dentry, ATTR_UID | ATTR_GID,
old_cred->uid, old_cred->gid, 0);
if (rc)
GOTO(out_fput, rc);
* copy after copy data. Otherwise, it may get wrong file size after
* re-attach a file. See LU-13023 for details.
*/
- rc = pcc_inode_reset_iattr(dentry, ATTR_SIZE, KUIDT_INIT(0),
+ rc = pcc_inode_reset_iattr(*dentry, ATTR_SIZE, KUIDT_INIT(0),
KGIDT_INIT(0), ret);
+out_fput:
+ fput(pcc_filp);
+out_dentry:
+ if (rc) {
+ pcc_inode_remove(inode, *dentry);
+ dput(*dentry);
+ }
+out_cred:
+ revert_creds(old_cred);
+ RETURN(rc);
+}
+
+int pcc_readwrite_attach(struct file *file, struct inode *inode,
+ __u32 archive_id)
+{
+ struct pcc_dataset *dataset;
+ struct ll_inode_info *lli = ll_i2info(inode);
+ struct pcc_super *super = ll_i2pccs(inode);
+ struct pcc_inode *pcci;
+ struct dentry *dentry;
+ int rc;
+
+ ENTRY;
+
+ rc = pcc_attach_allowed_check(inode);
if (rc)
- GOTO(out_fput, rc);
+ RETURN(rc);
+
+ dataset = pcc_dataset_get(&ll_i2sbi(inode)->ll_pcc_super,
+ LU_PCC_READWRITE, archive_id);
+ if (dataset == NULL)
+ RETURN(-ENOENT);
+
+ rc = pcc_attach_data_archive(file, inode, dataset, &dentry);
+ if (rc)
+ GOTO(out_dataset_put, rc);
/* Pause to allow for a race with concurrent HSM remove */
CFS_FAIL_TIMEOUT(OBD_FAIL_LLITE_PCC_ATTACH_PAUSE, cfs_fail_val);
dentry, LU_PCC_READWRITE);
out_unlock:
pcc_inode_unlock(inode);
-out_fput:
- fput(pcc_filp);
-out_dentry:
if (rc) {
+ const struct cred *old_cred;
+
+ old_cred = override_creds(pcc_super_cred(inode->i_sb));
(void) pcc_inode_remove(inode, dentry);
+ revert_creds(old_cred);
dput(dentry);
}
out_dataset_put:
pcc_dataset_put(dataset);
- revert_creds(old_cred);
RETURN(rc);
}
out_put:
if (rc) {
- (void) pcc_inode_remove(inode, pcci->pcci_path.dentry);
+ if (!pcci->pcci_unlinked)
+ (void) pcc_inode_remove(inode, pcci->pcci_path.dentry);
pcc_inode_put(pcci);
}
out_unlock:
RETURN(rc);
}
+static int pcc_layout_rdonly_set(struct inode *inode, __u32 *gen)
+
+{
+ struct ll_inode_info *lli = ll_i2info(inode);
+ struct lu_extent ext = {
+ .e_start = 0,
+ .e_end = OBD_OBJECT_EOF,
+ };
+ struct cl_layout clt = {
+ .cl_layout_gen = 0,
+ .cl_is_released = false,
+ .cl_is_rdonly = false,
+ };
+ int retries = 0;
+ int rc;
+
+ ENTRY;
+
+repeat:
+ rc = pcc_get_layout_info(inode, &clt);
+ if (rc)
+ RETURN(rc);
+
+ /*
+ * For the HSM released file, restore the data first.
+ */
+ if (clt.cl_is_released) {
+ retries++;
+ if (retries > 2)
+ RETURN(-EBUSY);
+
+ if (ll_layout_version_get(lli) != CL_LAYOUT_GEN_NONE) {
+ rc = ll_layout_restore(inode, 0, OBD_OBJECT_EOF);
+ if (rc) {
+ CDEBUG(D_CACHE, DFID" RESTORE failure: %d\n",
+ PFID(&lli->lli_fid), rc);
+ RETURN(rc);
+ }
+ }
+ rc = ll_layout_refresh(inode, gen);
+ if (rc)
+ RETURN(rc);
+
+ goto repeat;
+ }
+
+
+ if (!clt.cl_is_rdonly) {
+ rc = ll_layout_write_intent(inode, LAYOUT_INTENT_PCCRO_SET,
+ &ext);
+ if (rc)
+ RETURN(rc);
+
+ rc = ll_layout_refresh(inode, gen);
+ if (rc)
+ RETURN(rc);
+ } else { /* Readonly layout */
+ *gen = clt.cl_layout_gen;
+ }
+
+ RETURN(rc);
+}
+
+static int pcc_readonly_ioctl_attach(struct file *file,
+ struct inode *inode,
+ struct lu_pcc_attach *attach)
+{
+ struct ll_sb_info *sbi = ll_i2sbi(inode);
+ struct pcc_super *super = ll_i2pccs(inode);
+ struct ll_inode_info *lli = ll_i2info(inode);
+ const struct cred *old_cred;
+ struct pcc_dataset *dataset;
+ struct pcc_inode *pcci;
+ struct dentry *dentry;
+ bool attached = false;
+ bool unlinked = false;
+ __u32 gen;
+ int rc;
+
+ ENTRY;
+
+ if (!test_bit(LL_SBI_LAYOUT_LOCK, sbi->ll_flags))
+ RETURN(-EOPNOTSUPP);
+
+ rc = pcc_attach_allowed_check(inode);
+ if (rc)
+ RETURN(rc);
+
+ rc = pcc_layout_rdonly_set(inode, &gen);
+ if (rc)
+ RETURN(rc);
+
+ dataset = pcc_dataset_get(&ll_s2sbi(inode->i_sb)->ll_pcc_super,
+ LU_PCC_READONLY, attach->pcca_id);
+ if (dataset == NULL)
+ RETURN(-ENOENT);
+
+ rc = pcc_attach_data_archive(file, inode, dataset, &dentry);
+ if (rc)
+ GOTO(out_dataset_put, rc);
+
+ mutex_lock(&lli->lli_layout_mutex);
+ pcc_inode_lock(inode);
+ old_cred = override_creds(super->pccs_cred);
+ lli->lli_pcc_state &= ~PCC_STATE_FL_ATTACHING;
+ if (gen != ll_layout_version_get(lli))
+ GOTO(out_put_unlock, rc = -ESTALE);
+
+ pcci = ll_i2pcci(inode);
+ if (!pcci) {
+ OBD_SLAB_ALLOC_PTR_GFP(pcci, pcc_inode_slab, GFP_NOFS);
+ if (pcci == NULL)
+ GOTO(out_put_unlock, rc = -ENOMEM);
+
+ pcc_inode_attach_set(super, dataset, lli, pcci,
+ dentry, LU_PCC_READONLY);
+ } else {
+ atomic_inc(&pcci->pcci_refcount);
+ path_put(&pcci->pcci_path);
+ pcci->pcci_path.mnt = mntget(dataset->pccd_path.mnt);
+ pcci->pcci_path.dentry = dentry;
+ pcci->pcci_type = LU_PCC_READONLY;
+ }
+ attached = true;
+ rc = pcc_layout_xattr_set(pcci, gen);
+ if (rc) {
+ pcci->pcci_type = LU_PCC_NONE;
+ unlinked = pcci->pcci_unlinked;
+ GOTO(out_put_unlock, rc);
+ }
+
+ pcc_layout_gen_set(pcci, gen);
+out_put_unlock:
+ if (rc) {
+ if (!unlinked)
+ (void) pcc_inode_remove(inode, dentry);
+ if (attached)
+ pcc_inode_put(pcci);
+ else
+ dput(dentry);
+ }
+ revert_creds(old_cred);
+ pcc_inode_unlock(inode);
+ mutex_unlock(&lli->lli_layout_mutex);
+out_dataset_put:
+ pcc_dataset_put(dataset);
+
+ RETURN(rc);
+}
+
+int pcc_ioctl_attach(struct file *file, struct inode *inode,
+ struct lu_pcc_attach *attach)
+{
+ int rc = 0;
+
+ ENTRY;
+
+ switch (attach->pcca_type) {
+ case LU_PCC_READWRITE:
+ rc = -EOPNOTSUPP;
+ break;
+ case LU_PCC_READONLY:
+ rc = pcc_readonly_ioctl_attach(file, inode, attach);
+ break;
+ default:
+ rc = -EINVAL;
+ break;
+ }
+
+ RETURN(rc);
+}
+
static int pcc_hsm_remove(struct inode *inode)
{
struct hsm_user_request *hur;
{
struct ll_inode_info *lli = ll_i2info(inode);
struct pcc_inode *pcci;
+ const struct cred *old_cred;
bool hsm_remove = false;
int rc = 0;
__pcc_layout_invalidate(pcci);
pcc_inode_put(pcci);
+ } else if (pcci->pcci_type == LU_PCC_READONLY) {
+ __pcc_layout_invalidate(pcci);
+
+ if (opt == PCC_DETACH_OPT_UNCACHE && !pcci->pcci_unlinked) {
+ old_cred = override_creds(pcc_super_cred(inode->i_sb));
+ rc = pcc_inode_remove(inode, pcci->pcci_path.dentry);
+ revert_creds(old_cred);
+ if (!rc)
+ pcci->pcci_unlinked = true;
+ }
+
+ pcc_inode_put(pcci);
+ } else {
+ rc = -EOPNOTSUPP;
}
out_unlock:
pcc_inode_unlock(inode);
if (hsm_remove) {
- const struct cred *old_cred;
-
old_cred = override_creds(pcc_super_cred(inode->i_sb));
rc = pcc_hsm_remove(inode);
revert_creds(old_cred);
*/
atomic_t pcci_refcount;
/* Whether readonly or readwrite PCC */
- enum lu_pcc_type pcci_type;
+ enum lu_pcc_type pcci_type:8;
/* Whether the inode attr is cached locally */
bool pcci_attr_valid;
+ /* Whether the PCC inode is unlinked at detach */
+ bool pcci_unlinked;
/* Layout generation */
__u32 pcci_layout_gen;
/*
PIT_FAULT,
/* fsync system call handling */
PIT_FSYNC,
-#ifdef HAVE_DEFAULT_FILE_SPLICE_READ_EXPORT
/* splice_read system call */
PIT_SPLICE_READ,
-#endif
/* open system call */
PIT_OPEN
};
int pcc_readwrite_attach_fini(struct file *file, struct inode *inode,
__u32 gen, bool lease_broken, int rc,
bool attached);
+int pcc_ioctl_attach(struct file *file, struct inode *inode,
+ struct lu_pcc_attach *attach);
int pcc_ioctl_detach(struct inode *inode, __u32 opt);
int pcc_ioctl_state(struct file *file, struct inode *inode,
struct lu_pcc_state *state);
}
/* dynamic layout change needed, send layout intent RPC. */
- if (io->ci_need_write_intent) {
+ if (io->ci_need_write_intent || io->ci_need_pccro_clear) {
enum layout_intent_opc opc = LAYOUT_INTENT_WRITE;
io->ci_need_write_intent = 0;
if (cl_io_is_trunc(io))
opc = LAYOUT_INTENT_TRUNC;
+ if (io->ci_need_pccro_clear) {
+ io->ci_need_pccro_clear = 0;
+ opc = LAYOUT_INTENT_PCCRO_CLEAR;
+ }
+
rc = ll_layout_write_intent(inode, opc, &io->ci_write_intent);
io->ci_result = rc;
if (!rc)
comp_cnt = le16_to_cpu(comp_v1->lcm_entry_count);
if (comp_cnt == 0)
GOTO(out, rc = -EINVAL);
+
lo->ldo_layout_gen = le32_to_cpu(comp_v1->lcm_layout_gen);
lo->ldo_is_composite = 1;
mirror_cnt = le16_to_cpu(comp_v1->lcm_mirror_count) + 1;
for (i = 0; i < lo->ldo_mirror_count; i++) {
if (i == primary)
continue;
+
rc = lod_declare_update_extents(env, lo, &pri_extent,
th, i, 0);
/* if update_extents changed the layout, it may have
{
struct lov_stripe_md_entry *lsme;
struct lov_foreign_md *lfm = buf;
+ size_t length;
__u32 magic;
+ __u32 type;
ENTRY;
if (magic != LOV_MAGIC_FOREIGN)
RETURN(ERR_PTR(-EINVAL));
+ type = le32_to_cpu(lfm->lfm_type);
+ if (!lov_foreign_type_supported(type)) {
+ CDEBUG(D_LAYOUT, "Unsupported foreign type: %u\n", type);
+ RETURN(ERR_PTR(-EINVAL));
+ }
+
+ length = le32_to_cpu(lfm->lfm_length);
+ if (lov_foreign_size_le(lfm) > buf_size) {
+ CDEBUG(D_LAYOUT, "LOV EA HSM too small: %zu, need %zu\n",
+ buf_size, lov_foreign_size_le(lfm));
+ RETURN(ERR_PTR(-EINVAL));
+ }
+
+ if (lov_hsm_type_supported(type) &&
+ length < sizeof(struct lov_hsm_base)) {
+ CDEBUG(D_LAYOUT,
+ "Invalid LOV HSM len: %zu, should be larger than %zu\n",
+ length, sizeof(struct lov_hsm_base));
+ RETURN(ERR_PTR(-EINVAL));
+ }
+
OBD_ALLOC_LARGE(lsme, sizeof(*lsme));
if (!lsme)
RETURN(ERR_PTR(-ENOMEM));
lsme->lsme_magic = magic;
lsme->lsme_pattern = LOV_PATTERN_FOREIGN;
lsme->lsme_flags = 0;
+ lsme->lsme_length = length;
+ lsme->lsme_type = type;
+ lsme->lsme_foreign_flags = le32_to_cpu(lfm->lfm_flags);
+
+ /* TODO: Initialize for other kind of foreign layout such as DAOS. */
+ if (lov_hsm_type_supported(type))
+ lov_foreign_hsm_to_cpu(&lsme->lsme_hsm, lfm);
if (maxbytes)
*maxbytes = MAX_LFS_FILESIZE;
!(lov_pattern(le32_to_cpu(lmm->lmm_pattern)) & LOV_PATTERN_MDT))
RETURN(ERR_PTR(-EINVAL));
- if (magic == LOV_MAGIC_V1) {
+ if (magic == LOV_MAGIC_FOREIGN) {
+ return lsme_unpack_foreign(lov, lmm, lmm_buf_size,
+ inited, maxbytes);
+ } else if (magic == LOV_MAGIC_V1) {
return lsme_unpack(lov, lmm, lmm_buf_size, NULL,
inited, lmm->lmm_objects, maxbytes);
} else if (magic == LOV_MAGIC_V3) {
lsm->lsm_entry_count = entry_count;
lsm->lsm_mirror_count = le16_to_cpu(lcm->lcm_mirror_count);
lsm->lsm_flags = le16_to_cpu(lcm->lcm_flags);
+ lsm->lsm_is_rdonly = lsm->lsm_flags & LCM_FL_PCC_RDONLY;
lsm->lsm_is_released = true;
lsm->lsm_maxbytes = LLONG_MIN;
* pressume that unrecognized magic component also has valid
* lsme_id/lsme_flags/lsme_extent
*/
- if (!(lsme->lsme_pattern & LOV_PATTERN_F_RELEASED))
+ if (!(lsme->lsme_magic == LOV_MAGIC_FOREIGN) &&
+ !(lsme->lsme_pattern & LOV_PATTERN_F_RELEASED))
lsm->lsm_is_released = false;
lsm->lsm_entries[i] = lsme;
for (i = 0; i < lsm->lsm_entry_count; i++) {
struct lov_stripe_md_entry *lse = lsm->lsm_entries[i];
- CDEBUG(level, DEXT ": id: %u, flags: %x, "
- "magic 0x%08X, layout_gen %u, "
- "stripe count %u, sstripe size %u, "
- "pool: ["LOV_POOLNAMEF"]\n",
- PEXT(&lse->lsme_extent), lse->lsme_id, lse->lsme_flags,
- lse->lsme_magic, lse->lsme_layout_gen,
- lse->lsme_stripe_count, lse->lsme_stripe_size,
- lse->lsme_pool_name);
- if (!lsme_inited(lse) ||
- lse->lsme_pattern & LOV_PATTERN_F_RELEASED ||
- !lov_supported_comp_magic(lse->lsme_magic) ||
- !lov_pattern_supported(lov_pattern(lse->lsme_pattern)))
- continue;
- for (j = 0; j < lse->lsme_stripe_count; j++) {
- CDEBUG(level, " oinfo:%p: ostid: "DOSTID
- " ost idx: %d gen: %d\n",
- lse->lsme_oinfo[j],
- POSTID(&lse->lsme_oinfo[j]->loi_oi),
- lse->lsme_oinfo[j]->loi_ost_idx,
- lse->lsme_oinfo[j]->loi_ost_gen);
+ if (lsme_is_foreign(lse)) {
+ CDEBUG_LIMIT(level,
+ "HSM layout "DEXT ": id %u, flags: %08x, magic 0x%08X, length %u, type %x, flags %08x, archive_id %llu, archive_ver %llu, archive_uuid '%.*s'\n",
+ PEXT(&lse->lsme_extent), lse->lsme_id,
+ lse->lsme_flags, lse->lsme_magic,
+ lse->lsme_length, lse->lsme_type,
+ lse->lsme_foreign_flags,
+ lse->lsme_archive_id, lse->lsme_archive_ver,
+ (int)sizeof(lse->lsme_uuid), lse->lsme_uuid);
+ } else {
+ CDEBUG_LIMIT(level,
+ DEXT ": id: %u, flags: %x, magic 0x%08X, layout_gen %u, stripe count %u, sstripe size %u, pool: ["LOV_POOLNAMEF"]\n",
+ PEXT(&lse->lsme_extent), lse->lsme_id,
+ lse->lsme_flags, lse->lsme_magic,
+ lse->lsme_layout_gen, lse->lsme_stripe_count,
+ lse->lsme_stripe_size, lse->lsme_pool_name);
+ if (!lsme_inited(lse) ||
+ lse->lsme_pattern & LOV_PATTERN_F_RELEASED ||
+ !lov_supported_comp_magic(lse->lsme_magic) ||
+ !lov_pattern_supported(
+ lov_pattern(lse->lsme_pattern)))
+ continue;
+ for (j = 0; j < lse->lsme_stripe_count; j++) {
+ CDEBUG_LIMIT(level,
+ " oinfo:%p: ostid: "DOSTID" ost idx: %d gen: %d\n",
+ lse->lsme_oinfo[j],
+ POSTID(&lse->lsme_oinfo[j]->loi_oi),
+ lse->lsme_oinfo[j]->loi_ost_idx,
+ lse->lsme_oinfo[j]->loi_ost_gen);
+ }
}
}
}
u32 lsme_flags;
u32 lsme_pattern;
u64 lsme_timestamp;
- u32 lsme_stripe_size;
- u16 lsme_stripe_count;
- u16 lsme_layout_gen;
- char lsme_pool_name[LOV_MAXPOOLNAME + 1];
- struct lov_oinfo *lsme_oinfo[];
+ union {
+ struct { /* For stripe objects */
+ u32 lsme_stripe_size;
+ u16 lsme_stripe_count;
+ u16 lsme_layout_gen;
+ char lsme_pool_name[LOV_MAXPOOLNAME + 1];
+ struct lov_oinfo *lsme_oinfo[];
+ };
+ struct { /* For foreign layout (i.e. HSM, DAOS) */
+ u32 lsme_length;
+ u32 lsme_type;
+ u32 lsme_foreign_flags;
+ u32 lsme_padding;
+ union {
+ /* inline HSM layout data */
+ struct lov_hsm_base lsme_hsm;
+ /* Other kind of foreign layout (i.e. DAOS) */
+ char *lsme_value;
+ };
+ };
+ };
};
+#define lsme_archive_id lsme_hsm.lhb_archive_id
+#define lsme_archive_ver lsme_hsm.lhb_archive_ver
+#define lsme_uuid lsme_hsm.lhb_uuid
+
static inline bool lsme_is_dom(struct lov_stripe_md_entry *lsme)
{
return (lov_pattern(lsme->lsme_pattern) & LOV_PATTERN_MDT);
u32 lsm_layout_gen;
u16 lsm_flags;
bool lsm_is_released;
+ bool lsm_is_rdonly;
u16 lsm_mirror_count;
u16 lsm_entry_count;
struct lov_stripe_md_entry *lsm_entries[];
return magic == LOV_MAGIC_COMP_V1;
}
+static inline bool lsm_is_rdonly(const struct lov_stripe_md *lsm)
+{
+ return lsm->lsm_is_rdonly;
+}
+
static inline size_t lov_comp_md_size(const struct lov_stripe_md *lsm)
{
struct lov_stripe_md_entry *lsme;
lsme = lsm->lsm_entries[entry];
- if (lsme_inited(lsme))
- stripe_count = lsme->lsme_stripe_count;
- else
- stripe_count = 0;
+ if (lsme->lsme_magic == LOV_MAGIC_FOREIGN) {
+ size += lov_foreign_md_size(lsme->lsme_length);
+ } else {
+ if (lsme_inited(lsme))
+ stripe_count = lsme->lsme_stripe_count;
+ else
+ stripe_count = 0;
- size += lov_mds_md_size(stripe_count,
- lsme->lsme_magic);
+ size += lov_mds_md_size(stripe_count, lsme->lsme_magic);
+ }
}
return size;
{
int index;
int result = 0;
+ bool rdonly;
ENTRY;
io->ci_result = 0;
lio->lis_object = obj;
lio->lis_cached_entry = LIS_CACHE_ENTRY_NONE;
+ rdonly = lsm_is_rdonly(obj->lo_lsm);
switch (io->ci_type) {
case CIT_READ:
case CIT_WRITE:
+ if (io->ci_type == CIT_WRITE && rdonly) {
+ io->ci_need_pccro_clear = 1;
+ GOTO(out, result = 1);
+ }
lio->lis_pos = io->u.ci_rw.crw_pos;
lio->lis_endpos = io->u.ci_rw.crw_pos + io->u.ci_rw.crw_bytes;
lio->lis_io_endpos = lio->lis_endpos;
case CIT_SETATTR:
if (cl_io_is_fallocate(io)) {
+ if (rdonly) {
+ io->ci_need_pccro_clear = 1;
+ GOTO(out, result = 1);
+ }
lio->lis_pos = io->u.ci_setattr.sa_falloc_offset;
lio->lis_endpos = io->u.ci_setattr.sa_falloc_end;
} else if (cl_io_is_trunc(io)) {
+ if (rdonly) {
+ io->ci_need_pccro_clear = 1;
+ GOTO(out, result = 1);
+ }
lio->lis_pos = io->u.ci_setattr.sa_attr.lvb_size;
lio->lis_endpos = OBD_OBJECT_EOF;
} else {
case CIT_FAULT: {
pgoff_t index = io->u.ci_fault.ft_index;
+ if (cl_io_is_mkwrite(io) && rdonly) {
+ io->ci_need_pccro_clear = 1;
+ GOTO(out, result = -ENODATA);
+ }
+
lio->lis_pos = index << PAGE_SHIFT;
lio->lis_endpos = (index + 1) << PAGE_SHIFT;
break;
if (!lsm_entry_inited(lov->lo_lsm, index))
continue;
+ if (lsm_entry_is_foreign(lov->lo_lsm, index))
+ continue;
+
result = entry->lle_comp_ops->lco_getattr(env, lov, index,
entry, &lov_attr);
if (result < 0)
cl->cl_size = lov_comp_md_size(lsm);
cl->cl_layout_gen = lsm->lsm_layout_gen;
+ cl->cl_is_rdonly = lsm->lsm_is_rdonly;
cl->cl_is_released = lsm->lsm_is_released;
cl->cl_is_composite = lsm_is_composite(lsm->lsm_magic);
!lov_supported_comp_magic(lse->lsme_magic))
break;
+ if (lsme_is_foreign(lse))
+ break;
+
for (j = 0; j < lse->lsme_stripe_count; j++) {
struct lov_oinfo *loi =
lse->lsme_oinfo[j];
RETURN(lfm_size);
}
+unsigned int lov_lsme_pack_foreign(struct lov_stripe_md_entry *lsme, void *lmm)
+{
+ struct lov_foreign_md *lfm = (struct lov_foreign_md *)lmm;
+
+ lfm->lfm_magic = cpu_to_le32(lsme->lsme_magic);
+ lfm->lfm_length = cpu_to_le32(lsme->lsme_length);
+ lfm->lfm_type = cpu_to_le32(lsme->lsme_type);
+ lfm->lfm_flags = cpu_to_le32(lsme->lsme_foreign_flags);
+
+ /* TODO: support for foreign layout other than HSM, i.e. DAOS. */
+ if (lov_hsm_type_supported(lsme->lsme_type))
+ lov_foreign_hsm_to_le(lfm, &lsme->lsme_hsm);
+
+ return lov_foreign_md_size(lsme->lsme_length);
+}
+
+unsigned int lov_lsme_pack_v1v3(struct lov_stripe_md_entry *lsme,
+ struct lov_mds_md *lmm)
+{
+ struct lov_ost_data_v1 *lmm_objects;
+ __u16 stripe_count;
+ unsigned int i;
+
+ lmm->lmm_magic = cpu_to_le32(lsme->lsme_magic);
+ /* lmm->lmm_oi not set */
+ lmm->lmm_pattern = cpu_to_le32(lsme->lsme_pattern);
+ lmm->lmm_stripe_size = cpu_to_le32(lsme->lsme_stripe_size);
+ lmm->lmm_stripe_count = cpu_to_le16(lsme->lsme_stripe_count);
+ lmm->lmm_layout_gen = cpu_to_le16(lsme->lsme_layout_gen);
+
+ if (lsme->lsme_magic == LOV_MAGIC_V3) {
+ struct lov_mds_md_v3 *lmmv3 = (struct lov_mds_md_v3 *)lmm;
+
+ strlcpy(lmmv3->lmm_pool_name, lsme->lsme_pool_name,
+ sizeof(lmmv3->lmm_pool_name));
+ lmm_objects = lmmv3->lmm_objects;
+ } else {
+ lmm_objects = ((struct lov_mds_md_v1 *)lmm)->lmm_objects;
+ }
+
+ if (lsme_inited(lsme) && !(lsme->lsme_pattern & LOV_PATTERN_F_RELEASED))
+ stripe_count = lsme->lsme_stripe_count;
+ else
+ stripe_count = 0;
+
+ for (i = 0; i < stripe_count; i++) {
+ struct lov_oinfo *loi = lsme->lsme_oinfo[i];
+
+ ostid_cpu_to_le(&loi->loi_oi, &lmm_objects[i].l_ost_oi);
+ lmm_objects[i].l_ost_gen = cpu_to_le32(loi->loi_ost_gen);
+ lmm_objects[i].l_ost_idx = cpu_to_le32(loi->loi_ost_idx);
+ }
+
+ return lov_mds_md_size(stripe_count, lsme->lsme_magic);
+}
+
ssize_t lov_lsm_pack(const struct lov_stripe_md *lsm, void *buf,
size_t buf_size)
{
struct lov_comp_md_v1 *lcmv1 = buf;
struct lov_comp_md_entry_v1 *lcme;
- struct lov_ost_data_v1 *lmm_objects;
size_t lmm_size;
unsigned int entry;
unsigned int offset;
unsigned int size;
- unsigned int i;
ENTRY;
for (entry = 0; entry < lsm->lsm_entry_count; entry++) {
struct lov_stripe_md_entry *lsme;
struct lov_mds_md *lmm;
- __u16 stripe_count;
lsme = lsm->lsm_entries[entry];
lcme = &lcmv1->lcm_entries[entry];
lcme->lcme_offset = cpu_to_le32(offset);
lmm = (struct lov_mds_md *)((char *)lcmv1 + offset);
- lmm->lmm_magic = cpu_to_le32(lsme->lsme_magic);
- /* lmm->lmm_oi not set */
- lmm->lmm_pattern = cpu_to_le32(lsme->lsme_pattern);
- lmm->lmm_stripe_size = cpu_to_le32(lsme->lsme_stripe_size);
- lmm->lmm_stripe_count = cpu_to_le16(lsme->lsme_stripe_count);
- lmm->lmm_layout_gen = cpu_to_le16(lsme->lsme_layout_gen);
-
- if (lsme->lsme_magic == LOV_MAGIC_V3) {
- struct lov_mds_md_v3 *lmmv3 =
- (struct lov_mds_md_v3 *)lmm;
-
- strlcpy(lmmv3->lmm_pool_name, lsme->lsme_pool_name,
- sizeof(lmmv3->lmm_pool_name));
- lmm_objects = lmmv3->lmm_objects;
- } else {
- lmm_objects =
- ((struct lov_mds_md_v1 *)lmm)->lmm_objects;
- }
-
- if (lsme_inited(lsme) &&
- !(lsme->lsme_pattern & LOV_PATTERN_F_RELEASED))
- stripe_count = lsme->lsme_stripe_count;
+ if (lsme->lsme_magic == LOV_MAGIC_FOREIGN)
+ size = lov_lsme_pack_foreign(lsme, lmm);
else
- stripe_count = 0;
-
- for (i = 0; i < stripe_count; i++) {
- struct lov_oinfo *loi = lsme->lsme_oinfo[i];
-
- ostid_cpu_to_le(&loi->loi_oi, &lmm_objects[i].l_ost_oi);
- lmm_objects[i].l_ost_gen =
- cpu_to_le32(loi->loi_ost_gen);
- lmm_objects[i].l_ost_idx =
- cpu_to_le32(loi->loi_ost_idx);
- }
-
- size = lov_mds_md_size(stripe_count, lsme->lsme_magic);
+ size = lov_lsme_pack_v1v3(lsme, lmm);
lcme->lcme_size = cpu_to_le32(size);
offset += size;
} /* for each layout component */
RETURN(rc);
}
+
/**
* Layout change callback for object.
*
do_facet $facet $LCTL pcc add $MOUNT $hsm_root -p $param
}
+umount_loopdev() {
+ local facet=$1
+ local mntpt=$2
+ local rc
+
+ do_facet $facet lsof $mntpt || true
+ do_facet $facet $UMOUNT $mntpt
+ rc=$?
+ return $rc
+}
+
setup_loopdev() {
local facet=$1
local file=$2
do_facet $facet file $file
do_facet $facet mount -t ext4 -o loop,usrquota,grpquota $file $mntpt ||
error "mount -o loop,usrquota,grpquota $file $mntpt failed"
- stack_trap "do_facet $facet $UMOUNT $mntpt" EXIT
+ stack_trap "umount_loopdev $facet $mntpt" EXIT
}
lpcc_rw_test() {
do_facet $SINGLEAGT $RUNAS $LFS pcc detach $file ||
error "failed to detach file $file"
- check_lpcc_state $file "none"
wait_request_state $(path2fid $file) REMOVE SUCCEED
+ check_lpcc_state $file "none"
}
run_test 1e "Test RW-PCC with non-root user"
dd if=/dev/zero of=$file bs=1024 count=1 ||
error "failed to dd write to $file"
+ chmod 600 $file || error "chmod 600 $file failed"
do_facet $SINGLEAGT $RUNAS dd if=/dev/zero of=$file bs=1024 count=1 &&
- error "non-root user can dd write to $file"
+ error "non-root user can dd write $file"
+ do_facet $SINGLEAGT $RUNAS dd if=$file of=/dev/null bs=1024 count=1 &&
+ error "non-root user can dd read $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"
+ do_facet $SINGLEAGT $RUNAS dd if=$file of=/dev/null bs=1024 count=1 &&
+ error "non-root user can dd read $file"
chmod 777 $DIR2/$tfile || error "chmod 777 $DIR2/$tfile 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)"
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"
wait_request_state $(path2fid $file) REMOVE SUCCEED
+ 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)"
}
test_3a() {
local file=$DIR/$tdir/$tfile
+ local file2=$DIR2/$tdir/$tfile
copytool setup -m "$MOUNT" -a "$HSM_ARCHIVE_NUMBER"
setup_pcc_mapping $SINGLEAGT \
"projid={100}\ rwid=$HSM_ARCHIVE_NUMBER\ auto_attach=0"
mkdir -p $DIR/$tdir || error "mkdir $DIR/$tdir failed"
- dd if=/dev/zero of=$file bs=1024 count=1 ||
+ dd if=/dev/zero of=$file2 bs=1024 count=1 ||
error "failed to dd write to $file"
- echo "Start to attach/detach the file: $file"
+ echo "Start to RW-PCC attach/detach the file: $file"
do_facet $SINGLEAGT $LFS pcc attach -i $HSM_ARCHIVE_NUMBER $file ||
error "failed to attach file $file"
check_lpcc_state $file "readwrite"
error "failed to detach file $file"
check_lpcc_state $file "none"
- echo "Repeat to attach/detach the same file: $file"
+ echo "Repeat to RW-PCC attach/detach the same file: $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 $LFS pcc detach -k $file ||
error "failed to detach file $file"
check_lpcc_state $file "none"
+
+ rm -f $file || error "failed to remove $file"
+ echo "ropcc_data" > $file
+
+ echo "Start to RO-PCC attach/detach the file: $file"
+ do_facet $SINGLEAGT $LFS pcc attach -r -i $HSM_ARCHIVE_NUMBER $file ||
+ error "failed to attach file $file"
+ check_lpcc_state $file "readonly"
+ do_facet $SINGLEAGT $LFS pcc detach -k $file ||
+ error "failed to detach file $file"
+ check_lpcc_state $file "none"
+
+ echo "Repeat to RO-PCC attach/detach the same file: $file"
+ do_facet $SINGLEAGT $LFS pcc attach -r -i $HSM_ARCHIVE_NUMBER $file ||
+ error "failed to attach file $file"
+ check_lpcc_state $file "readonly"
+ do_facet $SINGLEAGT $LFS pcc detach -k $file ||
+ error "failed to detach file $file"
+ check_lpcc_state $file "none"
}
run_test 3a "Repeat attach/detach operations"
# Start all of the copytools and setup PCC
for n in $(seq $AGTCOUNT); do
- copytool setup -f agt$n -a $n -m $MOUNT
+ copytool setup -f agt$n -a $n -m $MOUNT -h $(hsm_root agt$n)
setup_pcc_mapping agt$n "projid={100}\ rwid=$n\ auto_attach=0"
done
dd if=/dev/zero of=$file bs=1024 count=1 ||
error "failed to dd write to $file"
- echo "Start to attach/detach $file on $agt1_HOST"
+ echo "Start to RW-PCC attach/detach $file on $agt1_HOST"
do_facet agt1 $LFS pcc attach -i 1 $file ||
error "failed to attach file $file"
check_lpcc_state $file "readwrite" agt1
error "failed to detach file $file"
check_lpcc_state $file "none" agt1
- echo "Repeat to attach/detach $file on $agt2_HOST"
+ echo "Repeat to RW-PCC attach/detach $file on $agt2_HOST"
do_facet agt2 $LFS pcc attach -i 2 $file ||
error "failed to attach file $file"
check_lpcc_state $file "readwrite" agt2
error "failed to detach file $file"
check_lpcc_state $file "none" agt2
- echo "Try attach on two agents"
+ echo "Try RW-PCC attach on two agents"
do_facet agt1 $LFS pcc attach -i 1 $file ||
error "failed to attach file $file"
check_lpcc_state $file "readwrite" agt1
do_facet agt2 $LFS pcc detach -k $file ||
error "failed to detach file $file"
check_lpcc_state $file "none" agt2
+
+ echo "Start to RO-PCC attach/detach $file on $agt1_HOST"
+ do_facet agt1 $LFS pcc attach -r -i 1 $file ||
+ error "failed to attach file $file"
+ check_lpcc_state $file "readonly" agt1
+ do_facet agt1 $LFS pcc detach -k $file ||
+ error "failed to detach file $file"
+ check_lpcc_state $file "none" agt1
+
+ echo "Repeat to RO-PCC attach/detach $file on $agt2_HOST"
+ do_facet agt2 $LFS pcc attach -r -i 2 $file ||
+ error "failed to attach file $file"
+ check_lpcc_state $file "readonly" agt2
+ do_facet agt2 $LFS pcc detach -k $file ||
+ error "failed to detach file $file"
+ check_lpcc_state $file "none" agt2
+
+ echo "Try RO-PCC attach on two agents"
+ do_facet agt1 $LFS pcc attach -r -i 1 $file ||
+ error "failed to attach file $file"
+ check_lpcc_state $file "readonly" agt1
+ do_facet agt2 $LFS pcc attach -r -i 2 $file ||
+ error "failed to attach file $file"
+ check_lpcc_state $file "readonly" agt2
+ check_lpcc_state $file "readonly" agt1
+ do_facet agt2 $LFS pcc detach -k $file ||
+ error "failed to detach file $file"
+ check_lpcc_state $file "none" agt2
+ do_facet agt1 $LFS pcc detach -k $file ||
+ error "failed to detach file $file"
+ check_lpcc_state $file "none" agt1
}
run_test 3b "Repeat attach/detach operations on multiple clients"
local loopfile="$TMP/$tfile"
local mntpt="/mnt/pcc.$tdir"
local hsm_root="$mntpt/$tdir"
+ local state="readwrite"
local ug=$1
+ local ro=$2
local id=$RUNAS_ID
[[ $ug == "g" ]] && id=$RUNAS_GID
-
+ [[ -z $ro ]] || state="readonly"
setup_loopdev $SINGLEAGT $loopfile $mntpt 50
do_facet $SINGLEAGT quotacheck -c$ug $mntpt ||
error "quotacheck -c$ug $mntpt failed"
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 \
+ do_facet $SINGLEAGT $RUNAS $LFS pcc attach -i $HSM_ARCHIVE_NUMBER $ro \
$file1 || error "attach $file1 failed"
- do_facet $SINGLEAGT $RUNAS $LFS pcc attach -i $HSM_ARCHIVE_NUMBER \
+ do_facet $SINGLEAGT $RUNAS $LFS pcc attach -i $HSM_ARCHIVE_NUMBER $ro \
$file2 && error "attach $file2 should fail due to quota limit"
- check_lpcc_state $file1 "readwrite"
+ check_lpcc_state $file1 $state
check_lpcc_state $file2 "none"
+ if [[ -n $ro ]]; then
+ do_facet $SINGLEAGT $LFS pcc detach $file1 ||
+ error "detach $file1 failed"
+ return 0
+ fi
+
+ echo "Test -EDQUOT error tolerance for RW-PCC"
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 -k $file1 ||
- error "failed to detach file $file"
- rm $file1 $file2
}
test_10a() {
}
run_test 10b "Test RW-PCC with group quota on loop PCC device"
+test_10c() {
+ test_usrgrp_quota "u" "-r"
+}
+run_test 10c "Test RO-PCC with user quota on loop PCC device"
+
+test_10d() {
+ test_usrgrp_quota "g" "-r"
+}
+run_test 10d "Test RO-PCC with group quota on loop PCC device"
+
test_11() {
local loopfile="$TMP/$tfile"
local mntpt="/mnt/pcc.$tdir"
set_param ldlm.namespaces.*mdc*.lru_size=clear
check_file_data $SINGLEAGT $file "autodetach_data"
check_lpcc_state $file "none"
+
+ rm $file || error "rm $file failed"
+ do_facet $SINGLEAGT "echo -n ro_autodetach_data > $file"
+ do_facet $SINGLEAGT $LFS pcc attach -r -i $HSM_ARCHIVE_NUMBER $file ||
+ error "PCC attach $file failed"
+ check_lpcc_state $file "readonly"
+
+ # Revoke the layout lock, the PCC-cached file will be
+ # detached automatically.
+ do_facet $SINGLEAGT $LCTL \
+ set_param ldlm.namespaces.*mdc*.lru_size=clear
+ check_file_data $SINGLEAGT $file "ro_autodetach_data"
+ check_lpcc_state $file "none"
}
run_test 14 "Revocation of the layout lock should detach the file automatically"
mkdir_on_mdt0 $DIR/$tdir || error "mkdir $DIR/$tdir failed"
chmod 777 $DIR/$tdir || error "chmod 777 $DIR/$tdir failed"
- echo "Check open attach for non-root user"
+ echo "Verify open attach for non-root user"
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 \
error "PCC detach $file failed"
rm $file || error "rm $file failed"
- echo "check open attach for root user"
+ echo "Verify auto attach at open for RW-PCC"
do_facet $SINGLEAGT "echo -n autoattach_data > $file"
do_facet $SINGLEAGT $LFS pcc attach -i $HSM_ARCHIVE_NUMBER \
- $file || error "PCC attach $file failed"
+ $file || error "RW-PCC attach $file failed"
check_lpcc_state $file "readwrite"
# Revoke the layout lock, the PCC-cached file will be
# is not changed, so the file is still valid cached in PCC,
# and can be reused from PCC cache directly.
do_facet $SINGLEAGT $LFS pcc detach -k $file ||
- error "PCC detach $file failed"
+ error "RW-PCC detach $file failed"
check_lpcc_state $file "readwrite"
# HSM released exists archived status
check_hsm_flags $file "0x0000000d"
# HSM exists archived status
check_hsm_flags $file "0x00000009"
+ echo "Verify auto attach at open for RO-PCC"
+ do_facet $SINGLEAGT $LFS pcc attach -i $HSM_ARCHIVE_NUMBER -r $file ||
+ error "RO-PCC attach $file failed"
+ check_lpcc_state $file "readonly"
+
+ # Revoke the layout lock, the PCC-cached file will be
+ # detached automatically.
+ do_facet $SINGLEAGT $LCTL \
+ set_param ldlm.namespaces.*mdc*.lru_size=clear
+ check_file_data $SINGLEAGT $file "autoattach_data"
+ check_lpcc_state $file "readonly"
+
+ # Detach the file with "-k" option, as the file layout generation
+ # is not changed, so the file is still valid cached in PCC,
+ # and can be reused from PCC cache directly.
+ do_facet $SINGLEAGT $LFS pcc detach -k $file ||
+ error "RO-PCC detach $file failed"
+ check_lpcc_state $file "readonly"
+ check_file_data $SINGLEAGT $file "autoattach_data"
+ do_facet $SINGLEAGT $LFS pcc detach $file ||
+ error "RO-PCC detach $file failed"
}
run_test 15 "Test auto attach at open when file is still valid cached"
copytool setup -m "$MOUNT" -a "$HSM_ARCHIVE_NUMBER"
setup_pcc_mapping
+ echo "Test detach for RW-PCC"
do_facet $SINGLEAGT "echo -n detach_data > $file"
lpcc_path=$(lpcc_fid2path $hsm_root $file)
do_facet $SINGLEAGT $LFS pcc attach -i $HSM_ARCHIVE_NUMBER \
- $file || error "PCC attach $file failed"
+ $file || error "RW-PCC attach $file failed"
check_lpcc_state $file "readwrite"
# HSM released exists archived status
check_hsm_flags $file "0x0000000d"
echo "Test for the default detach"
# Permanent detach by default, it will remove the PCC copy
do_facet $SINGLEAGT $LFS pcc detach $file ||
- error "PCC detach $file failed"
+ error "RW-PCC detach $file failed"
wait_request_state $(path2fid $file) REMOVE SUCCEED
check_lpcc_state $file "none"
# File is removed from PCC backend
do_facet $SINGLEAGT "[ -f $lpcc_path ]" &&
error "RW-PCC cached file '$lpcc_path' should be removed"
+ echo "Test detach for RO-PCC"
+ do_facet $SINGLEAGT $LFS pcc attach -i $HSM_ARCHIVE_NUMBER -r $file ||
+ error "RO-PCC attach $file failed"
+ check_lpcc_state $file "readonly"
+
+ do_facet $SINGLEAGT $LFS pcc detach -k $file ||
+ error "RO-PCC detach $file failed"
+ check_lpcc_state $file "readonly"
+
+ do_facet $SINGLEAGT $LFS pcc detach $file ||
+ error "RO-PCC detach $file failed"
+ check_lpcc_state $file "none"
+ do_facet $SINGLEAGT "[ -f $lpcc_path ]" &&
+ error "RO-PCC cached file '$lpcc_path' should be removed"
+
return 0
}
run_test 16 "Test detach with different options"
}
run_test 20 "Auto attach works after the inode was once evicted from cache"
+test_21a() {
+ local loopfile="$TMP/$tfile"
+ local mntpt="/mnt/pcc.$tdir"
+ local hsm_root="$mntpt/$tdir"
+ local file=$DIR/$tfile
+
+ setup_loopdev $SINGLEAGT $loopfile $mntpt 50
+ copytool setup -m "$MOUNT" -a "$HSM_ARCHIVE_NUMBER"
+ setup_pcc_mapping $SINGLEAGT \
+ "projid={100}\ rwid=$HSM_ARCHIVE_NUMBER\ auto_attach=0"
+
+ do_facet $SINGLEAGT "echo -n pccro_as_mirror_layout > $file"
+ echo "Plain layout info before PCC-RO attach '$file':"
+ $LFS getstripe -v $file
+ do_facet $SINGLEAGT $LFS pcc attach -r -i $HSM_ARCHIVE_NUMBER $file ||
+ error "RW-PCC attach $file failed"
+ check_lpcc_state $file "readonly"
+ echo -e "\nFLR layout info after PCC-RO attach '$file':"
+ $LFS getstripe -v $file
+ do_facet $SINGLEAGT $LFS pcc detach -k $file ||
+ error "failed to detach file $file"
+ check_lpcc_state $file "none"
+ echo -e "\nFLR layout info after PCC-RO detach '$file':"
+ $LFS getstripe -v $file
+
+ do_facet $SINGLEAGT $LFS pcc attach -r -i $HSM_ARCHIVE_NUMBER $file ||
+ error "failed to attach file $file"
+ check_lpcc_state $file "readonly"
+ echo -e "\nFLR layout info after RO-PCC attach $file again:"
+ $LFS getstripe -v $file
+ do_facet $SINGLEAGT $LFS pcc detach -k $file ||
+ error "failed to detach file $file"
+ check_lpcc_state $file "none"
+ echo -e "\nFLR layout info after RO-PCC detach '$file' again:"
+ $LFS getstripe -v $file
+}
+run_test 21a "PCC-RO storing as a plain HSM mirror component for plain layout"
+
+test_21b() {
+ local loopfile="$TMP/$tfile"
+ local mntpt="/mnt/pcc.$tdir"
+ local hsm_root="$mntpt/$tdir"
+ local file=$DIR/$tfile
+
+ setup_loopdev $SINGLEAGT $loopfile $mntpt 50
+ copytool setup -m "$MOUNT" -a "$HSM_ARCHIVE_NUMBER"
+ setup_pcc_mapping $SINGLEAGT \
+ "projid={100}\ rwid=$HSM_ARCHIVE_NUMBER\ auto_attach=0"
+
+ $LFS mirror create -N -S 4M -c 2 -N -S 1M -c -1 $file ||
+ error "create mirrored file $file failed"
+ #do_facet $SINGLEAGT "echo -n pccro_as_mirror_layout > $file"
+ echo "FLR layout before PCC-RO attach '$file':"
+ $LFS getstripe -v $file
+ do_facet $SINGLEAGT $LFS pcc attach -r -i $HSM_ARCHIVE_NUMBER $file ||
+ error "failed to attach file $file"
+ check_lpcc_state $file "readonly"
+ echo -e "\nFLR layout after PCC-RO attach '$file':"
+ $LFS getstripe -v $file
+ do_facet $SINGLEAGT $LFS pcc detach -k $file ||
+ error "failed to detach file $file"
+ check_lpcc_state $file "none"
+ echo -e "\nFLR layout info after PCC-RO detach '$file':"
+ $LFS getstripe -v $file
+
+ do_facet $SINGLEAGT $LFS pcc attach -r -i $HSM_ARCHIVE_NUMBER $file ||
+ error "failed to attach file $file"
+ check_lpcc_state $file "readonly"
+ echo -e "\nFLR layout after PCC-RO attach '$file' again:"
+ $LFS getstripe -v $file
+ do_facet $SINGLEAGT $LFS pcc detach -k $file ||
+ error "failed to detach file $file"
+ check_lpcc_state $file "none"
+ echo -e "\nFLR layout info after PCC-RO detach '$file':"
+ $LFS getstripe -v $file
+}
+run_test 21b "PCC-RO stroing as a plain HSM mirror component for FLR layouts"
+
+test_21c() {
+ local loopfile="$TMP/$tfile"
+ local mntpt="/mnt/pcc.$tdir"
+ local hsm_root="$mntpt/$tdir"
+ local file=$DIR/$tfile
+ local file2=$DIR2/$tfile
+ local fid
+
+ setup_loopdev $SINGLEAGT $loopfile $mntpt 50
+ copytool setup -m "$MOUNT" -a "$HSM_ARCHIVE_NUMBER"
+ setup_pcc_mapping $SINGLEAGT \
+ "projid={100}\ rwid=$HSM_ARCHIVE_NUMBER\ auto_attach=0"
+
+ do_facet $SINGLEAGT "echo -n pccro_hsm_release > $file"
+ fid=$(path2fid $file)
+ $LFS hsm_archive --archive $HSM_ARCHIVE_NUMBER $file ||
+ error "Archive $file failed"
+ wait_request_state $fid ARCHIVE SUCCEED
+ $LFS hsm_state $file
+
+ do_facet $SINGLEAGT $LFS pcc attach -i $HSM_ARCHIVE_NUMBER -r $file ||
+ error "RO-PCC attach $file failed"
+ # HSM exists archived status
+ check_hsm_flags $file "0x00000009"
+ check_lpcc_state $file "readonly"
+ check_file_data $SINGLEAGT $file "pccro_hsm_release"
+
+ $LFS hsm_release $file || error "HSM released $file failed"
+ $LFS getstripe $file
+ $LFS hsm_state $file
+ do_facet $SINGLEAGT $LFS pcc detach -k $file ||
+ error "failed to detach $file"
+ check_lpcc_state $file "none"
+ unlink $file || error "unlink $file failed"
+}
+run_test 21c "Verify HSM release works storing PCC-RO as HSM mirror component"
+
+test_21d() {
+ local loopfile="$TMP/$tfile"
+ local mntpt="/mnt/pcc.$tdir"
+ local hsm_root="$mntpt/$tdir"
+ local file=$DIR/$tfile
+
+ setup_loopdev $SINGLEAGT $loopfile $mntpt 50
+ copytool setup -m "$MOUNT" -a "$HSM_ARCHIVE_NUMBER"
+ setup_pcc_mapping
+
+ echo "pccro_init_data" > $file
+ $LFS getstripe $file
+ do_facet $SINGLEAGT $LFS pcc attach -r -i $HSM_ARCHIVE_NUMBER $file ||
+ error "failed to PCC-RO attach file $file"
+ check_lpcc_state $file "readonly"
+ echo "PCC-RO attach '$file':"
+ $LFS getstripe -v $file
+
+ echo "Write invalidated PCC-RO cache:"
+ echo -n "write_mod_data" > $file
+ check_lpcc_state $file "none"
+ $LFS getstripe -v $file
+ check_file_data $SINGLEAGT $file "write_mod_data"
+}
+run_test 21d "Write should invalidate PCC-RO caching"
+
+test_21e() {
+ local loopfile="$TMP/$tfile"
+ local mntpt="/mnt/pcc.$tdir"
+ local hsm_root="$mntpt/$tdir"
+ local file=$DIR/$tfile
+
+ setup_loopdev $SINGLEAGT $loopfile $mntpt 50
+ copytool setup -m "$MOUNT" -a "$HSM_ARCHIVE_NUMBER"
+ setup_pcc_mapping
+
+ echo "pccro_init_data" > $file
+ $LFS getstripe $file
+ do_facet $SINGLEAGT $LFS pcc attach -r -i $HSM_ARCHIVE_NUMBER $file ||
+ error "failed to PCC-RO attach file $file"
+ check_lpcc_state $file "readonly"
+ echo "PCC-RO attach '$file':"
+ $LFS getstripe -v $file
+
+ echo "Trucate invalidate PCC-RO file '$file':"
+ $TRUNCATE $file 256 || error "failed to truncate $file"
+ $LFS getstripe -v $file
+ check_lpcc_state $file "none"
+ check_file_size $SINGLEAGT $file 256
+}
+run_test 21e "Truncate should invalidate PCC-RO caching"
+
+test_21f() {
+ local loopfile="$TMP/$tfile"
+ local mntpt="/mnt/pcc.$tdir"
+ local hsm_root="$mntpt/$tdir"
+ local file=$DIR/$tfile
+
+ setup_loopdev $SINGLEAGT $loopfile $mntpt 50
+ copytool setup -m "$MOUNT" -a "$HSM_ARCHIVE_NUMBER"
+ setup_pcc_mapping
+
+ echo "pccro_mmap_data" > $file
+ $LFS getstripe $file
+ do_facet $SINGLEAGT $LFS pcc attach -r -i $HSM_ARCHIVE_NUMBER $file ||
+ error "failed to PCC-RO attach file $file"
+ check_lpcc_state $file "readonly"
+ echo "PCC-RO attach '$file':"
+ $LFS getstripe -v $file
+
+ echo "Mmap write invalidate PCC-RO caching:"
+ # Mmap write will invalidate the RO-PCC cache
+ do_facet $SINGLEAGT $MULTIOP $file OSMWUc ||
+ error "mmap write $file failed"
+ check_lpcc_state $file "none"
+ $LFS getstripe -v $file
+ # After mmap-write by MULTIOP, the first character of the content
+ # will be increased with 1.
+ content=$(do_facet $SINGLEAGT $MMAP_CAT $file)
+ [[ $content == "qccro_mmap_data" ]] ||
+ error "mmap_cat data mismatch: $content"
+}
+run_test 21f "mmap write should invalidate PCC-RO caching"
+
+test_21g() {
+ local loopfile="$TMP/$tfile"
+ local mntpt="/mnt/pcc.$tdir"
+ local hsm_root="$mntpt/$tdir"
+ local file=$DIR/$tfile
+
+ setup_loopdev $SINGLEAGT $loopfile $mntpt 50
+ copytool setup -m "$MOUNT" -a "$HSM_ARCHIVE_NUMBER"
+ setup_pcc_mapping $SINGLEAGT \
+ "projid={100}\ rwid=$HSM_ARCHIVE_NUMBER\ auto_attach=0"
+
+ $LFS mirror create -N -S 4M -c 2 -N -S 1M -c -1 $file ||
+ error "create mirrored file '$file' failed"
+ do_facet $SINGLEAGT "echo -n pccro_as_mirror_layout > $file"
+ echo "FLR layout before PCC-RO attach '$file':"
+ $LFS getstripe -v $file
+ do_facet $SINGLEAGT $LFS pcc attach -r -i $HSM_ARCHIVE_NUMBER $file ||
+ error "failed to PCC-RO attach '$file'"
+ echo "FLR layout after PCC-RO attach '$file':"
+ $LFS getstripe -v $file
+ echo "Layout after Write invalidate '$file':"
+ echo -n pccro_write_invalidate_mirror > $file
+ $LFS getstripe -v $file
+}
+run_test 21g "PCC-RO for file under FLR write pending state"
+
+test_21h() {
+ local loopfile="$TMP/$tfile"
+ local mntpt="/mnt/pcc.$tdir"
+ local hsm_root="$mntpt/$tdir"
+ local file=$DIR/$tfile
+
+ setup_loopdev $SINGLEAGT $loopfile $mntpt 50
+ copytool setup -m "$MOUNT" -a "$HSM_ARCHIVE_NUMBER"
+ setup_pcc_mapping $SINGLEAGT \
+ "projid={100}\ rwid=$HSM_ARCHIVE_NUMBER\ auto_attach=0"
+
+ $LFS mirror create -N -S 4M -c 2 -N -S 1M -c -1 $file ||
+ error "create mirrored file $file failed"
+ #do_facet $SINGLEAGT "echo -n pccro_as_mirror_layout > $file"
+ echo "FLR layout before PCC-RO attach '$file':"
+ $LFS getstripe -v $file
+ do_facet $SINGLEAGT $LFS pcc attach -r -i $HSM_ARCHIVE_NUMBER $file ||
+ error "failed to attach file $file"
+ check_lpcc_state $file "readonly"
+ echo -e "\nFLR layout after PCC-RO attach '$file':"
+ $LFS getstripe -v $file
+
+ $LFS mirror extend -N -S 8M -c -1 $file ||
+ error "mirror extend $file failed"
+ echo -e "\nFLR layout after extend a mirror:"
+ $LFS getstripe -v $file
+ $LFS pcc state $file
+ check_lpcc_state $file "none"
+
+ do_facet $SINGLEAGT $LFS pcc attach -r -i $HSM_ARCHIVE_NUMBER $file ||
+ error "failed to attach file $file"
+ check_lpcc_state $file "readonly"
+ echo -e "\nFLR layout after PCC-RO attach '$file' again:"
+ $LFS getstripe -v $file
+ do_facet $SINGLEAGT $LFS pcc detach -k $file ||
+ error "failed to detach file $file"
+ check_lpcc_state $file "none"
+}
+run_test 21h "Extend mirror once file was PCC-RO cached"
+
+test_21i() {
+ local loopfile="$TMP/$tfile"
+ local mntpt="/mnt/pcc.$tdir"
+ local hsm_root="$mntpt/$tdir"
+ local file=$DIR/$tfile
+ local file2=$DIR2/$tfile
+ local fid
+
+ setup_loopdev $SINGLEAGT $loopfile $mntpt 50
+ copytool setup -m "$MOUNT" -a "$HSM_ARCHIVE_NUMBER"
+ setup_pcc_mapping $SINGLEAGT \
+ "projid={100}\ rwid=$HSM_ARCHIVE_NUMBER\ auto_attach=0"
+
+ do_facet $SINGLEAGT "echo -n hsm_release_pcc_file > $file"
+ do_facet $SINGLEAGT $LFS pcc attach -i $HSM_ARCHIVE_NUMBER $file ||
+ error "RW-PCC attach $file failed"
+ check_lpcc_state $file "readwrite"
+ # HSM released exists archived status
+ check_hsm_flags $file "0x0000000d"
+
+ do_facet $SINGLEAGT $LFS pcc detach -k $file ||
+ error "RW-PCC detach $file failed"
+ check_lpcc_state $file "none"
+ # HSM released exists archived status
+ check_hsm_flags $file "0x0000000d"
+
+ do_facet $SINGLEAGT $LFS pcc attach -r -i $HSM_ARCHIVE_NUMBER $file ||
+ error "failed to PCC-RO attach $file"
+
+ $LFS hsm_state $file
+ $LFS hsm_release $file || error "HSM released $file failed"
+ echo "Layout after HSM release $file:"
+ $LFS getstripe -v $file
+ echo "PCC state $file:"
+ $LFS pcc state $file
+ do_facet $SINGLEAGT $LFS pcc attach -i $HSM_ARCHIVE_NUMBER -r $file ||
+ error "RO-PCC attach $file failed"
+ echo "Layout after PCC-RO attach $file again:"
+ $LFS getstripe -v $file
+ echo "PCC state:"
+ $LFS pcc state $file
+
+ do_facet $SINGLEAGT $LFS pcc detach -k $file ||
+ error "RW-PCC detach $file failed"
+ check_lpcc_state $file "none"
+}
+run_test 21i "HSM release increase layout gen, should invalidate PCC-RO cache"
+
+test_22() {
+ local loopfile="$TMP/$tfile"
+ local mntpt="/mnt/pcc.$tdir"
+ local hsm_root="$mntpt/$tdir"
+ local file=$DIR/$tfile
+ local file2=$DIR2/$tfile
+ local fid
+
+ setup_loopdev $SINGLEAGT $loopfile $mntpt 50
+ copytool setup -m "$MOUNT" -a "$HSM_ARCHIVE_NUMBER"
+ setup_pcc_mapping $SINGLEAGT \
+ "projid={100}\ rwid=$HSM_ARCHIVE_NUMBER\ auto_attach=0"
+
+ do_facet $SINGLEAGT "echo -n roattach_data > $file"
+
+ do_facet $SINGLEAGT $LFS pcc attach -i $HSM_ARCHIVE_NUMBER $file ||
+ error "RW-PCC attach $file failed"
+ check_lpcc_state $file "readwrite"
+ # HSM released exists archived status
+ check_hsm_flags $file "0x0000000d"
+
+ do_facet $SINGLEAGT $LFS pcc detach -k $file ||
+ error "RW-PCC detach $file failed"
+ check_lpcc_state $file "none"
+ # HSM released exists archived status
+ check_hsm_flags $file "0x0000000d"
+
+ do_facet $SINGLEAGT $LFS pcc attach -i $HSM_ARCHIVE_NUMBER -r $file ||
+ error "RO-PCC attach $file failed"
+ echo "Layout after PCC-RO attach $file:"
+ $LFS getstripe -v $file
+ # HSM exists archived status
+ check_hsm_flags $file "0x00000009"
+ check_lpcc_state $file "readonly"
+ check_file_data $SINGLEAGT $file "roattach_data"
+
+ $LFS hsm_release $file || error "HSM released $file failed"
+ echo "Layout after HSM release $file:"
+ $LFS getstripe -v $file
+ # HSM released exists archived status
+ check_hsm_flags $file "0x0000000d"
+ do_facet $SINGLEAGT $LFS pcc attach -i $HSM_ARCHIVE_NUMBER -r $file ||
+ error "RO-PCC attach $file failed"
+ echo "Layout after PCC-RO attach $file again:"
+ $LFS getstripe -v $file
+ check_lpcc_state $file "readonly"
+ check_file_data $SINGLEAGT $file "roattach_data"
+ do_facet $SINGLEAGT $LFS pcc detach -k $file ||
+ error "failed to detach $file"
+ echo "Layout after PCC-RO detach $file:"
+ $LFS getstripe -v $file
+ rm -f $file2 || error "rm -f $file failed"
+ do_facet $SINGLEAGT "echo -n roattach_data2 > $file"
+ fid=$(path2fid $file)
+ $LFS hsm_archive --archive $HSM_ARCHIVE_NUMBER $file ||
+ error "Archive $file failed"
+ wait_request_state $fid ARCHIVE SUCCEED
+ $LFS hsm_release $file || error "HSM released $file failed"
+ # HSM released exists archived status
+ check_hsm_flags $file "0x0000000d"
+ do_facet $SINGLEAGT $LFS pcc attach -i $HSM_ARCHIVE_NUMBER -r $file ||
+ error "RO-PCC attach $file failed"
+ check_lpcc_state $file "readonly"
+ check_file_data $SINGLEAGT $file "roattach_data2"
+ do_facet $SINGLEAGT $LFS pcc detach $file ||
+ error "RO-PCC detach $file failed"
+}
+run_test 22 "Test RO-PCC attach for the HSM released file"
+
+test_23() {
+ local loopfile="$TMP/$tfile"
+ local mntpt="/mnt/pcc.$tdir"
+ local hsm_root="$mntpt/$tdir"
+ local file=$DIR/$tfile
+ local -a lpcc_path
+
+ setup_loopdev $SINGLEAGT $loopfile $mntpt 50
+ copytool setup -m "$MOUNT" -a "$HSM_ARCHIVE_NUMBER"
+ setup_pcc_mapping
+
+ echo "ropcc_data" > $file
+ lpcc_path=$(lpcc_fid2path $hsm_root $file)
+
+ do_facet $SINGLEAGT $LFS pcc attach -r -i $HSM_ARCHIVE_NUMBER $file ||
+ error "failed to RO-PCC attach file $file"
+ check_lpcc_state $file "readonly"
+ check_lpcc_data $SINGLEAGT $lpcc_path $file "ropcc_data"
+
+ local content=$(do_facet $SINGLEAGT $MMAP_CAT $file)
+
+ [[ $content == "ropcc_data" ]] ||
+ error "mmap_cat data mismatch: $content"
+ check_lpcc_state $file "readonly"
+
+ echo -n "write_mod_data" > $file
+ echo "Write should invalidate the RO-PCC cache:"
+ $LFS getstripe -v $file
+ check_lpcc_state $file "none"
+ check_file_data $SINGLEAGT $file "write_mod_data"
+
+ do_facet $SINGLEAGT $LFS pcc attach -r -i $HSM_ARCHIVE_NUMBER $file ||
+ error "failed to RO-PCC attach file $file"
+ check_lpcc_state $file "readonly"
+ echo "PCC-RO attach '$file' again:"
+ $LFS getstripe -v $file
+
+ echo "Truncate invalidate the RO-PCC cache:"
+ $TRUNCATE $file 256 || error "failed to truncate $file"
+ $LFS getstripe -v $file
+ echo "Finish trucate operation"
+ check_lpcc_state $file "none"
+ check_file_size $SINGLEAGT $file 256
+
+ echo "Mmap write invalidates RO-PCC caching"
+ echo -n mmap_write_data > $file || error "echo write $file failed"
+ $LFS getstripe -v $file
+ do_facet $SINGLEAGT $LFS pcc attach -r -i $HSM_ARCHIVE_NUMBER $file ||
+ error "failed to RO-PCC attach file $file"
+ check_lpcc_state $file "readonly"
+ echo "PCC-RO attach '$file' again:"
+ $LFS getstripe -v $file
+ echo "Mmap write $file via multiop"
+ # Mmap write will invalidate the RO-PCC cache
+ do_facet $SINGLEAGT $MULTIOP $file OSMWUc ||
+ error "mmap write $file failed"
+ check_lpcc_state $file "none"
+ $LFS getstripe -v $file
+ # After mmap-write by MULTIOP, the first character of the content
+ # increases 1.
+ content=$(do_facet $SINGLEAGT $MMAP_CAT $file)
+ [[ $content == "nmap_write_data" ]] ||
+ error "mmap_cat data mismatch: $content"
+}
+run_test 23 "Test write/truncate/mmap-write invalidating RO-PCC caching"
+
+test_24a() {
+ local loopfile="$TMP/$tfile"
+ local mntpt="/mnt/pcc.$tdir"
+ local hsm_root="$mntpt/$tdir"
+ local file=$DIR/$tdir/$tfile
+ local -a lpcc_path
+
+ setup_loopdev $SINGLEAGT $loopfile $mntpt 50
+ copytool setup -m "$MOUNT" -a "$HSM_ARCHIVE_NUMBER"
+ setup_pcc_mapping $SINGLEAGT \
+ "projid={100}\ rwid=$HSM_ARCHIVE_NUMBER\ auto_attach=0"
+ $LCTL pcc list $MOUNT
+ mkdir -p $DIR/$tdir
+ chmod 777 $DIR/$tdir
+
+ 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 -r -i $HSM_ARCHIVE_NUMBER \
+ $file || error "failed to attach file $file"
+ check_lpcc_state $file "readonly"
+ do_facet $SINGLEAGT $RUNAS dd if=$file of=/dev/null bs=1024 count=1 ||
+ error "failed to dd read from $file"
+ check_lpcc_state $file "readonly"
+
+ do_facet $SINGLEAGT $RUNAS $LFS pcc detach -k $file ||
+ error "failed to detach file $file"
+ check_lpcc_state $file "none"
+
+ # 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 attach -r -i $HSM_ARCHIVE_NUMBER \
+ $file || error "failed to attach file $file"
+ check_lpcc_state $file "readonly"
+
+ # Test RO-PCC detach as non-root user
+ do_facet $SINGLEAGT $RUNAS $LFS pcc detach $file ||
+ error "failed to detach file $file"
+ check_lpcc_state $file "none"
+ do_facet $SINGLEAGT "[ -f $lpcc_path ]" &&
+ error "RO-PCC cached file '$lpcc_path' should be removed"
+
+ return 0
+}
+run_test 24a "Test RO-PCC with non-root user"
+
+test_24b() {
+ local loopfile="$TMP/$tfile"
+ local mntpt="/mnt/pcc.$tdir"
+ local hsm_root="$mntpt/$tdir"
+ local file=$DIR/$tdir/$tfile
+
+ setup_loopdev $SINGLEAGT $loopfile $mntpt 50
+ copytool setup -m "$MOUNT" -a "$HSM_ARCHIVE_NUMBER"
+ setup_pcc_mapping
+
+ mkdir -p $DIR/$tdir || error "mkdir $DIR/$tdir failed"
+ dd if=/dev/zero of=$file bs=1024 count=1 ||
+ error "failed to dd write $file"
+ chmod 600 $file || error "chmod 600 $file failed"
+ do_facet $SINGLEAGT $RUNAS dd if=/dev/zero of=$file bs=1024 count=1 &&
+ error "non-root user can dd write $file"
+ do_facet $SINGLEAGT $RUNAS dd if=$file of=/dev/null bs=1024 count=1 &&
+ error "non-root user can dd read $file"
+ do_facet $SINGLEAGT $LFS pcc attach -r -i $HSM_ARCHIVE_NUMBER $file ||
+ error "failed to attach file $file"
+ check_lpcc_state $file "readonly"
+ do_facet $SINGLEAGT $RUNAS dd if=/dev/zero of=$file bs=1024 count=1 &&
+ error "non-root user can dd write $file"
+ do_facet $SINGLEAGT $RUNAS dd if=$file of=/dev/null bs=1024 count=1 &&
+ error "non-root user can dd read $file"
+ chmod 777 $file || error "chmod 777 $file failed"
+ do_facet $SINGLEAGT $RUNAS dd if=$file of=/dev/null bs=1024 count=1 ||
+ error "non-root user cannot read $file with permission (777)"
+ check_lpcc_state $file "readonly"
+
+ 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 $file with permission (777)"
+}
+run_test 24b "General permission test for RO-PCC"
+
+test_25() {
+ local loopfile="$TMP/$tfile"
+ local mntpt="/mnt/pcc.$tdir"
+ local hsm_root="$mntpt/$tdir"
+ local file=$DIR/$tdir/$tfile
+ local content
+
+ setup_loopdev $SINGLEAGT $loopfile $mntpt 50
+ copytool setup -m "$MOUNT" -a "$HSM_ARCHIVE_NUMBER"
+ setup_pcc_mapping
+
+ mkdir -p $DIR/$tdir || error "mkdir $DIR/$tdir failed"
+
+ echo "ro_fake_mmap_cat_err" > $file
+ do_facet $SINGLEAGT $LFS pcc attach -r -i $HSM_ARCHIVE_NUMBER $file ||
+ error "failed to attach RO-PCC file $file"
+ check_lpcc_state $file "readonly"
+ check_file_data $SINGLEAGT $file "ro_fake_mmap_cat_err"
+
+ # define OBD_FAIL_LLITE_PCC_FAKE_ERROR 0x1411
+ do_facet $SINGLEAGT $LCTL set_param fail_loc=0x1411
+ content=$(do_facet $SINGLEAGT $MMAP_CAT $file)
+ [[ $content == "ro_fake_mmap_cat_err" ]] ||
+ error "failed to fall back to Lustre I/O path for mmap-read"
+ # Above mmap read will return VM_FAULT_SIGBUS failure and
+ # retry the IO on normal IO path.
+ check_lpcc_state $file "readonly"
+ check_file_data $SINGLEAGT $file "ro_fake_mmap_cat_err"
+
+ do_facet $SINGLEAGT $LFS pcc detach $file ||
+ error "failed to detach RO-PCC file $file"
+ check_lpcc_state $file "none"
+
+ do_facet $SINGLEAGT $LCTL set_param fail_loc=0
+ echo "ro_fake_cat_err" > $file
+ do_facet $SINGLEAGT $LFS pcc attach -r -i $HSM_ARCHIVE_NUMBER $file ||
+ error "failed to attach RO-PCC file $file"
+ check_lpcc_state $file "readonly"
+ check_file_data $SINGLEAGT $file "ro_fake_cat_err"
+
+ # define OBD_FAIL_LLITE_PCC_FAKE_ERROR 0x1411
+ do_facet $SINGLEAGT $LCTL set_param fail_loc=0x1411
+ # Fake read I/O will return -EIO failure and
+ # retry the IO on normal IO path.
+ check_file_data $SINGLEAGT $file "ro_fake_cat_err"
+ check_lpcc_state $file "readonly"
+
+ do_facet $SINGLEAGT $LFS pcc detach $file ||
+ error "failed to detach RO-PCC file $file"
+ check_lpcc_state $file "none"
+}
+run_test 25 "Tolerate fake read failure for RO-PCC"
+
+test_26() {
+ local agt_host=$(facet_active_host $SINGLEAGT)
+ local loopfile="$TMP/$tfile"
+ local mntpt="/mnt/pcc.$tdir"
+ local hsm_root="$mntpt/$tdir"
+ local file=$DIR/$tfile
+
+ setup_loopdev $SINGLEAGT $loopfile $mntpt 50
+ copytool setup -m "$MOUNT" -a "$HSM_ARCHIVE_NUMBER" -h "$hsm_root"
+ setup_pcc_mapping $SINGLEAGT \
+ "projid={100}\ rwid=$HSM_ARCHIVE_NUMBER\ auto_attach=0"
+
+ echo -n attach_keep_open > $file
+ do_facet $SINGLEAGT $LFS pcc attach -r -i $HSM_ARCHIVE_NUMBER $file ||
+ error "attach $file failed"
+ check_lpcc_state $file "readonly"
+ rmultiop_start $agt_host $file O_c || error "multiop $file failed"
+ do_facet $SINGLEAGT $LFS pcc detach -k $file ||
+ error "detach $file failed"
+ do_facet $SINGLEAGT $LFS pcc attach -r -i $HSM_ARCHIVE_NUMBER $file ||
+ error "attach $file failed"
+ check_lpcc_state $file "readonly"
+ check_file_data $SINGLEAGT $file "attach_keep_open"
+ check_lpcc_state $file "readonly"
+ do_facet $SINGLEAGT $LFS pcc detach $file ||
+ error "detach $file failed"
+ rmultiop_stop $agt_host || error "multiop $file close failed"
+
+ do_facet $SINGLEAGT $LFS pcc attach -r -i $HSM_ARCHIVE_NUMBER $file ||
+ error "attach $file failed"
+ check_lpcc_state $file "readonly"
+ rmultiop_start $agt_host $file O_c || error "multiop $file failed"
+ do_facet $SINGLEAGT $LFS pcc detach $file ||
+ error "detach $file failed"
+ do_facet $SINGLEAGT $LFS pcc attach -r -i $HSM_ARCHIVE_NUMBER $file ||
+ error "attach $file failed"
+ check_lpcc_state $file "readonly"
+ check_file_data $SINGLEAGT $file "attach_keep_open"
+ check_lpcc_state $file "readonly"
+ do_facet $SINGLEAGT $LFS pcc detach $file ||
+ error "detach $file failed"
+ rmultiop_stop $agt_host || error "multiop $file close failed"
+
+ do_facet $SINGLEAGT $LFS pcc attach -r -i $HSM_ARCHIVE_NUMBER $file ||
+ error "attach $file failed"
+ check_lpcc_state $file "readonly"
+ rmultiop_start $agt_host $file O_c || error "multiop $file failed"
+ do_facet $SINGLEAGT $LFS pcc detach $file ||
+ error "detach $file failed"
+ do_facet $SINGLEAGT $LFS pcc attach -r -i $HSM_ARCHIVE_NUMBER $file ||
+ error "attach $file failed"
+ check_lpcc_state $file "readonly"
+ check_file_data $SINGLEAGT $file "attach_keep_open"
+ check_lpcc_state $file "readonly"
+ rmultiop_stop $agt_host || error "multiop $file close failed"
+ do_facet $SINGLEAGT $LFS pcc detach $file ||
+ error "detach $file failed"
+
+ do_facet $SINGLEAGT $LFS pcc attach -i $HSM_ARCHIVE_NUMBER $file ||
+ error "attach $file failed"
+ check_lpcc_state $file "readwrite"
+ rmultiop_start $agt_host $file O_c || error "multiop $file failed"
+ do_facet $SINGLEAGT $LFS pcc detach $file ||
+ error "detach $file failed"
+ wait_request_state $(path2fid $file) REMOVE SUCCEED
+ do_facet $SINGLEAGT $LFS pcc attach -r -i $HSM_ARCHIVE_NUMBER $file ||
+ error "attach $file failed"
+ check_lpcc_state $file "readonly"
+ check_file_data $SINGLEAGT $file "attach_keep_open"
+ check_lpcc_state $file "readonly"
+ rmultiop_stop $agt_host || error "multiop $file close failed"
+ check_lpcc_state $file "readonly"
+ do_facet $SINGLEAGT $LFS pcc detach $file ||
+ error "detach $file failed"
+
+ rm $file || error "rm $file failed"
+ echo -n attach_keep_open > $file
+ do_facet $SINGLEAGT $LFS pcc attach -i $HSM_ARCHIVE_NUMBER $file ||
+ error "attach $file failed"
+ check_lpcc_state $file "readwrite"
+ rmultiop_start $agt_host $file O_c || error "multiop $file failed"
+ do_facet $SINGLEAGT $LFS pcc detach $file ||
+ error "detach $file failed"
+ wait_request_state $(path2fid $file) REMOVE SUCCEED
+ do_facet $SINGLEAGT $LFS pcc attach -r -i $HSM_ARCHIVE_NUMBER $file ||
+ error "attach $file failed"
+ check_lpcc_state $file "readonly"
+ check_file_data $SINGLEAGT $file "attach_keep_open"
+ check_lpcc_state $file "readonly"
+ do_facet $SINGLEAGT $LFS pcc detach $file ||
+ error "detach $file failed"
+ rmultiop_stop $agt_host || error "multiop $file close failed"
+ check_lpcc_state $file "none"
+}
+run_test 26 "Repeat the attach/detach when the file has multiple openers"
+
+test_27() {
+ local agt_host=$(facet_active_host $SINGLEAGT)
+ local loopfile="$TMP/$tfile"
+ local mntpt="/mnt/pcc.$tdir"
+ local hsm_root="$mntpt/$tdir"
+ local file=$DIR/$tfile
+
+ setup_loopdev $SINGLEAGT $loopfile $mntpt 50
+ copytool setup -m "$MOUNT" -a "$HSM_ARCHIVE_NUMBER" -h "$hsm_root"
+ setup_pcc_mapping $SINGLEAGT \
+ "projid={100}\ rwid=$HSM_ARCHIVE_NUMBER\ open_attach=1"
+
+ echo -n auto_attach_multi_open > $file
+ do_facet $SINGLEAGT $LFS pcc attach -i $HSM_ARCHIVE_NUMBER $file ||
+ error "attach $file failed"
+ check_lpcc_state $file "readwrite"
+ rmultiop_start $agt_host $file O_c || error "multiop $file failed"
+ do_facet $SINGLEAGT $LFS pcc detach -k $file ||
+ error "detach $file failed"
+ check_lpcc_state $file "readwrite"
+ check_file_data $SINGLEAGT $file "auto_attach_multi_open"
+ check_lpcc_state $file "readwrite"
+ do_facet $SINGLEAGT $LFS pcc detach $file ||
+ error "detach $file failed"
+ wait_request_state $(path2fid $file) REMOVE SUCCEED
+ check_lpcc_state $file "none"
+ rmultiop_stop $agt_host || error "multiop $file close failed"
+
+ rm $file || error "rm $file failed"
+ echo -n auto_attach_multi_open > $file
+ do_facet $SINGLEAGT $LFS pcc attach -i $HSM_ARCHIVE_NUMBER $file ||
+ error "attach $file failed"
+ check_lpcc_state $file "readwrite"
+ rmultiop_start $agt_host $file O_c || error "multiop $file failed"
+ do_facet $SINGLEAGT $LCTL \
+ set_param ldlm.namespaces.*mdc*.lru_size=clear
+ check_lpcc_state $file "readwrite"
+ check_file_data $SINGLEAGT $file "auto_attach_multi_open"
+ check_lpcc_state $file "readwrite"
+ do_facet $SINGLEAGT $LFS pcc detach $file ||
+ error "detach $file failed"
+ wait_request_state $(path2fid $file) REMOVE SUCCEED
+ check_lpcc_state $file "none"
+ rmultiop_stop $agt_host || error "multiop $file close failed"
+
+ do_facet $SINGLEAGT $LFS pcc attach -r -i $HSM_ARCHIVE_NUMBER $file ||
+ error "attach $file failed"
+ check_lpcc_state $file "readonly"
+ rmultiop_start $agt_host $file O_c || error "multiop $file failed"
+ do_facet $SINGLEAGT $LFS pcc detach -k $file ||
+ error "detach $file failed"
+ check_lpcc_state $file "readonly"
+ check_file_data $SINGLEAGT $file "auto_attach_multi_open"
+ check_lpcc_state $file "readonly"
+ do_facet $SINGLEAGT $LFS pcc detach $file ||
+ error "detach $file failed"
+ check_lpcc_state $file "none"
+ rmultiop_stop $agt_host || error "multiop $file close failed"
+
+ do_facet $SINGLEAGT $LFS pcc attach -r -i $HSM_ARCHIVE_NUMBER $file ||
+ error "attach $file failed"
+ check_lpcc_state $file "readonly"
+ rmultiop_start $agt_host $file O_c || error "multiop $file failed"
+ do_facet $SINGLEAGT $LCTL \
+ set_param ldlm.namespaces.*mdc*.lru_size=clear
+ check_lpcc_state $file "readonly"
+ check_file_data $SINGLEAGT $file "auto_attach_multi_open"
+ check_lpcc_state $file "readonly"
+ do_facet $SINGLEAGT $LFS pcc detach $file ||
+ error "detach $file failed"
+ check_lpcc_state $file "none"
+ rmultiop_stop $agt_host || error "multiop $file close failed"
+}
+run_test 27 "Auto attach at open when the file has multiple openers"
+
+test_28() {
+ local agt_host=$(facet_active_host $SINGLEAGT)
+ local loopfile="$TMP/$tfile"
+ local mntpt="/mnt/pcc.$tdir"
+ local hsm_root="$mntpt/$tdir"
+ local file=$DIR/$tfile
+ local file2=$DIR2/$tfile
+ local multipid
+
+ setup_loopdev $SINGLEAGT $loopfile $mntpt 50
+ copytool setup -m "$MOUNT" -a "$HSM_ARCHIVE_NUMBER" -h "$hsm_root"
+ setup_pcc_mapping $SINGLEAGT \
+ "projid={100}\ rwid=$HSM_ARCHIVE_NUMBER\ auto_attach=0"
+
+ echo -n rw_attach_hasopen_fail > $file
+ rmultiop_start $agt_host $file O_c || error "multiop $file failed"
+ do_facet $SINGLEAGT $LFS pcc attach -i $HSM_ARCHIVE_NUMBER $file &&
+ error "attach $file should fail"
+ rmultiop_stop $agt_host || error "multiop $file close failed"
+ do_facet $SINGLEAGT $LFS pcc attach -i $HSM_ARCHIVE_NUMBER $file ||
+ error "attach $file should fail"
+ check_lpcc_state $file "readwrite"
+ do_facet $SINGLEAGT $LFS pcc detach -k $file ||
+ error "detach $file failed"
+ check_lpcc_state $file "none"
+
+ multiop_bg_pause $file2 O_c || error "multiop $file2 failed"
+ multipid=$!
+ do_facet $SINGLEAGT $LFS pcc attach -i $HSM_ARCHIVE_NUMBER $file &&
+ error "attach $file should fail"
+ kill -USR1 $multipid
+ wait $multipid || error "multiop $file2 close failed"
+ do_facet $SINGLEAGT $LFS pcc attach -i $HSM_ARCHIVE_NUMBER $file ||
+ error "attach $file should fail"
+ check_lpcc_state $file "readwrite"
+ do_facet $SINGLEAGT $LFS pcc detach -k $file ||
+ error "detach $file failed"
+ check_lpcc_state $file "none"
+}
+run_test 28 "RW-PCC attach should fail when the file has cluster-wide openers"
+
#test 101: containers and PCC
#LU-15170: Test mount namespaces with PCC
#This tests the cases where the PCC mount is not present in the container by
*layout |= LOV_PATTERN_MDT;
else if (strcmp(layout_name, "overstriping") == 0)
*layout |= LOV_PATTERN_OVERSTRIPING;
+ else if (strcmp(layout_name, "foreign") == 0)
+ *layout |= LOV_PATTERN_FOREIGN;
else
return -1;
}
struct option long_opts[] = {
{ .val = 'h', .name = "help", .has_arg = no_argument },
{ .val = 'i', .name = "id", .has_arg = required_argument },
+ { .val = 'r', .name = "readonly", .has_arg = no_argument },
{ .name = NULL } };
int c;
int rc = 0;
- __u32 archive_id = 0;
+ __u32 attach_id = 0;
const char *path;
char *end;
char fullpath[PATH_MAX];
enum lu_pcc_type type = LU_PCC_READWRITE;
optind = 0;
- while ((c = getopt_long(argc, argv, "hi:",
+ while ((c = getopt_long(argc, argv, "hi:r",
long_opts, NULL)) != -1) {
switch (c) {
case 'i':
errno = 0;
- archive_id = strtoul(optarg, &end, 0);
+ attach_id = strtoul(optarg, &end, 0);
if (errno != 0 || *end != '\0' ||
- archive_id == 0 || archive_id > UINT32_MAX) {
+ attach_id == 0 || attach_id > UINT32_MAX) {
fprintf(stderr,
"error: %s: bad archive ID '%s'\n",
progname, optarg);
return CMD_HELP;
}
break;
+ case 'r':
+ type = LU_PCC_READONLY;
+ break;
+ case '?':
+ return CMD_HELP;
default:
fprintf(stderr, "%s: unrecognized option '%s'\n",
progname, argv[optind - 1]);
}
}
- if (archive_id == 0) {
+ if (attach_id == 0) {
fprintf(stderr, "%s: must specify attach ID\n", argv[0]);
return CMD_HELP;
}
continue;
}
- rc2 = llapi_pcc_attach(fullpath, archive_id, type);
+ rc2 = llapi_pcc_attach(fullpath, attach_id, type);
if (rc2 < 0) {
fprintf(stderr,
- "%s: cannot attach '%s' to PCC with archive ID '%u': %s\n",
- argv[0], path, archive_id, strerror(-rc2));
+ "%s: cannot attach '%s' to PCC with attach ID '%u': %s\n",
+ argv[0], path, attach_id, strerror(-rc2));
if (rc == 0)
rc = rc2;
}
static int lfs_pcc_attach_fid(int argc, char **argv)
{
struct option long_opts[] = {
- { .val = 'h', .name = "help", .has_arg = no_argument },
- { .val = 'i', .name = "id", .has_arg = required_argument },
- { .val = 'm', .name = "mnt", .has_arg = required_argument },
+ { .val = 'h', .name = "help", .has_arg = no_argument },
+ { .val = 'i', .name = "id", .has_arg = required_argument },
+ { .val = 'r', .name = "readonly", .has_arg = no_argument },
+ { .val = 'm', .name = "mnt", .has_arg = required_argument },
{ .name = NULL } };
int c;
int rc = 0;
- __u32 archive_id = 0;
+ __u32 attach_id = 0;
char *end;
const char *mntpath = NULL;
const char *fidstr;
enum lu_pcc_type type = LU_PCC_READWRITE;
optind = 0;
- while ((c = getopt_long(argc, argv, "hi:m:",
+ while ((c = getopt_long(argc, argv, "hi:m:r",
long_opts, NULL)) != -1) {
switch (c) {
case 'i':
errno = 0;
- archive_id = strtoul(optarg, &end, 0);
+ attach_id = strtoul(optarg, &end, 0);
if (errno != 0 || *end != '\0' ||
- archive_id > UINT32_MAX) {
+ attach_id > UINT32_MAX) {
fprintf(stderr,
- "error: %s: bad archive ID '%s'\n",
+ "error: %s: bad attach ID '%s'\n",
argv[0], optarg);
return CMD_HELP;
}
break;
+ case 'r':
+ type = LU_PCC_READONLY;
+ break;
case 'm':
mntpath = optarg;
break;
}
}
- if (archive_id == 0) {
+ if (attach_id == 0) {
fprintf(stderr, "%s: must specify an archive ID\n", argv[0]);
return CMD_HELP;
}
fidstr = argv[optind++];
rc2 = llapi_pcc_attach_fid_str(mntpath, fidstr,
- archive_id, type);
+ attach_id, type);
if (rc2 < 0) {
fprintf(stderr,
- "%s: cannot attach '%s' on '%s' to PCC with archive ID '%u': %s\n",
- argv[0], fidstr, mntpath, archive_id,
+ "%s: cannot attach '%s' on '%s' to PCC with attach ID '%u': %s\n",
+ argv[0], fidstr, mntpath, attach_id,
strerror(rc2));
}
if (rc == 0 && rc2 < 0)
const char *liblustreapi_cmd;
struct lustre_foreign_type lu_foreign_types[] = {
- {.lft_type = LU_FOREIGN_TYPE_NONE, .lft_name = "none"},
- {.lft_type = LU_FOREIGN_TYPE_SYMLINK, .lft_name = "symlink"},
+ {.lft_type = LU_FOREIGN_TYPE_NONE, .lft_name = "none"},
+ {.lft_type = LU_FOREIGN_TYPE_POSIX, .lft_name = "posix"},
+ {.lft_type = LU_FOREIGN_TYPE_PCCRW, .lft_name = "pccrw"},
+ {.lft_type = LU_FOREIGN_TYPE_PCCRO, .lft_name = "pccro"},
+ {.lft_type = LU_FOREIGN_TYPE_S3, .lft_name = "S3"},
+ {.lft_type = LU_FOREIGN_TYPE_SYMLINK, .lft_name = "symlink"},
/* must be the last element */
{.lft_type = LU_FOREIGN_TYPE_UNKNOWN, .lft_name = NULL}
/* array max dimension must be <= UINT32_MAX */
{
if (layout_pattern & LOV_PATTERN_F_RELEASED)
return "released";
+ else if (layout_pattern & LOV_PATTERN_FOREIGN)
+ return "foreign";
else if (layout_pattern == LOV_PATTERN_MDT)
return "mdt";
else if (layout_pattern == LOV_PATTERN_RAID0)
llapi_printf(LLAPI_MSG_NORMAL, "\n");
}
+static void hsm_flags2str(__u32 hsm_flags)
+{
+ bool found = false;
+ int i = 0;
+
+ if (!hsm_flags) {
+ llapi_printf(LLAPI_MSG_NORMAL, "0");
+ return;
+ }
+ for (i = 0; i < ARRAY_SIZE(hsm_flags_table); i++) {
+ if (hsm_flags & hsm_flags_table[i].hfn_flag) {
+ if (found)
+ llapi_printf(LLAPI_MSG_NORMAL, ",");
+ llapi_printf(LLAPI_MSG_NORMAL, "%s",
+ hsm_flags_table[i].hfn_name);
+ found = true;
+ }
+ }
+ if (hsm_flags) {
+ if (found)
+ llapi_printf(LLAPI_MSG_NORMAL, ",");
+ llapi_printf(LLAPI_MSG_NORMAL, "%#x", hsm_flags);
+ }
+}
+
+static uint32_t check_foreign_type(uint32_t foreign_type)
+{
+ uint32_t i;
+
+ for (i = 0; i < LU_FOREIGN_TYPE_UNKNOWN; i++) {
+ if (lu_foreign_types[i].lft_name == NULL)
+ break;
+ if (foreign_type == lu_foreign_types[i].lft_type)
+ return i;
+ }
+
+ return LU_FOREIGN_TYPE_UNKNOWN;
+}
+
+void lov_dump_hsm_lmm(void *lum, char *path, int depth,
+ enum llapi_layout_verbose verbose,
+ enum lov_dump_flags flags)
+{
+ struct lov_hsm_md *lhm = lum;
+ bool indent = flags & LDF_INDENT;
+ bool is_dir = flags & LDF_IS_DIR;
+ char *space = indent ? " " : "";
+
+ if (!is_dir) {
+ uint32_t type = check_foreign_type(lhm->lhm_type);
+
+ llapi_printf(LLAPI_MSG_NORMAL, "%slhm_magic: 0x%08X\n",
+ space, lhm->lhm_magic);
+ llapi_printf(LLAPI_MSG_NORMAL, "%slhm_pattern: hsm\n",
+ space);
+ llapi_printf(LLAPI_MSG_NORMAL, "%slhm_length: %u\n",
+ space, lhm->lhm_length);
+ llapi_printf(LLAPI_MSG_NORMAL, "%slhm_type: 0x%08X",
+ space, lhm->lhm_type);
+ if (type < LU_FOREIGN_TYPE_UNKNOWN)
+ llapi_printf(LLAPI_MSG_NORMAL, " (%s)\n",
+ lu_foreign_types[type].lft_name);
+ else
+ llapi_printf(LLAPI_MSG_NORMAL, " (unknown)\n");
+
+ llapi_printf(LLAPI_MSG_NORMAL, "%slhm_flags: ", space);
+ hsm_flags2str(lhm->lhm_flags);
+ llapi_printf(LLAPI_MSG_NORMAL, "\n");
+
+ if (!lov_hsm_type_supported(lhm->lhm_type))
+ return;
+
+ llapi_printf(LLAPI_MSG_NORMAL, "%slhm_archive_id: %llu\n",
+ space, (unsigned long long)lhm->lhm_archive_id);
+ llapi_printf(LLAPI_MSG_NORMAL, "%slhm_archive_ver: %llu\n",
+ space, (unsigned long long)lhm->lhm_archive_ver);
+ llapi_printf(LLAPI_MSG_NORMAL, "%slhm_archive_uuid: '%.*s'\n",
+ space, UUID_MAX, lhm->lhm_archive_uuid);
+ }
+}
+
static void lmv_dump_user_lmm(struct lmv_user_md *lum, char *pool_name,
char *path, int obdindex, int depth,
enum llapi_layout_verbose verbose,
continue;
v1 = lov_comp_entry(comp_v1, i);
+ if (v1->lmm_magic == LOV_MAGIC_FOREIGN)
+ continue;
+
objects = lov_v1v3_objects(v1);
for (j = 0; j < v1->lmm_stripe_count; j++) {
if (obdindex != OBD_NOT_FOUND) {
flags |= LDF_SKIP_OBJS;
v1 = lov_comp_entry(comp_v1, i);
+ if (v1->lmm_magic == LOV_MAGIC_FOREIGN)
+ continue;
+
objects = lov_v1v3_objects(v1);
for (j = 0; j < v1->lmm_stripe_count; j++) {
lov_dump_comp_v1_entry(param, flags, i);
v1 = lov_comp_entry(comp_v1, i);
- objects = lov_v1v3_objects(v1);
- lov_v1v3_pool_name(v1, pool_name);
+ if (v1->lmm_magic == LOV_MAGIC_FOREIGN) {
+ lov_dump_hsm_lmm(v1, path, param->fp_max_depth,
+ param->fp_verbose, flags);
+ } else {
+ objects = lov_v1v3_objects(v1);
+ lov_v1v3_pool_name(v1, pool_name);
- ext = entry->lcme_flags & LCME_FL_EXTENSION ? LDF_EXTENSION : 0;
- lov_dump_user_lmm_v1v3(v1, pool_name, objects, path, obdindex,
- param->fp_max_depth, param->fp_verbose,
- flags | ext);
+ ext = entry->lcme_flags & LCME_FL_EXTENSION ?
+ LDF_EXTENSION : 0;
+ lov_dump_user_lmm_v1v3(v1, pool_name, objects, path,
+ obdindex, param->fp_max_depth,
+ param->fp_verbose, flags | ext);
+ }
}
if (print_last_init_comp(param)) {
/**
lov_dump_comp_v1_entry(param, flags, i);
v1 = lov_comp_entry(comp_v1, i);
- objects = lov_v1v3_objects(v1);
- lov_v1v3_pool_name(v1, pool_name);
-
- entry = &comp_v1->lcm_entries[i];
- ext = entry->lcme_flags & LCME_FL_EXTENSION ? LDF_EXTENSION : 0;
- lov_dump_user_lmm_v1v3(v1, pool_name, objects, path, obdindex,
- param->fp_max_depth, param->fp_verbose,
- flags | ext);
+ if (v1->lmm_magic == LOV_MAGIC_FOREIGN) {
+ lov_dump_hsm_lmm(v1, path, param->fp_max_depth,
+ param->fp_verbose, flags);
+ } else {
+ objects = lov_v1v3_objects(v1);
+ lov_v1v3_pool_name(v1, pool_name);
+
+ entry = &comp_v1->lcm_entries[i];
+ ext = entry->lcme_flags & LCME_FL_EXTENSION ?
+ LDF_EXTENSION : 0;
+ lov_dump_user_lmm_v1v3(v1, pool_name, objects, path,
+ obdindex, param->fp_max_depth,
+ param->fp_verbose, flags | ext);
+ }
}
}
}
}
-static uint32_t check_foreign_type(uint32_t foreign_type)
-{
- uint32_t i;
-
- for (i = 0; i < LU_FOREIGN_TYPE_UNKNOWN; i++) {
- if (lu_foreign_types[i].lft_name == NULL)
- break;
- if (foreign_type == lu_foreign_types[i].lft_type)
- return i;
- }
-
- return LU_FOREIGN_TYPE_UNKNOWN;
-}
-
static void lov_dump_foreign_lmm(struct find_param *param, char *path,
enum lov_dump_flags flags)
{
/**
* Layout component, which contains all attributes of a plain
- * V1/V3 layout.
+ * V1/V3/FOREIGN(HSM) layout.
*/
struct llapi_layout_comp {
uint64_t llc_pattern;
- uint64_t llc_stripe_size;
- uint64_t llc_stripe_count;
- uint64_t llc_stripe_offset;
- /* Add 1 so user always gets back a null terminated string. */
- char llc_pool_name[LOV_MAXPOOLNAME + 1];
- /** Number of objects in llc_objects array if was initialized. */
- uint32_t llc_objects_count;
- struct lov_user_ost_data_v1 *llc_objects;
+ union {
+ struct { /* For plain layout. */
+ uint64_t llc_stripe_size;
+ uint64_t llc_stripe_count;
+ uint64_t llc_stripe_offset;
+ /**
+ * Add 1 so user always gets back a null terminated
+ * string.
+ */
+ char llc_pool_name[LOV_MAXPOOLNAME + 1];
+ /**
+ * Number of objects in llc_objects array if was
+ * initialized.
+ */
+ uint32_t llc_objects_count;
+ struct lov_user_ost_data_v1 *llc_objects;
+ };
+ struct { /* For FOREIGN/HSM layout. */
+ uint32_t llc_length;
+ uint32_t llc_type;
+ uint32_t llc_hsm_flags;
+ union {
+ struct lov_hsm_base llc_hsm;
+ char *llc_value;
+ };
+ };
+ };
+
/* fields used only for composite layouts */
struct lu_extent llc_extent; /* [start, end) of component */
uint32_t llc_id; /* unique ID of component */
bool llc_ondisk;
};
+#define llc_archive_id llc_hsm.lhb_archive_id
+#define llc_archive_ver llc_hsm.lhb_archive_ver
+#define llc_uuid llc_hsm.lhb_uuid
+
/**
* An Opaque data type abstracting the layout of a Lustre file.
*/
uint32_t magic;
size_t base_size;
+ if (lum->lmm_magic == __swab32(LOV_MAGIC_FOREIGN))
+ return 0;
+
if (lum_size < lov_user_md_size(0, LOV_MAGIC_V1))
return 0;
ent->lcme_offset);
lum_size = ent->lcme_size;
}
- obj_count = llapi_layout_objects_in_lum(lum, lum_size);
lum->lmm_magic = __swab32(lum->lmm_magic);
- lum->lmm_pattern = __swab32(lum->lmm_pattern);
- lum->lmm_stripe_size = __swab32(lum->lmm_stripe_size);
- lum->lmm_stripe_count = __swab16(lum->lmm_stripe_count);
- lum->lmm_stripe_offset = __swab16(lum->lmm_stripe_offset);
-
- if (lum->lmm_magic != LOV_MAGIC_V1) {
- struct lov_user_md_v3 *v3;
- v3 = (struct lov_user_md_v3 *)lum;
- lod = v3->lmm_objects;
+ if (lum->lmm_magic == LOV_MAGIC_FOREIGN) {
+ struct lov_hsm_md *lhm;
+
+ lhm = (struct lov_hsm_md *)lum;
+ lhm->lhm_length = __swab32(lhm->lhm_length);
+ lhm->lhm_type = __swab32(lhm->lhm_type);
+ lhm->lhm_flags = __swab32(lhm->lhm_flags);
+ if (!lov_hsm_type_supported(lhm->lhm_type))
+ continue;
+
+ lhm->lhm_archive_id = __swab64(lhm->lhm_archive_id);
+ lhm->lhm_archive_ver = __swab64(lhm->lhm_archive_ver);
} else {
- lod = lum->lmm_objects;
- }
+ obj_count = llapi_layout_objects_in_lum(lum, lum_size);
+
+ lum->lmm_pattern = __swab32(lum->lmm_pattern);
+ lum->lmm_stripe_size = __swab32(lum->lmm_stripe_size);
+ lum->lmm_stripe_count = __swab16(lum->lmm_stripe_count);
+ lum->lmm_stripe_offset =
+ __swab16(lum->lmm_stripe_offset);
- for (j = 0; j < obj_count; j++)
- lod[j].l_ost_idx = __swab32(lod[j].l_ost_idx);
+ if (lum->lmm_magic != LOV_MAGIC_V1) {
+ struct lov_user_md_v3 *v3;
+
+ v3 = (struct lov_user_md_v3 *)lum;
+ lod = v3->lmm_objects;
+ } else {
+ lod = lum->lmm_objects;
+ }
+
+ for (j = 0; j < obj_count; j++)
+ lod[j].l_ost_idx = __swab32(lod[j].l_ost_idx);
+ }
}
}
}
/**
+ * Allocate storage for a HSM component with \a length buffer.
+ *
+ * \retval valid pointer if allocation succeeds
+ * \retval NULL if allocate fails
+ */
+static struct llapi_layout_comp *__llapi_comp_hsm_alloc(uint32_t length)
+{
+ struct llapi_layout_comp *comp;
+
+ if (lov_foreign_md_size(length) > XATTR_SIZE_MAX) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ comp = calloc(1, sizeof(*comp));
+ if (comp == NULL) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ comp->llc_pattern = LLAPI_LAYOUT_FOREIGN;
+ comp->llc_length = length;
+ comp->llc_type = LU_FOREIGN_TYPE_UNKNOWN;
+ comp->llc_hsm_flags = 0;
+ comp->llc_archive_id = 0;
+ comp->llc_archive_ver = 0;
+ comp->llc_extent.e_start = 0;
+ comp->llc_extent.e_end = LUSTRE_EOF;
+ comp->llc_flags = 0;
+ comp->llc_id = 0;
+ INIT_LIST_HEAD(&comp->llc_list);
+
+ return comp;
+}
+
+/**
* Free memory allocated for \a comp
*
* \param[in] comp previously allocated by __llapi_comp_alloc()
*/
static void __llapi_comp_free(struct llapi_layout_comp *comp)
{
- if (comp->llc_objects != NULL)
+ if (comp->llc_pattern != LLAPI_LAYOUT_FOREIGN &&
+ comp->llc_objects != NULL) {
free(comp->llc_objects);
+ }
free(comp);
}
lum = (struct lov_user_md *)((char *)comp_v1 +
comp_v1->lcm_entries[i].lcme_offset);
lum_size = comp_v1->lcm_entries[i].lcme_size;
+
+ if (lum->lmm_magic == LOV_MAGIC_FOREIGN)
+ continue;
}
obj_count = llapi_layout_objects_in_lum(lum, lum_size);
struct lov_user_md *v1;
struct llapi_layout *layout = NULL;
struct llapi_layout_comp *comp;
- int i, ent_count = 0, obj_count;
+ int i, ent_count = 0, obj_count = 0;
if (lov_xattr == NULL || lov_xattr_size <= 0) {
errno = EINVAL;
ent = NULL;
}
- obj_count = llapi_layout_objects_in_lum(v1, lov_xattr_size);
- comp = __llapi_comp_alloc(obj_count);
- if (comp == NULL)
- goto out_layout;
+ if (v1->lmm_magic == LOV_MAGIC_FOREIGN) {
+ struct lov_hsm_md *lhm;
+
+ lhm = (struct lov_hsm_md *)v1;
+ if (!lov_hsm_type_supported(lhm->lhm_type))
+ goto out_layout;
+
+ if (lhm->lhm_length != sizeof(struct lov_hsm_base))
+ goto out_layout;
+
+ comp = __llapi_comp_hsm_alloc(lhm->lhm_length);
+ if (comp == NULL)
+ goto out_layout;
+
+ comp->llc_length = lhm->lhm_length;
+ comp->llc_type = lhm->lhm_type;
+ comp->llc_hsm_flags = lhm->lhm_flags;
+ comp->llc_archive_id = lhm->lhm_archive_id;
+ comp->llc_archive_ver = lhm->lhm_archive_ver;
+ memcpy(comp->llc_uuid, lhm->lhm_archive_uuid,
+ sizeof(comp->llc_uuid));
+ } else {
+ obj_count = llapi_layout_objects_in_lum(v1,
+ lov_xattr_size);
+ comp = __llapi_comp_alloc(obj_count);
+ if (comp == NULL)
+ goto out_layout;
+ }
if (ent != NULL) {
comp->llc_extent.e_start = ent->lcme_extent.e_start;
comp->llc_flags = 0;
}
+ if (v1->lmm_magic == LOV_MAGIC_FOREIGN) {
+ comp->llc_pattern = LLAPI_LAYOUT_FOREIGN;
+ goto comp_add;
+ }
+
if (v1->lmm_pattern == LOV_PATTERN_RAID0)
comp->llc_pattern = LLAPI_LAYOUT_RAID0;
else if (v1->lmm_pattern == (LOV_PATTERN_RAID0 |
else if (v1->lmm_pattern & LOV_PATTERN_MDT)
comp->llc_pattern = LLAPI_LAYOUT_MDT;
else
- /* Lustre only supports RAID0, overstripping
- * and DoM for now.
+ /* Lustre only supports RAID0, overstripping,
+ * DoM and FOREIGN/HSM for now.
*/
comp->llc_pattern = v1->lmm_pattern;
if (v1->lmm_magic != LOV_USER_MAGIC_V1) {
const struct lov_user_md_v3 *lumv3;
+ size_t size = sizeof(comp->llc_pool_name);
+ int rc;
+
lumv3 = (struct lov_user_md_v3 *)v1;
- snprintf(comp->llc_pool_name,
- sizeof(comp->llc_pool_name),
- "%s", lumv3->lmm_pool_name);
+ rc = snprintf(comp->llc_pool_name, size,
+ "%s", lumv3->lmm_pool_name);
+ /* Avoid GCC 7 format-truncation warning. */
+ if (rc > size)
+ comp->llc_pool_name[size - 1] = 0;
+
memcpy(comp->llc_objects, lumv3->lmm_objects,
obj_count * sizeof(lumv3->lmm_objects[0]));
} else {
if (obj_count != 0)
comp->llc_stripe_offset =
comp->llc_objects[0].l_ost_idx;
-
+comp_add:
comp->llc_ondisk = true;
list_add_tail(&comp->llc_list, &layout->llot_comp_list);
layout->llot_cur_comp = comp;
case LLAPI_LAYOUT_MDT:
lov_pattern = LOV_PATTERN_MDT;
break;
+ case LLAPI_LAYOUT_FOREIGN:
+ lov_pattern = LOV_PATTERN_FOREIGN;
+ break;
case LLAPI_LAYOUT_OVERSTRIPING:
lov_pattern = LOV_PATTERN_OVERSTRIPING | LOV_PATTERN_RAID0;
break;
return -1;
}
- *count = comp->llc_stripe_count;
+ if (comp->llc_pattern == LLAPI_LAYOUT_FOREIGN)
+ *count = 0;
+ else
+ *count = comp->llc_stripe_count;
return 0;
}
return -1;
}
+ /* FIXME: return a component rather than FOREIGN/HSM component. */
+ if (comp->llc_pattern == LLAPI_LAYOUT_FOREIGN) {
+ errno = EINVAL;
+ return -1;
+ }
+
comp_ext = comp->llc_flags & LCME_FL_EXTENSION;
if ((comp_ext && !extension) || (!comp_ext && extension)) {
errno = EINVAL;
if (comp == NULL)
return -1;
+ if (comp->llc_pattern == LLAPI_LAYOUT_FOREIGN) {
+ errno = EINVAL;
+ return -1;
+ }
+
comp_ext = comp->llc_flags & LCME_FL_EXTENSION;
if ((comp_ext && !extension) || (!comp_ext && extension)) {
errno = EINVAL;
if (pattern != LLAPI_LAYOUT_DEFAULT &&
pattern != LLAPI_LAYOUT_RAID0 && pattern != LLAPI_LAYOUT_MDT
- && pattern != LLAPI_LAYOUT_OVERSTRIPING) {
+ && pattern != LLAPI_LAYOUT_OVERSTRIPING &&
+ pattern != LLAPI_LAYOUT_FOREIGN) {
errno = EOPNOTSUPP;
return -1;
}
if (comp == NULL)
return -1;
+ if (comp->llc_pattern == LLAPI_LAYOUT_FOREIGN) {
+ errno = EINVAL;
+ return -1;
+ }
+
if (!llapi_layout_stripe_index_is_valid(ost_index)) {
errno = EINVAL;
return -1;
if (comp == NULL)
return -1;
+ if (comp->llc_pattern == LLAPI_LAYOUT_FOREIGN) {
+ errno = EINVAL;
+ return -1;
+ }
+
if (index == NULL) {
errno = EINVAL;
return -1;
return -1;
}
+ if (comp->llc_pattern == LLAPI_LAYOUT_FOREIGN) {
+ errno = EINVAL;
+ return -1;
+ }
+
strncpy(dest, comp->llc_pool_name, n);
return 0;
return -1;
}
+ if (comp->llc_pattern == LLAPI_LAYOUT_FOREIGN) {
+ errno = EINVAL;
+ return -1;
+ }
+
strncpy(comp->llc_pool_name, pool_name, sizeof(comp->llc_pool_name));
return 0;
}
return "wp";
case LCM_FL_SYNC_PENDING:
return "sp";
+ case LCM_FL_RDONLY | LCM_FL_PCC_RDONLY:
+ return "ro,pccro";
+ case LCM_FL_WRITE_PENDING | LCM_FL_PCC_RDONLY:
+ return "wp,pccro";
+ case LCM_FL_SYNC_PENDING | LCM_FL_PCC_RDONLY:
+ return "sp,pccro";
}
return "0";
LSE_START_GT_END,
LSE_ALIGN_END,
LSE_ALIGN_EXT,
+ LSE_FOREIGN_EXTENSION,
LSE_LAST,
};
"The component end must be aligned by the stripe size",
[LSE_ALIGN_EXT] =
"The extension size must be aligned by the stripe size",
+ [LSE_FOREIGN_EXTENSION] =
+ "FOREIGN components can't be extension space",
};
struct llapi_layout_sanity_args {
}
}
+ if (comp->llc_pattern == LLAPI_LAYOUT_FOREIGN ||
+ comp->llc_pattern == LOV_PATTERN_FOREIGN) {
+ /* FOREING/HSM components can't be extension components */
+ if (comp->llc_flags & LCME_FL_EXTENSION) {
+ args->lsa_rc = LSE_FOREIGN_EXTENSION;
+ goto out_err;
+ }
+ }
+
/* Extent sanity checks */
/* Must set previous component extent before adding another */
if (prev && prev->llc_extent.e_start == 0 &&
* Fetch and attach a file to readwrite PCC.
*
*/
-static int llapi_readwrite_pcc_attach_fd(int fd, __u32 archive_id)
+static int llapi_pcc_attach_rw_fd(int fd, __u32 archive_id)
{
int rc;
struct ll_ioc_lease *data;
return rc;
}
-static int llapi_readwrite_pcc_attach(const char *path, __u32 archive_id)
+static int llapi_pcc_attach_rw(const char *path, __u32 archive_id)
{
int fd;
int rc;
return rc;
}
- rc = llapi_readwrite_pcc_attach_fd(fd, archive_id);
+ rc = llapi_pcc_attach_rw_fd(fd, archive_id);
+
+ close(fd);
+ return rc;
+}
+
+static int llapi_pcc_attach_ro_fd(int fd, __u32 roid)
+{
+ struct lu_pcc_attach attach;
+ int rc;
+
+ attach.pcca_id = roid;
+ attach.pcca_type = LU_PCC_READONLY;
+ rc = ioctl(fd, LL_IOC_PCC_ATTACH, &attach);
+ if (rc) {
+ rc = -errno;
+ llapi_error(LLAPI_MSG_ERROR, rc,
+ "cannot attach the file to PCC with ID %u failed",
+ roid);
+ }
+
+ return rc;
+}
+
+static int llapi_pcc_attach_ro(const char *path, __u32 roid)
+{
+ int fd;
+ int rc;
+
+ if (strlen(path) <= 0 || path[0] != '/') {
+ rc = -EINVAL;
+ llapi_err_noerrno(LLAPI_MSG_ERROR, "invalid file path: %s",
+ path);
+ return rc;
+ }
+
+ fd = open(path, O_RDONLY);
+ if (fd < 0) {
+ rc = -errno;
+ llapi_error(LLAPI_MSG_ERROR, rc, "open file: %s failed",
+ path);
+ return rc;
+ }
+
+ rc = llapi_pcc_attach_ro_fd(fd, roid);
close(fd);
return rc;
switch (type & LU_PCC_TYPE_MASK) {
case LU_PCC_READWRITE:
- rc = llapi_readwrite_pcc_attach(path, id);
+ rc = llapi_pcc_attach_rw(path, id);
+ break;
+ case LU_PCC_READONLY:
+ rc = llapi_pcc_attach_ro(path, id);
break;
default:
rc = -EINVAL;
return rc;
}
-static int llapi_readwrite_pcc_attach_fid(const char *mntpath,
- const struct lu_fid *fid,
- __u32 id)
+static int llapi_pcc_attach_rw_fid(const char *mntpath,
+ const struct lu_fid *fid,
+ __u32 rwid)
{
int rc;
int fd;
return rc;
}
- rc = llapi_readwrite_pcc_attach_fd(fd, id);
+ rc = llapi_pcc_attach_rw_fd(fd, rwid);
+
+ close(fd);
+ return rc;
+}
+
+static int llapi_pcc_attach_ro_fid(const char *mntpath,
+ const struct lu_fid *fid,
+ __u32 roid)
+{
+ int rc;
+ int fd;
+
+ fd = llapi_open_by_fid(mntpath, fid, O_RDONLY);
+ if (fd < 0) {
+ rc = -errno;
+ llapi_error(LLAPI_MSG_ERROR, rc,
+ "llapi_open_by_fid for " DFID "failed",
+ PFID(fid));
+ return rc;
+ }
+
+ rc = llapi_pcc_attach_ro_fd(fd, roid);
close(fd);
return rc;
switch (type & LU_PCC_TYPE_MASK) {
case LU_PCC_READWRITE:
- rc = llapi_readwrite_pcc_attach_fid(mntpath, fid, id);
+ rc = llapi_pcc_attach_rw_fid(mntpath, fid, id);
+ break;
+ case LU_PCC_READONLY:
+ rc = llapi_pcc_attach_ro_fid(mntpath, fid, id);
break;
default:
rc = -EINVAL;
if (optind + 2 != argc) {
fprintf(stderr,
- "%s: must specify mount path and PCC path %d:%d\n",
- jt_cmdname(argv[0]), optind, argc);
+ "%s: must specify mount path and PCC path\n",
+ jt_cmdname(argv[0]));
return CMD_HELP;
}
optind = 1;
if (argc != 3) {
- fprintf(stderr, "%s: require 3 arguments\n",
+ fprintf(stderr, "%s: require 2 arguments\n",
jt_cmdname(argv[0]));
return CMD_HELP;
}
optind = 1;
if (argc != 2) {
- fprintf(stderr, "%s: require 2 arguments\n",
+ fprintf(stderr, "%s: require 1 arguments\n",
jt_cmdname(argv[0]));
return CMD_HELP;
}
optind = 1;
if (argc != 2) {
- fprintf(stderr, "%s: require 2 arguments\n",
+ fprintf(stderr, "%s: require 1 arguments\n",
jt_cmdname(argv[0]));
return CMD_HELP;
}