return 0;
}
+static inline bool
+pcc_dataset_attach_allowed(struct pcc_dataset *dataset, enum lu_pcc_type type)
+{
+ if (type == LU_PCC_READWRITE && dataset->pccd_flags & PCC_DATASET_RWPCC)
+ return true;
+
+ if (type == LU_PCC_READONLY && dataset->pccd_flags & PCC_DATASET_ROPCC)
+ return true;
+
+ return false;
+}
+
struct pcc_dataset*
-pcc_dataset_match_get(struct pcc_super *super, struct pcc_matcher *matcher)
+pcc_dataset_match_get(struct pcc_super *super, enum lu_pcc_type type,
+ struct pcc_matcher *matcher)
{
struct pcc_dataset *dataset;
struct pcc_dataset *selected = NULL;
down_read(&super->pccs_rw_sem);
list_for_each_entry(dataset, &super->pccs_datasets, pccd_linkage) {
- if (!(dataset->pccd_flags & PCC_DATASET_RWPCC))
- continue;
-
- if (pcc_cond_match(&dataset->pccd_rule, matcher)) {
+ if (pcc_dataset_attach_allowed(dataset, type) &&
+ pcc_cond_match(&dataset->pccd_rule, matcher)) {
atomic_inc(&dataset->pccd_refcount);
selected = dataset;
break;
pccf->pccf_type = LU_PCC_NONE;
}
-static inline bool pcc_auto_attach_enabled(enum pcc_dataset_flags flags,
+static inline bool pcc_auto_attach_enabled(struct pcc_dataset *dataset,
+ enum lu_pcc_type type,
enum pcc_io_type iot)
{
- if (iot == PIT_OPEN)
- return flags & PCC_DATASET_OPEN_ATTACH;
- if (iot == PIT_GETATTR)
- return flags & PCC_DATASET_STAT_ATTACH;
- else
- return flags & PCC_DATASET_AUTO_ATTACH;
+ if (pcc_dataset_attach_allowed(dataset, type)) {
+ if (iot == PIT_OPEN)
+ return dataset->pccd_flags & PCC_DATASET_OPEN_ATTACH;
+ if (iot == PIT_GETATTR)
+ return dataset->pccd_flags & PCC_DATASET_STAT_ATTACH;
+ else
+ return dataset->pccd_flags & PCC_DATASET_AUTO_ATTACH;
+ }
+
+ return false;
}
static const char pcc_xattr_layout[] = XATTR_USER_PREFIX "PCC.layout";
down_read(&super->pccs_rw_sem);
list_for_each_entry_safe(dataset, tmp,
&super->pccs_datasets, pccd_linkage) {
- if (!pcc_auto_attach_enabled(dataset->pccd_flags, iot))
+ if (!pcc_auto_attach_enabled(dataset, type, iot))
break;
rc = pcc_try_dataset_attach(inode, gen, type, dataset, cached);
RETURN(rc);
}
+static int pcc_readonly_ioctl_attach(struct file *file,
+ struct inode *inode,
+ __u32 roid);
+
+/* Call with pcci_mutex hold */
+static int pcc_try_readonly_open_attach(struct inode *inode, struct file *file,
+ bool *cached)
+{
+ struct dentry *dentry = file->f_path.dentry;
+ struct pcc_dataset *dataset;
+ struct pcc_matcher item;
+ struct pcc_inode *pcci;
+ int rc = 0;
+
+ ENTRY;
+
+ if (!((file->f_flags & O_ACCMODE) == O_RDONLY))
+ RETURN(0);
+
+ item.pm_uid = from_kuid(&init_user_ns, current_uid());
+ item.pm_gid = from_kgid(&init_user_ns, current_gid());
+ item.pm_projid = ll_i2info(inode)->lli_projid;
+ item.pm_name = &dentry->d_name;
+ dataset = pcc_dataset_match_get(&ll_i2sbi(inode)->ll_pcc_super,
+ LU_PCC_READONLY, &item);
+ if (dataset == NULL)
+ RETURN(0);
+
+ if ((dataset->pccd_flags & PCC_DATASET_PCC_ALL) == PCC_DATASET_ROPCC) {
+ pcc_inode_unlock(inode);
+ rc = pcc_readonly_ioctl_attach(file, inode, dataset->pccd_roid);
+ pcc_inode_lock(inode);
+ pcci = ll_i2pcci(inode);
+ if (pcci && pcc_inode_has_layout(pcci))
+ *cached = true;
+ if (rc) {
+ CDEBUG(D_CACHE,
+ "Failed to try PCC-RO attach "DFID", rc = %d\n",
+ PFID(&ll_i2info(inode)->lli_fid), rc);
+ /* ignore the error during auto PCC-RO attach. */
+ rc = 0;
+ }
+ }
+
+ pcc_dataset_put(dataset);
+ RETURN(rc);
+}
+
/*
* TODO: For RW-PCC, it is desirable to store HSM info as a layout (LU-10606).
* Thus the client can get archive ID from the layout directly. When try to
if (pcc_may_auto_attach(inode, PIT_OPEN))
rc = pcc_try_auto_attach(inode, &cached, PIT_OPEN);
+ if (rc == 0 && !cached)
+ rc = pcc_try_readonly_open_attach(inode, file, &cached);
+
if (rc < 0 || !cached)
GOTO(out_unlock, rc);
ENTRY;
+#ifdef FMODE_CAN_READ
+ /* It needs to add FMODE_CAN_READ flags here, otherwise the check
+ * in kernel_read() during open() for auto PCC-RO attach will fail.
+ */
+ if ((src->f_mode & FMODE_READ) &&
+ likely(src->f_op->read || src->f_op->write_iter))
+ src->f_mode |= FMODE_CAN_READ;
+#endif
+
OBD_ALLOC_LARGE(buf, buf_len);
if (buf == NULL)
RETURN(-ENOMEM);
}
out_dataset_put:
pcc_dataset_put(dataset);
-
RETURN(rc);
}
RETURN(rc);
}
+static void pcc_readonly_attach_fini(struct inode *inode)
+{
+ pcc_inode_lock(inode);
+ ll_i2info(inode)->lli_pcc_state &= ~PCC_STATE_FL_ATTACHING;
+ pcc_inode_unlock(inode);
+}
+
static int pcc_readonly_ioctl_attach(struct file *file,
struct inode *inode,
- struct lu_pcc_attach *attach)
+ __u32 roid)
{
struct ll_sb_info *sbi = ll_i2sbi(inode);
struct pcc_super *super = ll_i2pccs(inode);
rc = pcc_layout_rdonly_set(inode, &gen);
if (rc)
- RETURN(rc);
+ GOTO(out_fini, rc);
dataset = pcc_dataset_get(&ll_s2sbi(inode->i_sb)->ll_pcc_super,
- LU_PCC_READONLY, attach->pcca_id);
+ LU_PCC_READONLY, roid);
if (dataset == NULL)
- RETURN(-ENOENT);
+ GOTO(out_fini, rc = -ENOENT);
rc = pcc_attach_data_archive(file, inode, dataset, &dentry);
if (rc)
mutex_unlock(&lli->lli_layout_mutex);
out_dataset_put:
pcc_dataset_put(dataset);
+out_fini:
+ pcc_readonly_attach_fini(inode);
RETURN(rc);
}
rc = -ENOTSUPP;
break;
case LU_PCC_READONLY:
- rc = pcc_readonly_ioctl_attach(file, inode, attach);
+ rc = pcc_readonly_ioctl_attach(file, inode,
+ attach->pcca_id);
break;
default:
rc = -EINVAL;
}
run_test 28 "RW-PCC attach should fail when the file has cluster-wide openers"
+test_29() {
+ local project_id=100
+ local agt_facet=$SINGLEAGT
+ local loopfile="$TMP/$tfile"
+ local mntpt="/mnt/pcc.$tdir"
+ local hsm_root="$mntpt/$tdir"
+ local file=$DIR/$tdir/$tfile
+ local file2=$DIR2/$tdir/$tfile
+
+ ! is_project_quota_supported &&
+ skip "project quota is not supported"
+
+ enable_project_quota
+ setup_loopdev $SINGLEAGT $loopfile $mntpt 50
+ copytool setup -m "$MOUNT" -a "$HSM_ARCHIVE_NUMBER"
+ setup_pcc_mapping $SINGLEAGT \
+ "projid={$project_id}\ rwid=$HSM_ARCHIVE_NUMBER\ ropcc=1"
+ $LCTL pcc list $MOUNT
+
+ do_facet $SINGLEAGT mkdir -p $DIR/$tdir ||
+ error "mkdir $DIR/$tdir failed"
+ do_facet $SINGLEAGT "echo -n ro_uptodate > $file" ||
+ error "failed to write $file"
+ check_lpcc_state $file "none"
+ $LFS project -sp $project_id $file ||
+ error "failed to set project for $file"
+ $LFS project -d $file
+ check_lpcc_state $file "readonly"
+ check_file_data $SINGLEAGT $file "ro_uptodate"
+
+ echo -n Update_ro_data > $file2
+ check_lpcc_state $file "readonly"
+ check_file_data $SINGLEAGT $file "Update_ro_data"
+
+ do_facet $SINGLEAGT $LFS pcc detach $file ||
+ error "failed to detach $file"
+}
+run_test 29 "Auto readonly caching on RO-PCC backend for O_RDONLY open"
+
complete $SECONDS
check_and_cleanup_lustre
exit_status