// SPDX-License-Identifier: GPL-2.0-only /* * Common NFS I/O operations for the pnfs file based * layout drivers. * * Copyright (c) 2014, Primary Data, Inc. All rights reserved. * * Tom Haynes <loghyr@primarydata.com>
*/
/* Fake up some data that will cause nfs_commit_release to retry the writes. */ void pnfs_generic_prepare_to_resend_writes(struct nfs_commit_data *data)
{ struct nfs_writeverf *verf = data->res.verf;
/* The generic layer is about to remove the req from the commit list. * If this will make the bucket empty, it will need to put the lseg reference. * Note this must be called holding nfsi->commit_mutex
*/ void
pnfs_generic_clear_request_commit(struct nfs_page *req, struct nfs_commit_info *cinfo)
{ struct pnfs_commit_bucket *bucket = NULL;
if (!test_and_clear_bit(PG_COMMIT_TO_DS, &req->wb_flags)) goto out;
cinfo->ds->nwritten--; if (list_is_singular(&req->wb_list))
bucket = list_first_entry(&req->wb_list, struct pnfs_commit_bucket, written);
out:
nfs_request_remove_commit_list(req, cinfo); if (bucket)
pnfs_put_lseg(pnfs_free_bucket_lseg(bucket));
}
EXPORT_SYMBOL_GPL(pnfs_generic_clear_request_commit);
/* * Locks the nfs_page requests for commit and moves them to * @bucket->committing.
*/ staticint
pnfs_bucket_scan_ds_commit_list(struct pnfs_commit_bucket *bucket, struct nfs_commit_info *cinfo, int max)
{ struct list_head *src = &bucket->written; struct list_head *dst = &bucket->committing; int ret;
lockdep_assert_held(&NFS_I(cinfo->inode)->commit_mutex);
ret = nfs_scan_commit_list(src, dst, cinfo, max); if (ret) {
cinfo->ds->nwritten -= ret;
cinfo->ds->ncommitting += ret;
} return ret;
}
staticint pnfs_bucket_scan_array(struct nfs_commit_info *cinfo, struct pnfs_commit_bucket *buckets, unsignedint nbuckets, int max)
{ unsignedint i; int rv = 0, cnt;
for (i = 0; i < nbuckets && max != 0; i++) {
cnt = pnfs_bucket_scan_ds_commit_list(&buckets[i], cinfo, max);
rv += cnt;
max -= cnt;
} return rv;
}
/* Move reqs from written to committing lists, returning count * of number moved.
*/ int pnfs_generic_scan_commit_lists(struct nfs_commit_info *cinfo, int max)
{ struct pnfs_ds_commit_info *fl_cinfo = cinfo->ds; struct pnfs_commit_array *array; int rv = 0, cnt;
/* * Data server cache * * Data servers can be mapped to different device ids, but should * never be shared between net namespaces. * * nfs4_pnfs_ds reference counting: * - set to 1 on allocation * - incremented when a device id maps a data server already in the cache. * - decremented when deviceid is removed from the cache.
*/
if (refcount_dec_and_lock(&ds->ds_count, &nn->nfs4_data_server_lock)) {
list_del_init(&ds->ds_node);
spin_unlock(&nn->nfs4_data_server_lock);
destroy_ds(ds);
}
}
EXPORT_SYMBOL_GPL(nfs4_pnfs_ds_put);
/* * Create a string with a human readable address and port to avoid * complicated setup around many dprinks.
*/ staticchar *
nfs4_pnfs_remotestr(struct list_head *dsaddrs, gfp_t gfp_flags)
{ struct nfs4_pnfs_ds_addr *da; char *remotestr;
size_t len; char *p;
len = 3; /* '{', '}' and eol */
list_for_each_entry(da, dsaddrs, da_node) {
len += strlen(da->da_remotestr) + 1; /* string plus comma */
}
remotestr = kzalloc(len, gfp_flags); if (!remotestr) return NULL;
if (xprt_args.ident != clp->cl_proto) continue; if (xprt_args.dstaddr->sa_family !=
clp->cl_addr.ss_family) continue; /* Add this address as an alias */
rpc_clnt_add_xprt(clp->cl_rpcclient, &xprt_args,
rpc_clnt_test_and_add_xprt, NULL); continue;
}
/* for NFS with TLS we need to supply a correct * servername of the trunked transport, not the * servername of the main transport stored in * clp->cl_hostname. And set the protocol to * indicate to use TLS
*/
servername[0] = '\0'; switch(addr->sa_family) { case AF_INET:
snprintf(servername, sizeof(servername), "%pI4", &sin->sin_addr.s_addr); break; case AF_INET6:
snprintf(servername, sizeof(servername), "%pI6", &sin6->sin6_addr); break; default: /* do not consider this address */ continue;
}
xprt_args.ident = XPRT_TRANSPORT_TCP_TLS;
xprt_args.servername = servername;
} if (xprt_args.ident != clp->cl_proto) continue; if (xprt_args.dstaddr->sa_family !=
clp->cl_addr.ss_family) continue;
/** * Test this address for session trunking and * add as an alias
*/
xprtdata.cred = nfs4_get_clid_cred(clp);
rpc_clnt_add_xprt(clp->cl_rpcclient, &xprt_args,
rpc_clnt_setup_test_and_add_xprt,
&rpcdata); if (xprtdata.cred)
put_cred(xprtdata.cred);
} else {
ds_proto = da->da_transport; if (ds_proto == XPRT_TRANSPORT_TCP &&
xprtsec_policy != RPC_XPRTSEC_NONE)
ds_proto = XPRT_TRANSPORT_TCP_TLS;
/* * Create an rpc connection to the nfs4_pnfs_ds data server. * Currently only supports IPv4 and IPv6 addresses. * If connection fails, make devid unavailable and return a -errno.
*/ int nfs4_pnfs_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds, struct nfs4_deviceid_node *devid, unsignedint timeo, unsignedint retrans, u32 version, u32 minor_version)
{ int err;
do {
err = nfs4_wait_ds_connect(ds); if (err || ds->ds_clp) goto out; if (nfs4_test_deviceid_unavailable(devid)) {
err = -ENODEV; goto out;
}
} while (test_and_set_bit(NFS4DS_CONNECTING, &ds->ds_state) != 0);
connect_done:
nfs4_clear_ds_conn_bit(ds);
out: /* * At this point the ds->ds_clp should be ready, but it might have * hit an error.
*/ if (!err) { if (!ds->ds_clp || !nfs_client_init_is_complete(ds->ds_clp)) {
WARN_ON_ONCE(ds->ds_clp ||
!nfs4_test_deviceid_unavailable(devid));
err = -EINVAL;
} else
err = nfs_client_init_status(ds->ds_clp);
}
/* r_addr: ip/ip6addr with port in dec octets - see RFC 5665 */ /* port is ".ABC.DEF", 8 chars max */
rlen = xdr_stream_decode_string_dup(xdr, &buf, INET6_ADDRSTRLEN +
IPV6_SCOPE_ID_LEN + 8, gfp_flags); if (unlikely(rlen < 0)) goto out_free_netid;
/* replace port '.' with '-' */
portstr = strrchr(buf, '.'); if (!portstr) {
dprintk("%s: Failed finding expected dot in port\n",
__func__); goto out_free_buf;
}
*portstr = '-';
/* find '.' between address and port */
portstr = strrchr(buf, '.'); if (!portstr) {
dprintk("%s: Failed finding expected dot between address and " "port\n", __func__); goto out_free_buf;
}
*portstr = '\0';
da = nfs4_pnfs_ds_addr_alloc(gfp_flags); if (unlikely(!da)) goto out_free_buf;
mutex_lock(&NFS_I(cinfo->inode)->commit_mutex);
array = pnfs_lookup_commit_array(cinfo->ds, lseg); if (!array || !pnfs_is_valid_lseg(lseg)) goto out_resched;
bucket = &array->buckets[ds_commit_idx];
list = &bucket->written; /* Non-empty buckets hold a reference on the lseg. That ref * is normally transferred to the COMMIT call and released * there. It could also be released if the last req is pulled * off due to a rewrite, in which case it will be done in * pnfs_common_clear_request_commit
*/ if (!bucket->lseg)
bucket->lseg = pnfs_get_lseg(lseg);
set_bit(PG_COMMIT_TO_DS, &req->wb_flags);
cinfo->ds->nwritten++;
int
pnfs_nfs_generic_sync(struct inode *inode, bool datasync)
{ int ret;
if (!pnfs_layoutcommit_outstanding(inode)) return0;
ret = nfs_commit_inode(inode, FLUSH_SYNC); if (ret < 0) return ret; if (datasync) return0; return pnfs_layoutcommit_inode(inode, true);
}
EXPORT_SYMBOL_GPL(pnfs_nfs_generic_sync);
Messung V0.5 in Prozent
¤ 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.0.18Bemerkung:
(vorverarbeitet am 2026-06-08)
¤
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.