@@ -1891,6 +1891,10 @@ struct cl_io {
*/
unsigned int ci_ndelay_tried;
/**
+ * Designated mirror index for this I/O.
+ */
+ unsigned int ci_designated_mirror;
+ /**
* Number of pages owned by this IO. For invariant checking.
*/
unsigned int ci_owned_nr;
@@ -1104,6 +1104,28 @@ int ll_merge_attr(const struct lu_env *env, struct inode *inode)
return rc;
}
+/**
+ * Set designated mirror for I/O.
+ *
+ * So far only read, write, and truncated can support to issue I/O to
+ * designated mirror.
+ */
+void ll_io_set_mirror(struct cl_io *io, const struct file *file)
+{
+ struct ll_file_data *fd = LUSTRE_FPRIVATE(file);
+
+ /* FLR: disable non-delay for designated mirror I/O because obviously
+ * only one mirror is available
+ */
+ if (fd->fd_designated_mirror > 0) {
+ io->ci_ndelay = 0;
+ io->ci_designated_mirror = fd->fd_designated_mirror;
+ }
+
+ CDEBUG(D_VFSTRACE, "%s: desiginated mirror: %d\n",
+ file->f_path.dentry->d_name.name, io->ci_designated_mirror);
+}
+
static bool file_is_noatime(const struct file *file)
{
const struct vfsmount *mnt = file->f_path.mnt;
@@ -1160,6 +1182,8 @@ static void ll_io_init(struct cl_io *io, const struct file *file, int write)
* available mirror for write.
*/
io->ci_ndelay = !write;
+
+ ll_io_set_mirror(io, file);
}
static ssize_t
@@ -2976,6 +3000,16 @@ int ll_ioctl_fssetxattr(struct inode *inode, unsigned int cmd,
kfree(k_ladvise_hdr);
return rc;
}
+ case LL_IOC_FLR_SET_MIRROR: {
+ /* mirror I/O must be direct to avoid polluting page cache
+ * by stale data.
+ */
+ if (!(file->f_flags & O_DIRECT))
+ return -EINVAL;
+
+ fd->fd_designated_mirror = (u32)arg;
+ return 0;
+ }
case FS_IOC_FSGETXATTR:
return ll_ioctl_fsgetxattr(inode, cmd, arg);
case FS_IOC_FSSETXATTR:
@@ -103,6 +103,9 @@ int cl_setattr_ost(struct cl_object *obj, const struct iattr *attr,
io->u.ci_setattr.sa_xvalid = xvalid;
io->u.ci_setattr.sa_parent_fid = lu_object_fid(&obj->co_lu);
+ if (attr->ia_valid & ATTR_FILE)
+ ll_io_set_mirror(io, attr->ia_file);
+
again:
if (cl_io_init(env, io, CIT_SETATTR, io->ci_obj) == 0) {
struct vvp_io *vio = vvp_env_io(env);
@@ -653,6 +653,10 @@ struct ll_file_data {
*/
bool fd_write_failed;
bool ll_lock_no_expand;
+ /* Used by mirrored file to lead IOs to a specific mirror, usually
+ * for mirror resync. 0 means default.
+ */
+ u32 fd_designated_mirror;
rwlock_t fd_lock; /* protect lcc list */
struct list_head fd_lccs; /* list of ll_cl_context */
};
@@ -840,6 +844,7 @@ int ll_dir_getstripe(struct inode *inode, void **lmmp, int *lmm_size,
int ll_data_version(struct inode *inode, u64 *data_version, int flags);
int ll_hsm_release(struct inode *inode);
int ll_hsm_state_set(struct inode *inode, struct hsm_state_set *hss);
+void ll_io_set_mirror(struct cl_io *io, const struct file *file);
/* llite/dcache.c */
@@ -299,6 +299,27 @@ static int lov_io_mirror_init(struct lov_io *lio, struct lov_object *obj,
return 0;
}
+ /* find the corresponding mirror for designated mirror IO */
+ if (io->ci_designated_mirror > 0) {
+ struct lov_mirror_entry *entry;
+
+ LASSERT(!io->ci_ndelay);
+
+ index = 0;
+ lio->lis_mirror_index = -1;
+ lov_foreach_mirror_entry(obj, entry) {
+ if (entry->lre_mirror_id ==
+ io->ci_designated_mirror) {
+ lio->lis_mirror_index = index;
+ break;
+ }
+
+ index++;
+ }
+
+ return (lio->lis_mirror_index < 0) ? -EINVAL : 0;
+ }
+
result = lov_io_mirror_write_intent(lio, obj, io);
if (result)
return result;
@@ -998,7 +1019,11 @@ static int lov_io_submit(const struct lu_env *env,
if (lov_page_is_empty(page)) {
cl_page_list_move(&queue->c2_qout, qin, page);
- cl_page_prep(env, ios->cis_io, page, crt);
+ /* it could only be mirror read to get here therefore
+ * the pages will be transient. We don't care about
+ * the return code of cl_page_prep() at all.
+ */
+ (void) cl_page_prep(env, ios->cis_io, page, crt);
cl_page_completion(env, page, crt, 0);
continue;
}
@@ -276,7 +276,7 @@ struct ll_futimes_3 {
#define LL_IOC_GET_CONNECT_FLAGS _IOWR('f', 174, __u64 *)
#define LL_IOC_GET_MDTIDX _IOR('f', 175, int)
#define LL_IOC_FUTIMES_3 _IOWR('f', 176, struct ll_futimes_3)
-
+#define LL_IOC_FLR_SET_MIRROR _IOW('f', 177, long)
/* lustre_ioctl.h 177-210 */
#define LL_IOC_HSM_STATE_GET _IOR('f', 211, struct hsm_user_state)
#define LL_IOC_HSM_STATE_SET _IOW('f', 212, struct hsm_state_set)