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_PCCRW)
+ return true;
+
+ if (type == LU_PCC_READONLY && dataset->pccd_flags & PCC_DATASET_PCCRO)
+ 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_PCCRW))
- 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_PCCRO) {
+ 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);
* in pcc_page_mkwrite().
*/
} else if (pcci->pcci_type == LU_PCC_READONLY) {
+ /*
+ * For async I/O engine such as libaio and io_uring, PCC read
+ * should not tolerate -EAGAIN/-EIOCBQUEUED errors, return
+ * the error code to the caller directly.
+ */
if ((iot == PIT_READ || iot == PIT_GETATTR ||
- iot == PIT_SPLICE_READ) && rc < 0 && rc != -ENOMEM)
+ iot == PIT_SPLICE_READ) && rc < 0 && rc != -ENOMEM &&
+ rc != -EAGAIN && rc != -EIOCBQUEUED)
return false;
if (iot == PIT_FAULT && (rc & VM_FAULT_SIGBUS) &&
!(rc & VM_FAULT_OOM))
ENTRY;
+#ifdef FMODE_CAN_READ
+ /* Need 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->read_iter))
+ src->f_mode |= FMODE_CAN_READ;
+#endif
+
OBD_ALLOC_LARGE(buf, buf_len);
if (buf == NULL)
RETURN(-ENOMEM);
{
const struct cred *old_cred;
struct file *pcc_filp;
+ bool direct = false;
struct path path;
ssize_t ret;
int rc;
if (rc)
GOTO(out_fput, rc);
+ /*
+ * When attach a file at file open() time with direct I/O mode, the
+ * data copy from Lustre OSTs to PCC copy in kernel will report
+ * -EFAULT error as the buffer is allocated in the kernel space, not
+ * from the user space.
+ * Thus it needs to unmask O_DIRECT flag from the file handle during
+ * data copy. After finished data copying, restore the flag in the
+ * file handle.
+ */
+ if (file->f_flags & O_DIRECT) {
+ file->f_flags &= ~O_DIRECT;
+ direct = true;
+ }
+
ret = pcc_copy_data(file, pcc_filp);
+ if (direct)
+ file->f_flags |= O_DIRECT;
if (ret < 0)
GOTO(out_fput, rc = ret);
}
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 = -EOPNOTSUPP;
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;
local mntpt=$3
local size=${4:-50}
- do_facet $facet mkdir -p $mntpt || error "mkdir -p $hsm_root failed"
+ do_facet $facet mkdir -p $mntpt || error "mkdir -p $mntpt failed"
stack_trap "do_facet $facet rm -rf $mntpt" EXIT
do_facet $facet dd if=/dev/zero of=$file bs=1M count=$size
stack_trap "do_facet $facet rm -f $file" EXIT
}
run_test 10d "Test RO-PCC with group quota on loop PCC device"
+test_usrgrp_edquot() {
+ local loopfile="$TMP/$tfile"
+ local mntpt="/mnt/pcc.$tdir"
+ local hsm_root="$mntpt/$tdir"
+ local file=$DIR/$tfile
+ local id=$RUNAS_ID
+ local ug=$1
+
+ $LCTL get_param -n mdc.*.connect_flags | grep -q pcc_ro ||
+ skip "Server does not support PCC-RO"
+
+ [[ $ug == "g" ]] && id=$RUNAS_GID
+ setup_loopdev $SINGLEAGT $loopfile $mntpt 50
+ do_facet $SINGLEAGT quotacheck -c$ug $mntpt ||
+ error "quotacheck -c$ug $mntpt failed"
+ do_facet $SINGLEAGT quotaon -$ug $mntpt ||
+ error "quotaon -$ug $mntpt failed"
+ do_facet $SINGLEAGT setquota -$ug $id 0 4096 0 0 $mntpt ||
+ error "setquota -$ug $id on $mntpt failed"
+ do_facet $SINGLEAGT repquota -${ug}vs $mntpt
+ do_facet $SINGLEAGT mkdir $hsm_root || error "mkdir $hsm_root failed"
+ setup_pcc_mapping $SINGLEAGT \
+ "${ug}id={$id}\ roid=$HSM_ARCHIVE_NUMBER\ pccro=1"
+ do_facet $SINGLEAGT $LCTL pcc list $MOUNT
+
+ dd if=/dev/zero of=$file bs=1M count=2 ||
+ error "dd write $file failed"
+ chown $RUNAS_ID:$RUNAS_GID $file ||
+ error "chown $RUNAS_ID:$RUNAS_GID $file failed"
+ do_facet $SINGLEAGT $RUNAS dd if=$file of=/dev/null bs=1M count=2 ||
+ error "dd read $file failed"
+ check_lpcc_state $file "readonly"
+ $LFS getstripe -v $file
+ do_facet $SINGLEAGT dd if=/dev/zero of=$file bs=1M count=5 ||
+ error "dd write $file failed"
+ check_lpcc_state $file "none"
+ do_facet $SINGLEAGT $RUNAS dd if=$file of=/dev/null bs=1M count=5 ||
+ error "dd read $file failed"
+ do_facet $SINGLEAGT $LFS pcc state $file
+ $LFS getstripe -v $file
+ do_facet $SINGLEAGT $LFS pcc attach -r -i $HSM_ARCHIVE_NUMBER $file ||
+ error "PCC-RO attach $file failed"
+
+ do_facet $SINGLEAGT $LFS pcc detach $file || error "detach $file failed"
+}
+
+test_10e() {
+ test_usrgrp_edquot "u"
+}
+run_test 10e "Tolerate -EDQUOT failure when auto PCC-RO attach with user quota"
+
+test_10f() {
+ test_usrgrp_edquot "g"
+}
+run_test 10f "Tolerate -EDQUOT failure when auto PCC-RO attach with group quota"
+
test_11() {
local loopfile="$TMP/$tfile"
local mntpt="/mnt/pcc.$tdir"
}
run_test 28 "RW-PCC attach should fail when the file has cluster-wide openers"
+test_29a() {
+ 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
+
+ $LCTL get_param -n mdc.*.connect_flags | grep -q pcc_ro ||
+ skip "Server does not support PCC-RO"
+
+ is_project_quota_supported || skip "project quota is not supported"
+
+ 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\ pccro=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 29a "Auto readonly caching on RO-PCC backend for O_RDONLY open"
+
+test_29b() {
+ local loopfile="$TMP/$tfile"
+ local mntpt="/mnt/pcc.$tdir"
+ local hsm_root="$mntpt/$tdir"
+ local file=$DIR/myfile.dat
+
+ $LCTL get_param -n mdc.*.connect_flags | grep -q pcc_ro ||
+ skip "Server does not support PCC-RO"
+
+ setup_loopdev $SINGLEAGT $loopfile $mntpt 50
+ do_facet $SINGLEAGT mkdir $hsm_root || error "mkdir $hsm_root failed"
+ setup_pcc_mapping $SINGLEAGT \
+ "fname={*.dat}\ roid=$HSM_ARCHIVE_NUMBER\ pccro=1"
+ do_facet $SINGLEAGT $LCTL pcc list $MOUNT
+
+ do_facet $SINGLEAGT dd if=/dev/zero of=$file bs=4k count=1 ||
+ error "Write $file failed"
+ do_facet $SINGLEAGT dd if=$file of=/dev/null bs=4k count=1 ||
+ error "Read $file failed"
+ do_facet $SINGLEAGT $LFS pcc state $file
+ check_lpcc_state $file "readonly"
+ do_facet $SINGLEAGT dd if=/dev/zero of=$file bs=4k count=1 ||
+ error "Write $file failed"
+ sysctl vm.drop_caches=3
+ do_facet $SINGLEAGT dd if=$file of=/dev/null bs=4k count=1 ||
+ error "Read $file failed"
+ do_facet $SINGLEAGT $LFS pcc state $file
+ check_lpcc_state $file "readonly"
+
+ do_facet $SINGLEAGT $LFS pcc detach $file || error "detach $file failed"
+}
+run_test 29b "Auto PCC-RO attach in atomic_open"
+
#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