for (i = 0; i < mp_count; i++) { /* multipath ds */
da = nfs4_decode_mp_ds_addr(net, &stream, gfp_flags); if (da)
list_add_tail(&da->da_node, &dsaddrs);
} if (list_empty(&dsaddrs)) {
dprintk("%s: no suitable DS addresses found\n",
__func__);
ret = -ENOMEDIUM; goto out_err_drain_dsaddrs;
}
/* version count */
p = xdr_inline_decode(&stream, 4); if (unlikely(!p)) goto out_err_drain_dsaddrs;
version_count = be32_to_cpup(p);
dprintk("%s: version count %d\n", __func__, version_count);
ds_versions = kcalloc(version_count, sizeof(struct nfs4_ff_ds_version),
gfp_flags); if (!ds_versions) goto out_scratch;
for (i = 0; i < version_count; i++) { /* 20 = version(4) + minor_version(4) + rsize(4) + wsize(4) +
* tightly_coupled(4) */
p = xdr_inline_decode(&stream, 20); if (unlikely(!p)) goto out_err_drain_dsaddrs;
ds_versions[i].version = be32_to_cpup(p++);
ds_versions[i].minor_version = be32_to_cpup(p++);
ds_versions[i].rsize = nfs_io_size(be32_to_cpup(p++),
server->nfs_client->cl_proto);
ds_versions[i].wsize = nfs_io_size(be32_to_cpup(p++),
server->nfs_client->cl_proto);
ds_versions[i].tightly_coupled = be32_to_cpup(p);
if (ds_versions[i].rsize > NFS_MAX_FILE_IO_SIZE)
ds_versions[i].rsize = NFS_MAX_FILE_IO_SIZE; if (ds_versions[i].wsize > NFS_MAX_FILE_IO_SIZE)
ds_versions[i].wsize = NFS_MAX_FILE_IO_SIZE;
/* * check for valid major/minor combination. * currently we support dataserver which talk: * v3, v4.0, v4.1, v4.2
*/ if (!((ds_versions[i].version == 3 && ds_versions[i].minor_version == 0) ||
(ds_versions[i].version == 4 && ds_versions[i].minor_version < 3))) {
dprintk("%s: [%d] unsupported ds version %d-%d\n", __func__,
i, ds_versions[i].version,
ds_versions[i].minor_version);
ret = -EPROTONOSUPPORT; goto out_err_drain_dsaddrs;
}
dprintk("%s: [%d] vers %u minor_ver %u rsize %u wsize %u coupled %d\n",
__func__, i, ds_versions[i].version,
ds_versions[i].minor_version,
ds_versions[i].rsize,
ds_versions[i].wsize,
ds_versions[i].tightly_coupled);
}
new_ds->ds = nfs4_pnfs_ds_add(net, &dsaddrs, gfp_flags); if (!new_ds->ds) goto out_err_drain_dsaddrs;
/* If DS was already in cache, free ds addrs */ while (!list_empty(&dsaddrs)) {
da = list_first_entry(&dsaddrs, struct nfs4_pnfs_ds_addr,
da_node);
list_del_init(&da->da_node);
kfree(da->da_remotestr);
kfree(da);
}
__free_page(scratch); return new_ds;
out_err_drain_dsaddrs: while (!list_empty(&dsaddrs)) {
da = list_first_entry(&dsaddrs, struct nfs4_pnfs_ds_addr,
da_node);
list_del_init(&da->da_node);
kfree(da->da_remotestr);
kfree(da);
}
end = max_t(u64, pnfs_end_offset(err->offset, err->length),
pnfs_end_offset(offset, length));
err->offset = min_t(u64, err->offset, offset);
err->length = end - err->offset;
}
staticint
ff_ds_error_match(conststruct nfs4_ff_layout_ds_err *e1, conststruct nfs4_ff_layout_ds_err *e2)
{ int ret;
if (e1->opnum != e2->opnum) return e1->opnum < e2->opnum ? -1 : 1; if (e1->status != e2->status) return e1->status < e2->status ? -1 : 1;
ret = memcmp(e1->stateid.data, e2->stateid.data, sizeof(e1->stateid.data)); if (ret != 0) return ret;
ret = memcmp(&e1->deviceid, &e2->deviceid, sizeof(e1->deviceid)); if (ret != 0) return ret; if (pnfs_end_offset(e1->offset, e1->length) < e2->offset) return -1; if (e1->offset > pnfs_end_offset(e2->offset, e2->length)) return 1; /* If ranges overlap or are contiguous, they are the same */ return 0;
}
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];
}
/* check for race with another call to this function */ if (cmpxchg(&mirror->mirror_ds, NULL, mirror_ds) &&
mirror_ds != ERR_PTR(-ENODEV))
nfs4_put_deviceid_node(node);
}
if (IS_ERR(mirror->mirror_ds)) goto outerr;
returntrue;
outerr: returnfalse;
}
/** * nfs4_ff_layout_prepare_ds - prepare a DS connection for an RPC call * @lseg: the layout segment we're operating on * @mirror: layout mirror describing the DS to use * @fail_return: return layout on connect failure? * * Try to prepare a DS connection to accept an RPC call. This involves * selecting a mirror to use and connecting the client to it if it's not * already connected. * * Since we only need a single functioning mirror to satisfy a read, we don't * want to return the layout if there is one. For writes though, any down * mirror should result in a LAYOUTRETURN. @fail_return is how we distinguish * between the two cases. * * Returns a pointer to a connected DS object on success or NULL on failure.
*/ struct nfs4_pnfs_ds *
nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg, struct nfs4_ff_layout_mirror *mirror, bool fail_return)
{ struct nfs4_pnfs_ds *ds; struct inode *ino = lseg->pls_layout->plh_inode; struct nfs_server *s = NFS_SERVER(ino); unsignedint max_payload; int status = -EAGAIN;
if (!ff_layout_init_mirror_ds(lseg->pls_layout, mirror)) goto noconnect;
ds = mirror->mirror_ds->ds; if (READ_ONCE(ds->ds_clp)) goto out; /* matching smp_wmb() in _nfs4_pnfs_v3/4_ds_connect */
smp_rmb();
/* 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,
dataserver_timeo, dataserver_retrans,
mirror->mirror_ds->ds_versions[0].version,
mirror->mirror_ds->ds_versions[0].minor_version);
/* connect success, check rsize/wsize limit */ if (!status) { /* * ds_clp is put in destroy_ds(). * keep ds_clp even if DS is local, so that if local IO cannot * proceed somehow, we can fall back to NFS whenever we want.
*/
nfs_local_probe_async(ds->ds_clp);
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; goto out;
}
noconnect:
ff_layout_track_ds_error(FF_LAYOUT_FROM_HDR(lseg->pls_layout),
mirror, lseg->pls_range.offset,
lseg->pls_range.length, NFS4ERR_NXIO,
OP_ILLEGAL, GFP_NOIO);
ff_layout_send_layouterror(lseg); if (fail_return || !ff_layout_has_available_ds(lseg))
pnfs_error_mark_layout_for_return(ino, lseg);
ds = ERR_PTR(status);
out: return ds;
}
/** * nfs4_ff_find_or_create_ds_client - Find or create a DS rpc client * @mirror: pointer to the mirror * @ds_clp: nfs_client for the DS * @inode: pointer to inode * * Find or create a DS rpc client with th MDS server rpc client auth flavor * in the nfs_client cl_ds_clients list.
*/ 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) { case 3: /* For NFSv3 DS, flavor is set when creating DS connections */ return ds_clp->cl_rpcclient; case 4: return nfs4_find_or_create_ds_client(ds_clp, inode); default:
BUG();
}
}
/* called with inode i_lock held */ int ff_layout_encode_ds_ioerr(struct xdr_stream *xdr, conststruct list_head *head)
{ struct nfs4_ff_layout_ds_err *err;
__be32 *p;
module_param(dataserver_retrans, uint, 0644);
MODULE_PARM_DESC(dataserver_retrans, "The number of times the NFSv4.1 client " "retries a request before it attempts further " " recovery action.");
module_param(dataserver_timeo, uint, 0644);
MODULE_PARM_DESC(dataserver_timeo, "The time (in tenths of a second) the " "NFSv4.1 client waits for a response from a " " data server before it retries an NFS request.");
Messung V0.5
¤ Dauer der Verarbeitung: 0.15 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.