Commit d442670c authored by Jonathan Curley's avatar Jonathan Curley Committed by Anna Schumaker
Browse files

NFSv4/flexfiles: Add data structure support for striped layouts



Adds a new struct nfs4_ff_layout_ds_stripe that represents a data
server stripe within a layout. A new dynamically allocated array of
this type has been added to nfs4_ff_layout_mirror and per stripe
configuration information has been moved from the mirror type to the
stripe based on the RFC.

Signed-off-by: default avatarJonathan Curley <jcurley@purestorage.com>
Signed-off-by: default avatarAnna Schumaker <anna.schumaker@oracle.com>
parent eb71428e
Loading
Loading
Loading
Loading
+73 −61
Original line number Diff line number Diff line
@@ -171,7 +171,7 @@ ff_local_open_fh(struct pnfs_layout_segment *lseg, u32 ds_idx,
#if IS_ENABLED(CONFIG_NFS_LOCALIO)
	struct nfs4_ff_layout_mirror *mirror = FF_LAYOUT_COMP(lseg, ds_idx);

	return nfs_local_open_fh(clp, cred, fh, &mirror->nfl, mode);
	return nfs_local_open_fh(clp, cred, fh, &mirror->dss[0].nfl, mode);
#else
	return NULL;
#endif
@@ -182,13 +182,13 @@ static bool ff_mirror_match_fh(const struct nfs4_ff_layout_mirror *m1,
{
	int i, j;

	if (m1->fh_versions_cnt != m2->fh_versions_cnt)
	if (m1->dss[0].fh_versions_cnt != m2->dss[0].fh_versions_cnt)
		return false;
	for (i = 0; i < m1->fh_versions_cnt; i++) {
	for (i = 0; i < m1->dss[0].fh_versions_cnt; i++) {
		bool found_fh = false;
		for (j = 0; j < m2->fh_versions_cnt; j++) {
			if (nfs_compare_fh(&m1->fh_versions[i],
					&m2->fh_versions[j]) == 0) {
		for (j = 0; j < m2->dss[0].fh_versions_cnt; j++) {
			if (nfs_compare_fh(&m1->dss[0].fh_versions[i],
					&m2->dss[0].fh_versions[j]) == 0) {
				found_fh = true;
				break;
			}
@@ -209,7 +209,8 @@ ff_layout_add_mirror(struct pnfs_layout_hdr *lo,

	spin_lock(&inode->i_lock);
	list_for_each_entry(pos, &ff_layout->mirrors, mirrors) {
		if (memcmp(&mirror->devid, &pos->devid, sizeof(pos->devid)) != 0)
		if (memcmp(&mirror->dss[0].devid, &pos->dss[0].devid,
			   sizeof(pos->dss[0].devid)) != 0)
			continue;
		if (!ff_mirror_match_fh(mirror, pos))
			continue;
@@ -246,7 +247,7 @@ static struct nfs4_ff_layout_mirror *ff_layout_alloc_mirror(gfp_t gfp_flags)
		spin_lock_init(&mirror->lock);
		refcount_set(&mirror->ref, 1);
		INIT_LIST_HEAD(&mirror->mirrors);
		nfs_localio_file_init(&mirror->nfl);
		nfs_localio_file_init(&mirror->dss[0].nfl);
	}
	return mirror;
}
@@ -254,15 +255,19 @@ static struct nfs4_ff_layout_mirror *ff_layout_alloc_mirror(gfp_t gfp_flags)
static void ff_layout_free_mirror(struct nfs4_ff_layout_mirror *mirror)
{
	const struct cred	*cred;
	int dss_id = 0;

	ff_layout_remove_mirror(mirror);
	kfree(mirror->fh_versions);
	nfs_close_local_fh(&mirror->nfl);
	cred = rcu_access_pointer(mirror->ro_cred);

	kfree(mirror->dss[dss_id].fh_versions);
	nfs_close_local_fh(&mirror->dss[dss_id].nfl);
	cred = rcu_access_pointer(mirror->dss[dss_id].ro_cred);
	put_cred(cred);
	cred = rcu_access_pointer(mirror->rw_cred);
	cred = rcu_access_pointer(mirror->dss[dss_id].rw_cred);
	put_cred(cred);
	nfs4_ff_layout_put_deviceid(mirror->mirror_ds);
	nfs4_ff_layout_put_deviceid(mirror->dss[dss_id].mirror_ds);

	kfree(mirror->dss);
	kfree(mirror);
}

@@ -372,8 +377,8 @@ static void ff_layout_sort_mirrors(struct nfs4_ff_layout_segment *fls)

	for (i = 0; i < fls->mirror_array_cnt - 1; i++) {
		for (j = i + 1; j < fls->mirror_array_cnt; j++)
			if (fls->mirror_array[i]->efficiency <
			    fls->mirror_array[j]->efficiency)
			if (fls->mirror_array[i]->dss[0].efficiency <
			    fls->mirror_array[j]->dss[0].efficiency)
				swap(fls->mirror_array[i],
				     fls->mirror_array[j]);
	}
@@ -427,23 +432,25 @@ ff_layout_alloc_lseg(struct pnfs_layout_hdr *lh,
	fls->mirror_array_cnt = mirror_array_cnt;
	fls->stripe_unit = stripe_unit;

	u32 dss_count = 0;
	for (i = 0; i < fls->mirror_array_cnt; i++) {
		struct nfs4_ff_layout_mirror *mirror;
		struct cred *kcred;
		const struct cred __rcu *cred;
		kuid_t uid;
		kgid_t gid;
		u32 ds_count, fh_count, id;
		int j;
		u32 fh_count, id;
		int j, dss_id = 0;

		rc = -EIO;
		p = xdr_inline_decode(&stream, 4);
		if (!p)
			goto out_err_free;
		ds_count = be32_to_cpup(p);

		dss_count = be32_to_cpup(p);

		/* FIXME: allow for striping? */
		if (ds_count != 1)
		if (dss_count != 1)
			goto out_err_free;

		fls->mirror_array[i] = ff_layout_alloc_mirror(gfp_flags);
@@ -452,10 +459,13 @@ ff_layout_alloc_lseg(struct pnfs_layout_hdr *lh,
			goto out_err_free;
		}

		fls->mirror_array[i]->ds_count = ds_count;
		fls->mirror_array[i]->dss_count = dss_count;
		fls->mirror_array[i]->dss =
		    kcalloc(dss_count, sizeof(struct nfs4_ff_layout_ds_stripe),
			    gfp_flags);

		/* deviceid */
		rc = decode_deviceid(&stream, &fls->mirror_array[i]->devid);
		rc = decode_deviceid(&stream, &fls->mirror_array[i]->dss[dss_id].devid);
		if (rc)
			goto out_err_free;

@@ -464,10 +474,10 @@ ff_layout_alloc_lseg(struct pnfs_layout_hdr *lh,
		p = xdr_inline_decode(&stream, 4);
		if (!p)
			goto out_err_free;
		fls->mirror_array[i]->efficiency = be32_to_cpup(p);
		fls->mirror_array[i]->dss[dss_id].efficiency = be32_to_cpup(p);

		/* stateid */
		rc = decode_pnfs_stateid(&stream, &fls->mirror_array[i]->stateid);
		rc = decode_pnfs_stateid(&stream, &fls->mirror_array[i]->dss[dss_id].stateid);
		if (rc)
			goto out_err_free;

@@ -478,22 +488,22 @@ ff_layout_alloc_lseg(struct pnfs_layout_hdr *lh,
			goto out_err_free;
		fh_count = be32_to_cpup(p);

		fls->mirror_array[i]->fh_versions =
		fls->mirror_array[i]->dss[dss_id].fh_versions =
		    kcalloc(fh_count, sizeof(struct nfs_fh),
			    gfp_flags);
		if (fls->mirror_array[i]->fh_versions == NULL) {
		if (fls->mirror_array[i]->dss[dss_id].fh_versions == NULL) {
			rc = -ENOMEM;
			goto out_err_free;
		}

		for (j = 0; j < fh_count; j++) {
			rc = decode_nfs_fh(&stream,
					   &fls->mirror_array[i]->fh_versions[j]);
					   &fls->mirror_array[i]->dss[dss_id].fh_versions[j]);
			if (rc)
				goto out_err_free;
		}

		fls->mirror_array[i]->fh_versions_cnt = fh_count;
		fls->mirror_array[i]->dss[dss_id].fh_versions_cnt = fh_count;

		/* user */
		rc = decode_name(&stream, &id);
@@ -524,19 +534,21 @@ ff_layout_alloc_lseg(struct pnfs_layout_hdr *lh,
		cred = RCU_INITIALIZER(kcred);

		if (lgr->range.iomode == IOMODE_READ)
			rcu_assign_pointer(fls->mirror_array[i]->ro_cred, cred);
			rcu_assign_pointer(fls->mirror_array[i]->dss[dss_id].ro_cred, cred);
		else
			rcu_assign_pointer(fls->mirror_array[i]->rw_cred, cred);
			rcu_assign_pointer(fls->mirror_array[i]->dss[dss_id].rw_cred, cred);

		mirror = ff_layout_add_mirror(lh, fls->mirror_array[i]);
		if (mirror != fls->mirror_array[i]) {
			/* swap cred ptrs so free_mirror will clean up old */
			if (lgr->range.iomode == IOMODE_READ) {
				cred = xchg(&mirror->ro_cred, fls->mirror_array[i]->ro_cred);
				rcu_assign_pointer(fls->mirror_array[i]->ro_cred, cred);
				cred = xchg(&mirror->dss[dss_id].ro_cred,
					    fls->mirror_array[i]->dss[dss_id].ro_cred);
				rcu_assign_pointer(fls->mirror_array[i]->dss[dss_id].ro_cred, cred);
			} else {
				cred = xchg(&mirror->rw_cred, fls->mirror_array[i]->rw_cred);
				rcu_assign_pointer(fls->mirror_array[i]->rw_cred, cred);
				cred = xchg(&mirror->dss[dss_id].rw_cred,
					    fls->mirror_array[i]->dss[dss_id].rw_cred);
				rcu_assign_pointer(fls->mirror_array[i]->dss[dss_id].rw_cred, cred);
			}
			ff_layout_free_mirror(fls->mirror_array[i]);
			fls->mirror_array[i] = mirror;
@@ -624,8 +636,8 @@ nfs4_ff_layoutstat_start_io(struct nfs4_ff_layout_mirror *mirror,
	struct nfs4_flexfile_layout *ffl = FF_LAYOUT_FROM_HDR(mirror->layout);

	nfs4_ff_start_busy_timer(&layoutstat->busy_timer, now);
	if (!mirror->start_time)
		mirror->start_time = now;
	if (!mirror->dss[0].start_time)
		mirror->dss[0].start_time = now;
	if (mirror->report_interval != 0)
		report_interval = (s64)mirror->report_interval * 1000LL;
	else if (layoutstats_timer != 0)
@@ -680,8 +692,8 @@ nfs4_ff_layout_stat_io_start_read(struct inode *inode,
	bool report;

	spin_lock(&mirror->lock);
	report = nfs4_ff_layoutstat_start_io(mirror, &mirror->read_stat, now);
	nfs4_ff_layout_stat_io_update_requested(&mirror->read_stat, requested);
	report = nfs4_ff_layoutstat_start_io(mirror, &mirror->dss[0].read_stat, now);
	nfs4_ff_layout_stat_io_update_requested(&mirror->dss[0].read_stat, requested);
	set_bit(NFS4_FF_MIRROR_STAT_AVAIL, &mirror->flags);
	spin_unlock(&mirror->lock);

@@ -696,7 +708,7 @@ nfs4_ff_layout_stat_io_end_read(struct rpc_task *task,
		__u64 completed)
{
	spin_lock(&mirror->lock);
	nfs4_ff_layout_stat_io_update_completed(&mirror->read_stat,
	nfs4_ff_layout_stat_io_update_completed(&mirror->dss[0].read_stat,
			requested, completed,
			ktime_get(), task->tk_start);
	set_bit(NFS4_FF_MIRROR_STAT_AVAIL, &mirror->flags);
@@ -711,8 +723,8 @@ nfs4_ff_layout_stat_io_start_write(struct inode *inode,
	bool report;

	spin_lock(&mirror->lock);
	report = nfs4_ff_layoutstat_start_io(mirror , &mirror->write_stat, now);
	nfs4_ff_layout_stat_io_update_requested(&mirror->write_stat, requested);
	report = nfs4_ff_layoutstat_start_io(mirror, &mirror->dss[0].write_stat, now);
	nfs4_ff_layout_stat_io_update_requested(&mirror->dss[0].write_stat, requested);
	set_bit(NFS4_FF_MIRROR_STAT_AVAIL, &mirror->flags);
	spin_unlock(&mirror->lock);

@@ -731,7 +743,7 @@ nfs4_ff_layout_stat_io_end_write(struct rpc_task *task,
		requested = completed = 0;

	spin_lock(&mirror->lock);
	nfs4_ff_layout_stat_io_update_completed(&mirror->write_stat,
	nfs4_ff_layout_stat_io_update_completed(&mirror->dss[0].write_stat,
			requested, completed, ktime_get(), task->tk_start);
	set_bit(NFS4_FF_MIRROR_STAT_AVAIL, &mirror->flags);
	spin_unlock(&mirror->lock);
@@ -773,7 +785,7 @@ ff_layout_choose_ds_for_read(struct pnfs_layout_segment *lseg,
			continue;

		if (check_device &&
		    nfs4_test_deviceid_unavailable(&mirror->mirror_ds->id_node)) {
		    nfs4_test_deviceid_unavailable(&mirror->dss[0].mirror_ds->id_node)) {
			// reinitialize the error state in case if this is the last iteration
			ds = ERR_PTR(-EINVAL);
			continue;
@@ -882,7 +894,7 @@ ff_layout_pg_init_read(struct nfs_pageio_descriptor *pgio,

	mirror = FF_LAYOUT_COMP(pgio->pg_lseg, ds_idx);
	pgm = &pgio->pg_mirrors[0];
	pgm->pg_bsize = mirror->mirror_ds->ds_versions[0].rsize;
	pgm->pg_bsize = mirror->dss[0].mirror_ds->ds_versions[0].rsize;

	pgio->pg_mirror_idx = ds_idx;
	return;
@@ -954,7 +966,7 @@ ff_layout_pg_init_write(struct nfs_pageio_descriptor *pgio,
			goto retry;
		}
		pgm = &pgio->pg_mirrors[i];
		pgm->pg_bsize = mirror->mirror_ds->ds_versions[0].wsize;
		pgm->pg_bsize = mirror->dss[0].mirror_ds->ds_versions[0].wsize;
	}

	if (NFS_SERVER(pgio->pg_inode)->flags &
@@ -2032,7 +2044,7 @@ select_ds_fh_from_commit(struct pnfs_layout_segment *lseg, u32 i)
	/* FIXME: Assume that there is only one NFS version available
	 * for the DS.
	 */
	return &flseg->mirror_array[i]->fh_versions[0];
	return &flseg->mirror_array[i]->dss[0].fh_versions[0];
}

static int ff_layout_initiate_commit(struct nfs_commit_data *data, int how)
@@ -2148,10 +2160,10 @@ static void ff_layout_cancel_io(struct pnfs_layout_segment *lseg)

	for (idx = 0; idx < flseg->mirror_array_cnt; idx++) {
		mirror = flseg->mirror_array[idx];
		mirror_ds = mirror->mirror_ds;
		mirror_ds = mirror->dss[0].mirror_ds;
		if (IS_ERR_OR_NULL(mirror_ds))
			continue;
		ds = mirror->mirror_ds->ds;
		ds = mirror->dss[0].mirror_ds->ds;
		if (!ds)
			continue;
		ds_clp = ds->ds_clp;
@@ -2552,8 +2564,8 @@ ff_layout_encode_ff_layoutupdate(struct xdr_stream *xdr,
			      struct nfs4_ff_layout_mirror *mirror)
{
	struct nfs4_pnfs_ds_addr *da;
	struct nfs4_pnfs_ds *ds = mirror->mirror_ds->ds;
	struct nfs_fh *fh = &mirror->fh_versions[0];
	struct nfs4_pnfs_ds *ds = mirror->dss[0].mirror_ds->ds;
	struct nfs_fh *fh = &mirror->dss[0].fh_versions[0];
	__be32 *p;

	da = list_first_entry(&ds->ds_addrs, struct nfs4_pnfs_ds_addr, da_node);
@@ -2566,12 +2578,12 @@ ff_layout_encode_ff_layoutupdate(struct xdr_stream *xdr,
	xdr_encode_opaque(p, fh->data, fh->size);
	/* ff_io_latency4 read */
	spin_lock(&mirror->lock);
	ff_layout_encode_io_latency(xdr, &mirror->read_stat.io_stat);
	ff_layout_encode_io_latency(xdr, &mirror->dss[0].read_stat.io_stat);
	/* ff_io_latency4 write */
	ff_layout_encode_io_latency(xdr, &mirror->write_stat.io_stat);
	ff_layout_encode_io_latency(xdr, &mirror->dss[0].write_stat.io_stat);
	spin_unlock(&mirror->lock);
	/* nfstime4 */
	ff_layout_encode_nfstime(xdr, ktime_sub(ktime_get(), mirror->start_time));
	ff_layout_encode_nfstime(xdr, ktime_sub(ktime_get(), mirror->dss[0].start_time));
	/* bool */
	p = xdr_reserve_space(xdr, 4);
	*p = cpu_to_be32(false);
@@ -2618,7 +2630,7 @@ ff_layout_mirror_prepare_stats(struct pnfs_layout_hdr *lo,
	list_for_each_entry(mirror, &ff_layout->mirrors, mirrors) {
		if (i >= dev_limit)
			break;
		if (IS_ERR_OR_NULL(mirror->mirror_ds))
		if (IS_ERR_OR_NULL(mirror->dss[0].mirror_ds))
			continue;
		if (!test_and_clear_bit(NFS4_FF_MIRROR_STAT_AVAIL,
					&mirror->flags) &&
@@ -2627,15 +2639,15 @@ ff_layout_mirror_prepare_stats(struct pnfs_layout_hdr *lo,
		/* mirror refcount put in cleanup_layoutstats */
		if (!refcount_inc_not_zero(&mirror->ref))
			continue;
		dev = &mirror->mirror_ds->id_node; 
		dev = &mirror->dss[0].mirror_ds->id_node;
		memcpy(&devinfo->dev_id, &dev->deviceid, NFS4_DEVICEID4_SIZE);
		devinfo->offset = 0;
		devinfo->length = NFS4_MAX_UINT64;
		spin_lock(&mirror->lock);
		devinfo->read_count = mirror->read_stat.io_stat.ops_completed;
		devinfo->read_bytes = mirror->read_stat.io_stat.bytes_completed;
		devinfo->write_count = mirror->write_stat.io_stat.ops_completed;
		devinfo->write_bytes = mirror->write_stat.io_stat.bytes_completed;
		devinfo->read_count = mirror->dss[0].read_stat.io_stat.ops_completed;
		devinfo->read_bytes = mirror->dss[0].read_stat.io_stat.bytes_completed;
		devinfo->write_count = mirror->dss[0].write_stat.io_stat.ops_completed;
		devinfo->write_bytes = mirror->dss[0].write_stat.io_stat.bytes_completed;
		spin_unlock(&mirror->lock);
		devinfo->layout_type = LAYOUT_FLEX_FILES;
		devinfo->ld_private.ops = &layoutstat_ops;
+17 −10
Original line number Diff line number Diff line
@@ -71,12 +71,12 @@ struct nfs4_ff_layoutstat {
	struct nfs4_ff_busy_timer busy_timer;
};

struct nfs4_ff_layout_mirror {
	struct pnfs_layout_hdr		*layout;
	struct list_head		mirrors;
	u32				ds_count;
	u32				efficiency;
struct nfs4_ff_layout_mirror;

struct nfs4_ff_layout_ds_stripe {
	struct nfs4_ff_layout_mirror   *mirror;
	struct nfs4_deviceid		devid;
	u32				efficiency;
	struct nfs4_ff_layout_ds	*mirror_ds;
	u32				fh_versions_cnt;
	struct nfs_fh			*fh_versions;
@@ -84,12 +84,19 @@ struct nfs4_ff_layout_mirror {
	const struct cred __rcu		*ro_cred;
	const struct cred __rcu		*rw_cred;
	struct nfs_file_localio		nfl;
	refcount_t			ref;
	spinlock_t			lock;
	unsigned long			flags;
	struct nfs4_ff_layoutstat	read_stat;
	struct nfs4_ff_layoutstat	write_stat;
	ktime_t				start_time;
};

struct nfs4_ff_layout_mirror {
	struct pnfs_layout_hdr		*layout;
	struct list_head		mirrors;
	u32				dss_count;
	struct nfs4_ff_layout_ds_stripe *dss;
	refcount_t			ref;
	spinlock_t			lock;
	unsigned long			flags;
	u32				report_interval;
};

@@ -155,7 +162,7 @@ FF_LAYOUT_DEVID_NODE(struct pnfs_layout_segment *lseg, u32 idx)
	struct nfs4_ff_layout_mirror *mirror = FF_LAYOUT_COMP(lseg, idx);

	if (mirror != NULL) {
		struct nfs4_ff_layout_ds *mirror_ds = mirror->mirror_ds;
		struct nfs4_ff_layout_ds *mirror_ds = mirror->dss[0].mirror_ds;

		if (!IS_ERR_OR_NULL(mirror_ds))
			return &mirror_ds->id_node;
@@ -184,7 +191,7 @@ ff_layout_no_read_on_rw(struct pnfs_layout_segment *lseg)
static inline int
nfs4_ff_layout_ds_version(const struct nfs4_ff_layout_mirror *mirror)
{
	return mirror->mirror_ds->ds_versions[0].version;
	return mirror->dss[0].mirror_ds->ds_versions[0].version;
}

struct nfs4_ff_layout_ds *
+27 −27
Original line number Diff line number Diff line
@@ -259,7 +259,7 @@ int ff_layout_track_ds_error(struct nfs4_flexfile_layout *flo,
	if (status == 0)
		return 0;

	if (IS_ERR_OR_NULL(mirror->mirror_ds))
	if (IS_ERR_OR_NULL(mirror->dss[0].mirror_ds))
		return -EINVAL;

	dserr = kmalloc(sizeof(*dserr), gfp_flags);
@@ -271,8 +271,8 @@ int ff_layout_track_ds_error(struct nfs4_flexfile_layout *flo,
	dserr->length = length;
	dserr->status = status;
	dserr->opnum = opnum;
	nfs4_stateid_copy(&dserr->stateid, &mirror->stateid);
	memcpy(&dserr->deviceid, &mirror->mirror_ds->id_node.deviceid,
	nfs4_stateid_copy(&dserr->stateid, &mirror->dss[0].stateid);
	memcpy(&dserr->deviceid, &mirror->dss[0].mirror_ds->id_node.deviceid,
	       NFS4_DEVICEID4_SIZE);

	spin_lock(&flo->generic_hdr.plh_inode->i_lock);
@@ -287,9 +287,9 @@ ff_layout_get_mirror_cred(struct nfs4_ff_layout_mirror *mirror, u32 iomode)
	const struct cred *cred, __rcu **pcred;

	if (iomode == IOMODE_READ)
		pcred = &mirror->ro_cred;
		pcred = &mirror->dss[0].ro_cred;
	else
		pcred = &mirror->rw_cred;
		pcred = &mirror->dss[0].rw_cred;

	rcu_read_lock();
	do {
@@ -307,7 +307,7 @@ struct nfs_fh *
nfs4_ff_layout_select_ds_fh(struct nfs4_ff_layout_mirror *mirror)
{
	/* FIXME: For now assume there is only 1 version available for the DS */
	return &mirror->fh_versions[0];
	return &mirror->dss[0].fh_versions[0];
}

void
@@ -315,7 +315,7 @@ nfs4_ff_layout_select_ds_stateid(const struct nfs4_ff_layout_mirror *mirror,
		nfs4_stateid *stateid)
{
	if (nfs4_ff_layout_ds_version(mirror) == 4)
		nfs4_stateid_copy(stateid, &mirror->stateid);
		nfs4_stateid_copy(stateid, &mirror->dss[0].stateid);
}

static bool
@@ -324,23 +324,23 @@ ff_layout_init_mirror_ds(struct pnfs_layout_hdr *lo,
{
	if (mirror == NULL)
		goto outerr;
	if (mirror->mirror_ds == NULL) {
	if (mirror->dss[0].mirror_ds == NULL) {
		struct nfs4_deviceid_node *node;
		struct nfs4_ff_layout_ds *mirror_ds = ERR_PTR(-ENODEV);

		node = nfs4_find_get_deviceid(NFS_SERVER(lo->plh_inode),
				&mirror->devid, lo->plh_lc_cred,
				&mirror->dss[0].devid, lo->plh_lc_cred,
				GFP_KERNEL);
		if (node)
			mirror_ds = FF_LAYOUT_MIRROR_DS(node);

		/* check for race with another call to this function */
		if (cmpxchg(&mirror->mirror_ds, NULL, mirror_ds) &&
		if (cmpxchg(&mirror->dss[0].mirror_ds, NULL, mirror_ds) &&
		    mirror_ds != ERR_PTR(-ENODEV))
			nfs4_put_deviceid_node(node);
	}

	if (IS_ERR(mirror->mirror_ds))
	if (IS_ERR(mirror->dss[0].mirror_ds))
		goto outerr;

	return true;
@@ -379,7 +379,7 @@ nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg,
	if (!ff_layout_init_mirror_ds(lseg->pls_layout, mirror))
		goto noconnect;

	ds = mirror->mirror_ds->ds;
	ds = mirror->dss[0].mirror_ds->ds;
	if (READ_ONCE(ds->ds_clp))
		goto out;
	/* matching smp_wmb() in _nfs4_pnfs_v3/4_ds_connect */
@@ -388,10 +388,10 @@ nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg,
	/* FIXME: For now we assume the server sent only one version of NFS
	 * to use for the DS.
	 */
	status = nfs4_pnfs_ds_connect(s, ds, &mirror->mirror_ds->id_node,
	status = nfs4_pnfs_ds_connect(s, ds, &mirror->dss[0].mirror_ds->id_node,
			     dataserver_timeo, dataserver_retrans,
			     mirror->mirror_ds->ds_versions[0].version,
			     mirror->mirror_ds->ds_versions[0].minor_version);
			     mirror->dss[0].mirror_ds->ds_versions[0].version,
			     mirror->dss[0].mirror_ds->ds_versions[0].minor_version);

	/* connect success, check rsize/wsize limit */
	if (!status) {
@@ -404,10 +404,10 @@ nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg,
		max_payload =
			nfs_block_size(rpc_max_payload(ds->ds_clp->cl_rpcclient),
				       NULL);
		if (mirror->mirror_ds->ds_versions[0].rsize > max_payload)
			mirror->mirror_ds->ds_versions[0].rsize = max_payload;
		if (mirror->mirror_ds->ds_versions[0].wsize > max_payload)
			mirror->mirror_ds->ds_versions[0].wsize = max_payload;
		if (mirror->dss[0].mirror_ds->ds_versions[0].rsize > max_payload)
			mirror->dss[0].mirror_ds->ds_versions[0].rsize = max_payload;
		if (mirror->dss[0].mirror_ds->ds_versions[0].wsize > max_payload)
			mirror->dss[0].mirror_ds->ds_versions[0].wsize = max_payload;
		goto out;
	}
noconnect:
@@ -430,7 +430,7 @@ ff_layout_get_ds_cred(struct nfs4_ff_layout_mirror *mirror,
{
	const struct cred *cred;

	if (mirror && !mirror->mirror_ds->ds_versions[0].tightly_coupled) {
	if (mirror && !mirror->dss[0].mirror_ds->ds_versions[0].tightly_coupled) {
		cred = ff_layout_get_mirror_cred(mirror, range->iomode);
		if (!cred)
			cred = get_cred(mdscred);
@@ -453,7 +453,7 @@ struct rpc_clnt *
nfs4_ff_find_or_create_ds_client(struct nfs4_ff_layout_mirror *mirror,
				 struct nfs_client *ds_clp, struct inode *inode)
{
	switch (mirror->mirror_ds->ds_versions[0].version) {
	switch (mirror->dss[0].mirror_ds->ds_versions[0].version) {
	case 3:
		/* For NFSv3 DS, flavor is set when creating DS connections */
		return ds_clp->cl_rpcclient;
@@ -564,11 +564,11 @@ static bool ff_read_layout_has_available_ds(struct pnfs_layout_segment *lseg)
	for (idx = 0; idx < FF_LAYOUT_MIRROR_COUNT(lseg); idx++) {
		mirror = FF_LAYOUT_COMP(lseg, idx);
		if (mirror) {
			if (!mirror->mirror_ds)
			if (!mirror->dss[0].mirror_ds)
				return true;
			if (IS_ERR(mirror->mirror_ds))
			if (IS_ERR(mirror->dss[0].mirror_ds))
				continue;
			devid = &mirror->mirror_ds->id_node;
			devid = &mirror->dss[0].mirror_ds->id_node;
			if (!nfs4_test_deviceid_unavailable(devid))
				return true;
		}
@@ -585,11 +585,11 @@ static bool ff_rw_layout_has_available_ds(struct pnfs_layout_segment *lseg)

	for (idx = 0; idx < FF_LAYOUT_MIRROR_COUNT(lseg); idx++) {
		mirror = FF_LAYOUT_COMP(lseg, idx);
		if (!mirror || IS_ERR(mirror->mirror_ds))
		if (!mirror || IS_ERR(mirror->dss[0].mirror_ds))
			return false;
		if (!mirror->mirror_ds)
		if (!mirror->dss[0].mirror_ds)
			continue;
		devid = &mirror->mirror_ds->id_node;
		devid = &mirror->dss[0].mirror_ds->id_node;
		if (nfs4_test_deviceid_unavailable(devid))
			return false;
	}