Commit 61ea647e authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'nfsd-6.10' of git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux

Pull nfsd updates from Chuck Lever:
 "This is a light release containing mostly optimizations, code clean-
  ups, and minor bug fixes. This development cycle has focused on non-
  upstream kernel work:

   1. Continuing to build upstream CI for NFSD, based on kdevops

   2. Backporting NFSD filecache-related fixes to selected LTS kernels

  One notable new feature in v6.10 NFSD is the addition of a new netlink
  protocol dedicated to configuring NFSD. A new user space tool,
  nfsdctl, is to be added to nfs-utils. Lots more to come here.

  As always I am very grateful to NFSD contributors, reviewers, testers,
  and bug reporters who participated during this cycle"

* tag 'nfsd-6.10' of git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux: (29 commits)
  NFSD: Force all NFSv4.2 COPY requests to be synchronous
  SUNRPC: Fix gss_free_in_token_pages()
  NFS/knfsd: Remove the invalid NFS error 'NFSERR_OPNOTSUPP'
  knfsd: LOOKUP can return an illegal error value
  nfsd: set security label during create operations
  NFSD: Add COPY status code to OFFLOAD_STATUS response
  NFSD: Record status of async copy operation in struct nfsd4_copy
  SUNRPC: Remove comment for sp_lock
  NFSD: add listener-{set,get} netlink command
  SUNRPC: add a new svc_find_listener helper
  SUNRPC: introduce svc_xprt_create_from_sa utility routine
  NFSD: add write_version to netlink command
  NFSD: convert write_threads to netlink command
  NFSD: allow callers to pass in scope string to nfsd_svc
  NFSD: move nfsd_mutex handling into nfsd_svc callers
  lockd: host: Remove unnecessary statements'host = NULL;'
  nfsd: don't create nfsv4recoverydir in nfsdfs when not used.
  nfsd: optimise recalculate_deny_mode() for a common case
  nfsd: add tracepoint in mark_client_expired_locked
  nfsd: new tracepoint for check_slot_seqid
  ...
parents 25f48746 8d915bbf
...@@ -62,6 +62,59 @@ attribute-sets: ...@@ -62,6 +62,59 @@ attribute-sets:
name: compound-ops name: compound-ops
type: u32 type: u32
multi-attr: true multi-attr: true
-
name: server
attributes:
-
name: threads
type: u32
multi-attr: true
-
name: gracetime
type: u32
-
name: leasetime
type: u32
-
name: scope
type: string
-
name: version
attributes:
-
name: major
type: u32
-
name: minor
type: u32
-
name: enabled
type: flag
-
name: server-proto
attributes:
-
name: version
type: nest
nested-attributes: version
multi-attr: true
-
name: sock
attributes:
-
name: addr
type: binary
-
name: transport-name
type: string
-
name: server-sock
attributes:
-
name: addr
type: nest
nested-attributes: sock
multi-attr: true
operations: operations:
list: list:
...@@ -87,3 +140,60 @@ operations: ...@@ -87,3 +140,60 @@ operations:
- sport - sport
- dport - dport
- compound-ops - compound-ops
-
name: threads-set
doc: set the number of running threads
attribute-set: server
flags: [ admin-perm ]
do:
request:
attributes:
- threads
- gracetime
- leasetime
- scope
-
name: threads-get
doc: get the number of running threads
attribute-set: server
do:
reply:
attributes:
- threads
- gracetime
- leasetime
- scope
-
name: version-set
doc: set nfs enabled versions
attribute-set: server-proto
flags: [ admin-perm ]
do:
request:
attributes:
- version
-
name: version-get
doc: get nfs enabled versions
attribute-set: server-proto
do:
reply:
attributes:
- version
-
name: listener-set
doc: set nfs running sockets
attribute-set: server-sock
flags: [ admin-perm ]
do:
request:
attributes:
- addr
-
name: listener-get
doc: get nfs running listeners
attribute-set: server-sock
do:
reply:
attributes:
- addr
...@@ -117,7 +117,6 @@ static struct nlm_host *nlm_alloc_host(struct nlm_lookup_host_info *ni, ...@@ -117,7 +117,6 @@ static struct nlm_host *nlm_alloc_host(struct nlm_lookup_host_info *ni,
if (nsm != NULL) if (nsm != NULL)
refcount_inc(&nsm->sm_count); refcount_inc(&nsm->sm_count);
else { else {
host = NULL;
nsm = nsm_get_handle(ni->net, ni->sap, ni->salen, nsm = nsm_get_handle(ni->net, ni->sap, ni->salen,
ni->hostname, ni->hostname_len); ni->hostname, ni->hostname_len);
if (unlikely(nsm == NULL)) { if (unlikely(nsm == NULL)) {
......
...@@ -334,21 +334,25 @@ static void nfsd4_fslocs_free(struct nfsd4_fs_locations *fsloc) ...@@ -334,21 +334,25 @@ static void nfsd4_fslocs_free(struct nfsd4_fs_locations *fsloc)
static int export_stats_init(struct export_stats *stats) static int export_stats_init(struct export_stats *stats)
{ {
stats->start_time = ktime_get_seconds(); stats->start_time = ktime_get_seconds();
return nfsd_percpu_counters_init(stats->counter, EXP_STATS_COUNTERS_NUM); return percpu_counter_init_many(stats->counter, 0, GFP_KERNEL,
EXP_STATS_COUNTERS_NUM);
} }
static void export_stats_reset(struct export_stats *stats) static void export_stats_reset(struct export_stats *stats)
{ {
if (stats) if (stats) {
nfsd_percpu_counters_reset(stats->counter, int i;
EXP_STATS_COUNTERS_NUM);
for (i = 0; i < EXP_STATS_COUNTERS_NUM; i++)
percpu_counter_set(&stats->counter[i], 0);
}
} }
static void export_stats_destroy(struct export_stats *stats) static void export_stats_destroy(struct export_stats *stats)
{ {
if (stats) if (stats)
nfsd_percpu_counters_destroy(stats->counter, percpu_counter_destroy_many(stats->counter,
EXP_STATS_COUNTERS_NUM); EXP_STATS_COUNTERS_NUM);
} }
static void svc_export_put(struct kref *ref) static void svc_export_put(struct kref *ref)
......
...@@ -10,6 +10,36 @@ ...@@ -10,6 +10,36 @@
#include <uapi/linux/nfsd_netlink.h> #include <uapi/linux/nfsd_netlink.h>
/* Common nested types */
const struct nla_policy nfsd_sock_nl_policy[NFSD_A_SOCK_TRANSPORT_NAME + 1] = {
[NFSD_A_SOCK_ADDR] = { .type = NLA_BINARY, },
[NFSD_A_SOCK_TRANSPORT_NAME] = { .type = NLA_NUL_STRING, },
};
const struct nla_policy nfsd_version_nl_policy[NFSD_A_VERSION_ENABLED + 1] = {
[NFSD_A_VERSION_MAJOR] = { .type = NLA_U32, },
[NFSD_A_VERSION_MINOR] = { .type = NLA_U32, },
[NFSD_A_VERSION_ENABLED] = { .type = NLA_FLAG, },
};
/* NFSD_CMD_THREADS_SET - do */
static const struct nla_policy nfsd_threads_set_nl_policy[NFSD_A_SERVER_SCOPE + 1] = {
[NFSD_A_SERVER_THREADS] = { .type = NLA_U32, },
[NFSD_A_SERVER_GRACETIME] = { .type = NLA_U32, },
[NFSD_A_SERVER_LEASETIME] = { .type = NLA_U32, },
[NFSD_A_SERVER_SCOPE] = { .type = NLA_NUL_STRING, },
};
/* NFSD_CMD_VERSION_SET - do */
static const struct nla_policy nfsd_version_set_nl_policy[NFSD_A_SERVER_PROTO_VERSION + 1] = {
[NFSD_A_SERVER_PROTO_VERSION] = NLA_POLICY_NESTED(nfsd_version_nl_policy),
};
/* NFSD_CMD_LISTENER_SET - do */
static const struct nla_policy nfsd_listener_set_nl_policy[NFSD_A_SERVER_SOCK_ADDR + 1] = {
[NFSD_A_SERVER_SOCK_ADDR] = NLA_POLICY_NESTED(nfsd_sock_nl_policy),
};
/* Ops table for nfsd */ /* Ops table for nfsd */
static const struct genl_split_ops nfsd_nl_ops[] = { static const struct genl_split_ops nfsd_nl_ops[] = {
{ {
...@@ -19,6 +49,42 @@ static const struct genl_split_ops nfsd_nl_ops[] = { ...@@ -19,6 +49,42 @@ static const struct genl_split_ops nfsd_nl_ops[] = {
.done = nfsd_nl_rpc_status_get_done, .done = nfsd_nl_rpc_status_get_done,
.flags = GENL_CMD_CAP_DUMP, .flags = GENL_CMD_CAP_DUMP,
}, },
{
.cmd = NFSD_CMD_THREADS_SET,
.doit = nfsd_nl_threads_set_doit,
.policy = nfsd_threads_set_nl_policy,
.maxattr = NFSD_A_SERVER_SCOPE,
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
},
{
.cmd = NFSD_CMD_THREADS_GET,
.doit = nfsd_nl_threads_get_doit,
.flags = GENL_CMD_CAP_DO,
},
{
.cmd = NFSD_CMD_VERSION_SET,
.doit = nfsd_nl_version_set_doit,
.policy = nfsd_version_set_nl_policy,
.maxattr = NFSD_A_SERVER_PROTO_VERSION,
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
},
{
.cmd = NFSD_CMD_VERSION_GET,
.doit = nfsd_nl_version_get_doit,
.flags = GENL_CMD_CAP_DO,
},
{
.cmd = NFSD_CMD_LISTENER_SET,
.doit = nfsd_nl_listener_set_doit,
.policy = nfsd_listener_set_nl_policy,
.maxattr = NFSD_A_SERVER_SOCK_ADDR,
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
},
{
.cmd = NFSD_CMD_LISTENER_GET,
.doit = nfsd_nl_listener_get_doit,
.flags = GENL_CMD_CAP_DO,
},
}; };
struct genl_family nfsd_nl_family __ro_after_init = { struct genl_family nfsd_nl_family __ro_after_init = {
......
...@@ -11,11 +11,21 @@ ...@@ -11,11 +11,21 @@
#include <uapi/linux/nfsd_netlink.h> #include <uapi/linux/nfsd_netlink.h>
/* Common nested types */
extern const struct nla_policy nfsd_sock_nl_policy[NFSD_A_SOCK_TRANSPORT_NAME + 1];
extern const struct nla_policy nfsd_version_nl_policy[NFSD_A_VERSION_ENABLED + 1];
int nfsd_nl_rpc_status_get_start(struct netlink_callback *cb); int nfsd_nl_rpc_status_get_start(struct netlink_callback *cb);
int nfsd_nl_rpc_status_get_done(struct netlink_callback *cb); int nfsd_nl_rpc_status_get_done(struct netlink_callback *cb);
int nfsd_nl_rpc_status_get_dumpit(struct sk_buff *skb, int nfsd_nl_rpc_status_get_dumpit(struct sk_buff *skb,
struct netlink_callback *cb); struct netlink_callback *cb);
int nfsd_nl_threads_set_doit(struct sk_buff *skb, struct genl_info *info);
int nfsd_nl_threads_get_doit(struct sk_buff *skb, struct genl_info *info);
int nfsd_nl_version_set_doit(struct sk_buff *skb, struct genl_info *info);
int nfsd_nl_version_get_doit(struct sk_buff *skb, struct genl_info *info);
int nfsd_nl_listener_set_doit(struct sk_buff *skb, struct genl_info *info);
int nfsd_nl_listener_get_doit(struct sk_buff *skb, struct genl_info *info);
extern struct genl_family nfsd_nl_family; extern struct genl_family nfsd_nl_family;
......
...@@ -218,6 +218,7 @@ struct nfsd_net { ...@@ -218,6 +218,7 @@ struct nfsd_net {
/* Simple check to find out if a given net was properly initialized */ /* Simple check to find out if a given net was properly initialized */
#define nfsd_netns_ready(nn) ((nn)->sessionid_hashtbl) #define nfsd_netns_ready(nn) ((nn)->sessionid_hashtbl)
extern bool nfsd_support_version(int vers);
extern void nfsd_netns_free_versions(struct nfsd_net *nn); extern void nfsd_netns_free_versions(struct nfsd_net *nn);
extern unsigned int nfsd_net_id; extern unsigned int nfsd_net_id;
......
...@@ -978,12 +978,12 @@ static int max_cb_time(struct net *net) ...@@ -978,12 +978,12 @@ static int max_cb_time(struct net *net)
return max(((u32)nn->nfsd4_lease)/10, 1u) * HZ; return max(((u32)nn->nfsd4_lease)/10, 1u) * HZ;
} }
static struct workqueue_struct *callback_wq;
static bool nfsd4_queue_cb(struct nfsd4_callback *cb) static bool nfsd4_queue_cb(struct nfsd4_callback *cb)
{ {
trace_nfsd_cb_queue(cb->cb_clp, cb); struct nfs4_client *clp = cb->cb_clp;
return queue_work(callback_wq, &cb->cb_work);
trace_nfsd_cb_queue(clp, cb);
return queue_work(clp->cl_callback_wq, &cb->cb_work);
} }
static void nfsd41_cb_inflight_begin(struct nfs4_client *clp) static void nfsd41_cb_inflight_begin(struct nfs4_client *clp)
...@@ -1153,7 +1153,7 @@ void nfsd4_probe_callback(struct nfs4_client *clp) ...@@ -1153,7 +1153,7 @@ void nfsd4_probe_callback(struct nfs4_client *clp)
void nfsd4_probe_callback_sync(struct nfs4_client *clp) void nfsd4_probe_callback_sync(struct nfs4_client *clp)
{ {
nfsd4_probe_callback(clp); nfsd4_probe_callback(clp);
flush_workqueue(callback_wq); flush_workqueue(clp->cl_callback_wq);
} }
void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *conn) void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *conn)
...@@ -1372,19 +1372,6 @@ static const struct rpc_call_ops nfsd4_cb_ops = { ...@@ -1372,19 +1372,6 @@ static const struct rpc_call_ops nfsd4_cb_ops = {
.rpc_release = nfsd4_cb_release, .rpc_release = nfsd4_cb_release,
}; };
int nfsd4_create_callback_queue(void)
{
callback_wq = alloc_ordered_workqueue("nfsd4_callbacks", 0);
if (!callback_wq)
return -ENOMEM;
return 0;
}
void nfsd4_destroy_callback_queue(void)
{
destroy_workqueue(callback_wq);
}
/* must be called under the state lock */ /* must be called under the state lock */
void nfsd4_shutdown_callback(struct nfs4_client *clp) void nfsd4_shutdown_callback(struct nfs4_client *clp)
{ {
...@@ -1398,7 +1385,7 @@ void nfsd4_shutdown_callback(struct nfs4_client *clp) ...@@ -1398,7 +1385,7 @@ void nfsd4_shutdown_callback(struct nfs4_client *clp)
* client, destroy the rpc client, and stop: * client, destroy the rpc client, and stop:
*/ */
nfsd4_run_cb(&clp->cl_cb_null); nfsd4_run_cb(&clp->cl_cb_null);
flush_workqueue(callback_wq); flush_workqueue(clp->cl_callback_wq);
nfsd41_cb_inflight_wait_complete(clp); nfsd41_cb_inflight_wait_complete(clp);
} }
...@@ -1420,9 +1407,9 @@ static struct nfsd4_conn * __nfsd4_find_backchannel(struct nfs4_client *clp) ...@@ -1420,9 +1407,9 @@ static struct nfsd4_conn * __nfsd4_find_backchannel(struct nfs4_client *clp)
/* /*
* Note there isn't a lot of locking in this code; instead we depend on * Note there isn't a lot of locking in this code; instead we depend on
* the fact that it is run from the callback_wq, which won't run two * the fact that it is run from clp->cl_callback_wq, which won't run two
* work items at once. So, for example, callback_wq handles all access * work items at once. So, for example, clp->cl_callback_wq handles all
* of cl_cb_client and all calls to rpc_create or rpc_shutdown_client. * access of cl_cb_client and all calls to rpc_create or rpc_shutdown_client.
*/ */
static void nfsd4_process_cb_update(struct nfsd4_callback *cb) static void nfsd4_process_cb_update(struct nfsd4_callback *cb)
{ {
......
...@@ -1737,7 +1737,7 @@ static void cleanup_async_copy(struct nfsd4_copy *copy) ...@@ -1737,7 +1737,7 @@ static void cleanup_async_copy(struct nfsd4_copy *copy)
nfs4_put_copy(copy); nfs4_put_copy(copy);
} }
static void nfsd4_send_cb_offload(struct nfsd4_copy *copy, __be32 nfserr) static void nfsd4_send_cb_offload(struct nfsd4_copy *copy)
{ {
struct nfsd4_cb_offload *cbo; struct nfsd4_cb_offload *cbo;
...@@ -1747,12 +1747,12 @@ static void nfsd4_send_cb_offload(struct nfsd4_copy *copy, __be32 nfserr) ...@@ -1747,12 +1747,12 @@ static void nfsd4_send_cb_offload(struct nfsd4_copy *copy, __be32 nfserr)
memcpy(&cbo->co_res, &copy->cp_res, sizeof(copy->cp_res)); memcpy(&cbo->co_res, &copy->cp_res, sizeof(copy->cp_res));
memcpy(&cbo->co_fh, &copy->fh, sizeof(copy->fh)); memcpy(&cbo->co_fh, &copy->fh, sizeof(copy->fh));
cbo->co_nfserr = nfserr; cbo->co_nfserr = copy->nfserr;
nfsd4_init_cb(&cbo->co_cb, copy->cp_clp, &nfsd4_cb_offload_ops, nfsd4_init_cb(&cbo->co_cb, copy->cp_clp, &nfsd4_cb_offload_ops,
NFSPROC4_CLNT_CB_OFFLOAD); NFSPROC4_CLNT_CB_OFFLOAD);
trace_nfsd_cb_offload(copy->cp_clp, &cbo->co_res.cb_stateid, trace_nfsd_cb_offload(copy->cp_clp, &cbo->co_res.cb_stateid,
&cbo->co_fh, copy->cp_count, nfserr); &cbo->co_fh, copy->cp_count, copy->nfserr);
nfsd4_run_cb(&cbo->co_cb); nfsd4_run_cb(&cbo->co_cb);
} }
...@@ -1766,7 +1766,6 @@ static void nfsd4_send_cb_offload(struct nfsd4_copy *copy, __be32 nfserr) ...@@ -1766,7 +1766,6 @@ static void nfsd4_send_cb_offload(struct nfsd4_copy *copy, __be32 nfserr)
static int nfsd4_do_async_copy(void *data) static int nfsd4_do_async_copy(void *data)
{ {
struct nfsd4_copy *copy = (struct nfsd4_copy *)data; struct nfsd4_copy *copy = (struct nfsd4_copy *)data;
__be32 nfserr;
trace_nfsd_copy_do_async(copy); trace_nfsd_copy_do_async(copy);
if (nfsd4_ssc_is_inter(copy)) { if (nfsd4_ssc_is_inter(copy)) {
...@@ -1777,24 +1776,25 @@ static int nfsd4_do_async_copy(void *data) ...@@ -1777,24 +1776,25 @@ static int nfsd4_do_async_copy(void *data)
if (IS_ERR(filp)) { if (IS_ERR(filp)) {
switch (PTR_ERR(filp)) { switch (PTR_ERR(filp)) {
case -EBADF: case -EBADF:
nfserr = nfserr_wrong_type; copy->nfserr = nfserr_wrong_type;
break; break;
default: default:
nfserr = nfserr_offload_denied; copy->nfserr = nfserr_offload_denied;
} }
/* ss_mnt will be unmounted by the laundromat */ /* ss_mnt will be unmounted by the laundromat */
goto do_callback; goto do_callback;
} }
nfserr = nfsd4_do_copy(copy, filp, copy->nf_dst->nf_file, copy->nfserr = nfsd4_do_copy(copy, filp, copy->nf_dst->nf_file,
false); false);
nfsd4_cleanup_inter_ssc(copy->ss_nsui, filp, copy->nf_dst); nfsd4_cleanup_inter_ssc(copy->ss_nsui, filp, copy->nf_dst);
} else { } else {
nfserr = nfsd4_do_copy(copy, copy->nf_src->nf_file, copy->nfserr = nfsd4_do_copy(copy, copy->nf_src->nf_file,
copy->nf_dst->nf_file, false); copy->nf_dst->nf_file, false);
} }
do_callback: do_callback:
nfsd4_send_cb_offload(copy, nfserr); set_bit(NFSD4_COPY_F_COMPLETED, &copy->cp_flags);
nfsd4_send_cb_offload(copy);
cleanup_async_copy(copy); cleanup_async_copy(copy);
return 0; return 0;
} }
...@@ -1807,6 +1807,13 @@ nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, ...@@ -1807,6 +1807,13 @@ nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
__be32 status; __be32 status;
struct nfsd4_copy *async_copy = NULL; struct nfsd4_copy *async_copy = NULL;
/*
* Currently, async COPY is not reliable. Force all COPY
* requests to be synchronous to avoid client application
* hangs waiting for COPY completion.
*/
nfsd4_copy_set_sync(copy, true);
copy->cp_clp = cstate->clp; copy->cp_clp = cstate->clp;
if (nfsd4_ssc_is_inter(copy)) { if (nfsd4_ssc_is_inter(copy)) {
trace_nfsd_copy_inter(copy); trace_nfsd_copy_inter(copy);
...@@ -2003,11 +2010,16 @@ nfsd4_offload_status(struct svc_rqst *rqstp, ...@@ -2003,11 +2010,16 @@ nfsd4_offload_status(struct svc_rqst *rqstp,
struct nfsd4_copy *copy; struct nfsd4_copy *copy;
struct nfs4_client *clp = cstate->clp; struct nfs4_client *clp = cstate->clp;
os->completed = false;
spin_lock(&clp->async_lock); spin_lock(&clp->async_lock);
copy = find_async_copy_locked(clp, &os->stateid); copy = find_async_copy_locked(clp, &os->stateid);
if (copy) if (copy) {
os->count = copy->cp_res.wr_bytes_written; os->count = copy->cp_res.wr_bytes_written;
else if (test_bit(NFSD4_COPY_F_COMPLETED, &copy->cp_flags)) {
os->completed = true;
os->status = copy->nfserr;
}
} else
status = nfserr_bad_stateid; status = nfserr_bad_stateid;
spin_unlock(&clp->async_lock); spin_unlock(&clp->async_lock);
...@@ -2154,6 +2166,29 @@ nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, ...@@ -2154,6 +2166,29 @@ nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
return status == nfserr_same ? nfs_ok : status; return status == nfserr_same ? nfs_ok : status;
} }
static __be32
nfsd4_get_dir_delegation(struct svc_rqst *rqstp,
struct nfsd4_compound_state *cstate,
union nfsd4_op_u *u)
{
struct nfsd4_get_dir_delegation *gdd = &u->get_dir_delegation;
/*
* RFC 8881, section 18.39.3 says:
*
* "The server may refuse to grant the delegation. In that case, the
* server will return NFS4ERR_DIRDELEG_UNAVAIL."
*
* This is sub-optimal, since it means that the server would need to
* abort compound processing just because the delegation wasn't
* available. RFC8881bis should change this to allow the server to
* return NFS4_OK with a non-fatal status of GDD4_UNAVAIL in this
* situation.
*/
gdd->gddrnf_status = GDD4_UNAVAIL;
return nfs_ok;
}
#ifdef CONFIG_NFSD_PNFS #ifdef CONFIG_NFSD_PNFS
static const struct nfsd4_layout_ops * static const struct nfsd4_layout_ops *
nfsd4_layout_verify(struct svc_export *exp, unsigned int layout_type) nfsd4_layout_verify(struct svc_export *exp, unsigned int layout_type)
...@@ -3082,6 +3117,18 @@ static u32 nfsd4_copy_notify_rsize(const struct svc_rqst *rqstp, ...@@ -3082,6 +3117,18 @@ static u32 nfsd4_copy_notify_rsize(const struct svc_rqst *rqstp,
* sizeof(__be32); * sizeof(__be32);
} }
static u32 nfsd4_get_dir_delegation_rsize(const struct svc_rqst *rqstp,
const struct nfsd4_op *op)
{
return (op_encode_hdr_size +
1 /* gddr_status */ +
op_encode_verifier_maxsz +
op_encode_stateid_maxsz +
2 /* gddr_notification */ +
2 /* gddr_child_attributes */ +
2 /* gddr_dir_attributes */);
}
#ifdef CONFIG_NFSD_PNFS #ifdef CONFIG_NFSD_PNFS
static u32 nfsd4_getdeviceinfo_rsize(const struct svc_rqst *rqstp, static u32 nfsd4_getdeviceinfo_rsize(const struct svc_rqst *rqstp,
const struct nfsd4_op *op) const struct nfsd4_op *op)
...@@ -3470,6 +3517,12 @@ static const struct nfsd4_operation nfsd4_ops[] = { ...@@ -3470,6 +3517,12 @@ static const struct nfsd4_operation nfsd4_ops[] = {
.op_get_currentstateid = nfsd4_get_freestateid, .op_get_currentstateid = nfsd4_get_freestateid,
.op_rsize_bop = nfsd4_only_status_rsize, .op_rsize_bop = nfsd4_only_status_rsize,
}, },
[OP_GET_DIR_DELEGATION] = {
.op_func = nfsd4_get_dir_delegation,
.op_flags = OP_MODIFIES_SOMETHING,
.op_name = "OP_GET_DIR_DELEGATION",
.op_rsize_bop = nfsd4_get_dir_delegation_rsize,
},
#ifdef CONFIG_NFSD_PNFS #ifdef CONFIG_NFSD_PNFS
[OP_GETDEVICEINFO] = { [OP_GETDEVICEINFO] = {
.op_func = nfsd4_getdeviceinfo, .op_func = nfsd4_getdeviceinfo,
......
This diff is collapsed.
...@@ -1732,6 +1732,35 @@ nfsd4_decode_free_stateid(struct nfsd4_compoundargs *argp, ...@@ -1732,6 +1732,35 @@ nfsd4_decode_free_stateid(struct nfsd4_compoundargs *argp,
return nfsd4_decode_stateid4(argp, &free_stateid->fr_stateid); return nfsd4_decode_stateid4(argp, &free_stateid->fr_stateid);
} }
static __be32
nfsd4_decode_get_dir_delegation(struct nfsd4_compoundargs *argp,
union nfsd4_op_u *u)
{
struct nfsd4_get_dir_delegation *gdd = &u->get_dir_delegation;
__be32 status;
memset(gdd, 0, sizeof(*gdd));
if (xdr_stream_decode_bool(argp->xdr, &gdd->gdda_signal_deleg_avail) < 0)
return nfserr_bad_xdr;
status = nfsd4_decode_bitmap4(argp, gdd->gdda_notification_types,
ARRAY_SIZE(gdd->gdda_notification_types));
if (status)
return status;
status = nfsd4_decode_nfstime4(argp, &gdd->gdda_child_attr_delay);
if (status)
return status;
status = nfsd4_decode_nfstime4(argp, &gdd->gdda_dir_attr_delay);
if (status)
return status;
status = nfsd4_decode_bitmap4(argp, gdd->gdda_child_attributes,
ARRAY_SIZE(gdd->gdda_child_attributes));
if (status)
return status;
return nfsd4_decode_bitmap4(argp, gdd->gdda_dir_attributes,
ARRAY_SIZE(gdd->gdda_dir_attributes));
}
#ifdef CONFIG_NFSD_PNFS #ifdef CONFIG_NFSD_PNFS
static __be32 static __be32
nfsd4_decode_getdeviceinfo(struct nfsd4_compoundargs *argp, nfsd4_decode_getdeviceinfo(struct nfsd4_compoundargs *argp,
...@@ -2370,7 +2399,7 @@ static const nfsd4_dec nfsd4_dec_ops[] = { ...@@ -2370,7 +2399,7 @@ static const nfsd4_dec nfsd4_dec_ops[] = {
[OP_CREATE_SESSION] = nfsd4_decode_create_session, [OP_CREATE_SESSION] = nfsd4_decode_create_session,
[OP_DESTROY_SESSION] = nfsd4_decode_destroy_session, [OP_DESTROY_SESSION] = nfsd4_decode_destroy_session,
[OP_FREE_STATEID] = nfsd4_decode_free_stateid, [OP_FREE_STATEID] = nfsd4_decode_free_stateid,
[OP_GET_DIR_DELEGATION] = nfsd4_decode_notsupp, [OP_GET_DIR_DELEGATION] = nfsd4_decode_get_dir_delegation,
#ifdef CONFIG_NFSD_PNFS #ifdef CONFIG_NFSD_PNFS
[OP_GETDEVICEINFO] = nfsd4_decode_getdeviceinfo, [OP_GETDEVICEINFO] = nfsd4_decode_getdeviceinfo,
[OP_GETDEVICELIST] = nfsd4_decode_notsupp, [OP_GETDEVICELIST] = nfsd4_decode_notsupp,
...@@ -4963,6 +4992,49 @@ nfsd4_encode_test_stateid(struct nfsd4_compoundres *resp, __be32 nfserr, ...@@ -4963,6 +4992,49 @@ nfsd4_encode_test_stateid(struct nfsd4_compoundres *resp, __be32 nfserr,
return nfs_ok; return nfs_ok;
} }
static __be32
nfsd4_encode_get_dir_delegation(struct nfsd4_compoundres *resp, __be32 nfserr,
union nfsd4_op_u *u)
{
struct nfsd4_get_dir_delegation *gdd = &u->get_dir_delegation;
struct xdr_stream *xdr = resp->xdr;
__be32 status = nfserr_resource;
switch(gdd->gddrnf_status) {
case GDD4_OK:
if (xdr_stream_encode_u32(xdr, GDD4_OK) != XDR_UNIT)
break;
status = nfsd4_encode_verifier4(xdr, &gdd->gddr_cookieverf);
if (status)
break;
status = nfsd4_encode_stateid4(xdr, &gdd->gddr_stateid);
if (status)
break;
status = nfsd4_encode_bitmap4(xdr, gdd->gddr_notification[0], 0, 0);
if (status)
break;
status = nfsd4_encode_bitmap4(xdr, gdd->gddr_child_attributes[0],
gdd->gddr_child_attributes[1],
gdd->gddr_child_attributes[2]);
if (status)
break;
status = nfsd4_encode_bitmap4(xdr, gdd->gddr_dir_attributes[0],
gdd->gddr_dir_attributes[1],
gdd->gddr_dir_attributes[2]);
break;
default:
pr_warn("nfsd: bad gddrnf_status (%u)\n", gdd->gddrnf_status);
gdd->gddrnf_will_signal_deleg_avail = 0;
fallthrough;
case GDD4_UNAVAIL:
if (xdr_stream_encode_u32(xdr, GDD4_UNAVAIL) != XDR_UNIT)
break;
status = nfsd4_encode_bool(xdr, gdd->gddrnf_will_signal_deleg_avail);
break;
}
return status;
}
#ifdef CONFIG_NFSD_PNFS #ifdef CONFIG_NFSD_PNFS
static __be32 static __be32
nfsd4_encode_device_addr4(struct xdr_stream *xdr, nfsd4_encode_device_addr4(struct xdr_stream *xdr,
...@@ -5199,7 +5271,12 @@ nfsd4_encode_offload_status(struct nfsd4_compoundres *resp, __be32 nfserr, ...@@ -5199,7 +5271,12 @@ nfsd4_encode_offload_status(struct nfsd4_compoundres *resp, __be32 nfserr,
if (nfserr != nfs_ok) if (nfserr != nfs_ok)
return nfserr; return nfserr;
/* osr_complete<1> */ /* osr_complete<1> */
if (xdr_stream_encode_u32(xdr, 0) != XDR_UNIT) if (os->completed) {
if (xdr_stream_encode_u32(xdr, 1) != XDR_UNIT)
return nfserr_resource;
if (xdr_stream_encode_be32(xdr, os->status) != XDR_UNIT)
return nfserr_resource;
} else if (xdr_stream_encode_u32(xdr, 0) != XDR_UNIT)
return nfserr_resource; return nfserr_resource;
return nfs_ok; return nfs_ok;
} }
...@@ -5579,7 +5656,7 @@ static const nfsd4_enc nfsd4_enc_ops[] = { ...@@ -5579,7 +5656,7 @@ static const nfsd4_enc nfsd4_enc_ops[] = {
[OP_CREATE_SESSION] = nfsd4_encode_create_session, [OP_CREATE_SESSION] = nfsd4_encode_create_session,
[OP_DESTROY_SESSION] = nfsd4_encode_noop, [OP_DESTROY_SESSION] = nfsd4_encode_noop,
[OP_FREE_STATEID] = nfsd4_encode_noop, [OP_FREE_STATEID] = nfsd4_encode_noop,
[OP_GET_DIR_DELEGATION] = nfsd4_encode_noop, [OP_GET_DIR_DELEGATION] = nfsd4_encode_get_dir_delegation,
#ifdef CONFIG_NFSD_PNFS #ifdef CONFIG_NFSD_PNFS
[OP_GETDEVICEINFO] = nfsd4_encode_getdeviceinfo, [OP_GETDEVICEINFO] = nfsd4_encode_getdeviceinfo,
[OP_GETDEVICELIST] = nfsd4_encode_noop, [OP_GETDEVICELIST] = nfsd4_encode_noop,
......
This diff is collapsed.
...@@ -103,7 +103,7 @@ bool nfssvc_encode_voidres(struct svc_rqst *rqstp, ...@@ -103,7 +103,7 @@ bool nfssvc_encode_voidres(struct svc_rqst *rqstp,
/* /*
* Function prototypes. * Function prototypes.
*/ */
int nfsd_svc(int nrservs, struct net *net, const struct cred *cred); int nfsd_svc(int nrservs, struct net *net, const struct cred *cred, const char *scope);
int nfsd_dispatch(struct svc_rqst *rqstp); int nfsd_dispatch(struct svc_rqst *rqstp);
int nfsd_nrthreads(struct net *); int nfsd_nrthreads(struct net *);
...@@ -230,7 +230,6 @@ void nfsd_lockd_shutdown(void); ...@@ -230,7 +230,6 @@ void nfsd_lockd_shutdown(void);
#define nfserr_nospc cpu_to_be32(NFSERR_NOSPC) #define nfserr_nospc cpu_to_be32(NFSERR_NOSPC)
#define nfserr_rofs cpu_to_be32(NFSERR_ROFS) #define nfserr_rofs cpu_to_be32(NFSERR_ROFS)
#define nfserr_mlink cpu_to_be32(NFSERR_MLINK) #define nfserr_mlink cpu_to_be32(NFSERR_MLINK)
#define nfserr_opnotsupp cpu_to_be32(NFSERR_OPNOTSUPP)
#define nfserr_nametoolong cpu_to_be32(NFSERR_NAMETOOLONG) #define nfserr_nametoolong cpu_to_be32(NFSERR_NAMETOOLONG)
#define nfserr_notempty cpu_to_be32(NFSERR_NOTEMPTY) #define nfserr_notempty cpu_to_be32(NFSERR_NOTEMPTY)
#define nfserr_dquot cpu_to_be32(NFSERR_DQUOT) #define nfserr_dquot cpu_to_be32(NFSERR_DQUOT)
......
...@@ -573,7 +573,7 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, ...@@ -573,7 +573,7 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry,
_fh_update(fhp, exp, dentry); _fh_update(fhp, exp, dentry);
if (fhp->fh_handle.fh_fileid_type == FILEID_INVALID) { if (fhp->fh_handle.fh_fileid_type == FILEID_INVALID) {
fh_put(fhp); fh_put(fhp);
return nfserr_opnotsupp; return nfserr_stale;
} }
return 0; return 0;
...@@ -599,7 +599,7 @@ fh_update(struct svc_fh *fhp) ...@@ -599,7 +599,7 @@ fh_update(struct svc_fh *fhp)
_fh_update(fhp, fhp->fh_export, dentry); _fh_update(fhp, fhp->fh_export, dentry);
if (fhp->fh_handle.fh_fileid_type == FILEID_INVALID) if (fhp->fh_handle.fh_fileid_type == FILEID_INVALID)
return nfserr_opnotsupp; return nfserr_stale;
return 0; return 0;
out_bad: out_bad:
printk(KERN_ERR "fh_update: fh not verified!\n"); printk(KERN_ERR "fh_update: fh not verified!\n");
......
...@@ -133,8 +133,7 @@ struct svc_program nfsd_program = { ...@@ -133,8 +133,7 @@ struct svc_program nfsd_program = {
.pg_rpcbind_set = nfsd_rpcbind_set, .pg_rpcbind_set = nfsd_rpcbind_set,
}; };
static bool bool nfsd_support_version(int vers)
nfsd_support_version(int vers)
{ {
if (vers >= NFSD_MINVERS && vers < NFSD_NRVERS) if (vers >= NFSD_MINVERS && vers < NFSD_NRVERS)
return nfsd_version[vers] != NULL; return nfsd_version[vers] != NULL;
...@@ -769,13 +768,14 @@ int nfsd_set_nrthreads(int n, int *nthreads, struct net *net) ...@@ -769,13 +768,14 @@ int nfsd_set_nrthreads(int n, int *nthreads, struct net *net)
* this is the first time nrservs is nonzero. * this is the first time nrservs is nonzero.
*/ */
int int
nfsd_svc(int nrservs, struct net *net, const struct cred *cred) nfsd_svc(int nrservs, struct net *net, const struct cred *cred, const char *scope)
{ {
int error; int error;
struct nfsd_net *nn = net_generic(net, nfsd_net_id); struct nfsd_net *nn = net_generic(net, nfsd_net_id);
struct svc_serv *serv; struct svc_serv *serv;
mutex_lock(&nfsd_mutex); lockdep_assert_held(&nfsd_mutex);
dprintk("nfsd: creating service\n"); dprintk("nfsd: creating service\n");
nrservs = max(nrservs, 0); nrservs = max(nrservs, 0);
...@@ -785,7 +785,7 @@ nfsd_svc(int nrservs, struct net *net, const struct cred *cred) ...@@ -785,7 +785,7 @@ nfsd_svc(int nrservs, struct net *net, const struct cred *cred)
if (nrservs == 0 && nn->nfsd_serv == NULL) if (nrservs == 0 && nn->nfsd_serv == NULL)
goto out; goto out;
strscpy(nn->nfsd_name, utsname()->nodename, strscpy(nn->nfsd_name, scope ? scope : utsname()->nodename,
sizeof(nn->nfsd_name)); sizeof(nn->nfsd_name));
error = nfsd_create_serv(net); error = nfsd_create_serv(net);
...@@ -804,7 +804,6 @@ nfsd_svc(int nrservs, struct net *net, const struct cred *cred) ...@@ -804,7 +804,6 @@ nfsd_svc(int nrservs, struct net *net, const struct cred *cred)
if (serv->sv_nrthreads == 0) if (serv->sv_nrthreads == 0)
nfsd_destroy_serv(net); nfsd_destroy_serv(net);
out: out:
mutex_unlock(&nfsd_mutex);
return error; return error;
} }
......
...@@ -408,6 +408,8 @@ struct nfs4_client { ...@@ -408,6 +408,8 @@ struct nfs4_client {
1 << NFSD4_CLIENT_CB_KILL) 1 << NFSD4_CLIENT_CB_KILL)
#define NFSD4_CLIENT_CB_RECALL_ANY (6) #define NFSD4_CLIENT_CB_RECALL_ANY (6)
unsigned long cl_flags; unsigned long cl_flags;
struct workqueue_struct *cl_callback_wq;
const struct cred *cl_cb_cred; const struct cred *cl_cb_cred;
struct rpc_clnt *cl_cb_client; struct rpc_clnt *cl_cb_client;
u32 cl_cb_ident; u32 cl_cb_ident;
...@@ -486,7 +488,7 @@ struct nfs4_replay { ...@@ -486,7 +488,7 @@ struct nfs4_replay {
unsigned int rp_buflen; unsigned int rp_buflen;
char *rp_buf; char *rp_buf;
struct knfsd_fh rp_openfh; struct knfsd_fh rp_openfh;
struct mutex rp_mutex; atomic_t rp_locked;
char rp_ibuf[NFSD4_REPLAY_ISIZE]; char rp_ibuf[NFSD4_REPLAY_ISIZE];
}; };
...@@ -735,8 +737,6 @@ extern void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn * ...@@ -735,8 +737,6 @@ extern void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *
extern void nfsd4_init_cb(struct nfsd4_callback *cb, struct nfs4_client *clp, extern void nfsd4_init_cb(struct nfsd4_callback *cb, struct nfs4_client *clp,
const struct nfsd4_callback_ops *ops, enum nfsd4_cb_op op); const struct nfsd4_callback_ops *ops, enum nfsd4_cb_op op);
extern bool nfsd4_run_cb(struct nfsd4_callback *cb); extern bool nfsd4_run_cb(struct nfsd4_callback *cb);
extern int nfsd4_create_callback_queue(void);
extern void nfsd4_destroy_callback_queue(void);
extern void nfsd4_shutdown_callback(struct nfs4_client *); extern void nfsd4_shutdown_callback(struct nfs4_client *);
extern void nfsd4_shutdown_copy(struct nfs4_client *clp); extern void nfsd4_shutdown_copy(struct nfs4_client *clp);
extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(struct xdr_netobj name, extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(struct xdr_netobj name,
......
...@@ -73,48 +73,6 @@ static int nfsd_show(struct seq_file *seq, void *v) ...@@ -73,48 +73,6 @@ static int nfsd_show(struct seq_file *seq, void *v)
DEFINE_PROC_SHOW_ATTRIBUTE(nfsd); DEFINE_PROC_SHOW_ATTRIBUTE(nfsd);
int nfsd_percpu_counters_init(struct percpu_counter *counters, int num)
{
int i, err = 0;
for (i = 0; !err && i < num; i++)
err = percpu_counter_init(&counters[i], 0, GFP_KERNEL);
if (!err)
return 0;
for (; i > 0; i--)
percpu_counter_destroy(&counters[i-1]);
return err;
}
void nfsd_percpu_counters_reset(struct percpu_counter counters[], int num)
{
int i;
for (i = 0; i < num; i++)
percpu_counter_set(&counters[i], 0);
}
void nfsd_percpu_counters_destroy(struct percpu_counter counters[], int num)
{
int i;
for (i = 0; i < num; i++)
percpu_counter_destroy(&counters[i]);
}
int nfsd_stat_counters_init(struct nfsd_net *nn)
{
return nfsd_percpu_counters_init(nn->counter, NFSD_STATS_COUNTERS_NUM);
}
void nfsd_stat_counters_destroy(struct nfsd_net *nn)
{
nfsd_percpu_counters_destroy(nn->counter, NFSD_STATS_COUNTERS_NUM);
}
void nfsd_proc_stat_init(struct net *net) void nfsd_proc_stat_init(struct net *net)
{ {
struct nfsd_net *nn = net_generic(net, nfsd_net_id); struct nfsd_net *nn = net_generic(net, nfsd_net_id);
......
...@@ -10,11 +10,6 @@ ...@@ -10,11 +10,6 @@
#include <uapi/linux/nfsd/stats.h> #include <uapi/linux/nfsd/stats.h>
#include <linux/percpu_counter.h> #include <linux/percpu_counter.h>
int nfsd_percpu_counters_init(struct percpu_counter *counters, int num);
void nfsd_percpu_counters_reset(struct percpu_counter *counters, int num);
void nfsd_percpu_counters_destroy(struct percpu_counter *counters, int num);
int nfsd_stat_counters_init(struct nfsd_net *nn);
void nfsd_stat_counters_destroy(struct nfsd_net *nn);
void nfsd_proc_stat_init(struct net *net); void nfsd_proc_stat_init(struct net *net);
void nfsd_proc_stat_shutdown(struct net *net); void nfsd_proc_stat_shutdown(struct net *net);
......
...@@ -749,6 +749,76 @@ TRACE_EVENT_CONDITION(nfsd_seq4_status, ...@@ -749,6 +749,76 @@ TRACE_EVENT_CONDITION(nfsd_seq4_status,
) )
); );
DECLARE_EVENT_CLASS(nfsd_cs_slot_class,
TP_PROTO(
const struct nfs4_client *clp,
const struct nfsd4_create_session *cs
),
TP_ARGS(clp, cs),
TP_STRUCT__entry(
__field(u32, seqid)
__field(u32, slot_seqid)
__field(u32, cl_boot)
__field(u32, cl_id)
__sockaddr(addr, clp->cl_cb_conn.cb_addrlen)
),
TP_fast_assign(
const struct nfsd4_clid_slot *slot = &clp->cl_cs_slot;
__entry->cl_boot = clp->cl_clientid.cl_boot;
__entry->cl_id = clp->cl_clientid.cl_id;
__assign_sockaddr(addr, &clp->cl_cb_conn.cb_addr,
clp->cl_cb_conn.cb_addrlen);
__entry->seqid = cs->seqid;
__entry->slot_seqid = slot->sl_seqid;
),
TP_printk("addr=%pISpc client %08x:%08x seqid=%u slot_seqid=%u",
__get_sockaddr(addr), __entry->cl_boot, __entry->cl_id,
__entry->seqid, __entry->slot_seqid
)
);
#define DEFINE_CS_SLOT_EVENT(name) \
DEFINE_EVENT(nfsd_cs_slot_class, nfsd_##name, \
TP_PROTO( \
const struct nfs4_client *clp, \
const struct nfsd4_create_session *cs \
), \
TP_ARGS(clp, cs))
DEFINE_CS_SLOT_EVENT(slot_seqid_conf);
DEFINE_CS_SLOT_EVENT(slot_seqid_unconf);
TRACE_EVENT(nfsd_slot_seqid_sequence,
TP_PROTO(
const struct nfs4_client *clp,
const struct nfsd4_sequence *seq,
const struct nfsd4_slot *slot
),
TP_ARGS(clp, seq, slot),
TP_STRUCT__entry(
__field(u32, seqid)
__field(u32, slot_seqid)
__field(u32, cl_boot)
__field(u32, cl_id)
__sockaddr(addr, clp->cl_cb_conn.cb_addrlen)
__field(bool, in_use)
),
TP_fast_assign(
__entry->cl_boot = clp->cl_clientid.cl_boot;
__entry->cl_id = clp->cl_clientid.cl_id;
__assign_sockaddr(addr, &clp->cl_cb_conn.cb_addr,
clp->cl_cb_conn.cb_addrlen);
__entry->seqid = seq->seqid;
__entry->slot_seqid = slot->sl_seqid;
),
TP_printk("addr=%pISpc client %08x:%08x seqid=%u slot_seqid=%u (%sin use)",
__get_sockaddr(addr), __entry->cl_boot, __entry->cl_id,
__entry->seqid, __entry->slot_seqid,
__entry->in_use ? "" : "not "
)
);
DECLARE_EVENT_CLASS(nfsd_clientid_class, DECLARE_EVENT_CLASS(nfsd_clientid_class,
TP_PROTO(const clientid_t *clid), TP_PROTO(const clientid_t *clid),
TP_ARGS(clid), TP_ARGS(clid),
...@@ -778,6 +848,30 @@ DEFINE_CLIENTID_EVENT(purged); ...@@ -778,6 +848,30 @@ DEFINE_CLIENTID_EVENT(purged);
DEFINE_CLIENTID_EVENT(renew); DEFINE_CLIENTID_EVENT(renew);
DEFINE_CLIENTID_EVENT(stale); DEFINE_CLIENTID_EVENT(stale);
TRACE_EVENT(nfsd_mark_client_expired,
TP_PROTO(
const struct nfs4_client *clp,
int cl_rpc_users
),
TP_ARGS(clp, cl_rpc_users),
TP_STRUCT__entry(
__field(int, cl_rpc_users)
__field(u32, cl_boot)
__field(u32, cl_id)
__sockaddr(addr, clp->cl_cb_conn.cb_addrlen)
),
TP_fast_assign(
__entry->cl_rpc_users = cl_rpc_users;
__entry->cl_boot = clp->cl_clientid.cl_boot;
__entry->cl_id = clp->cl_clientid.cl_id;
__assign_sockaddr(addr, &clp->cl_cb_conn.cb_addr,
clp->cl_cb_conn.cb_addrlen)
),
TP_printk("addr=%pISpc client %08x:%08x cl_rpc_users=%d",
__get_sockaddr(addr), __entry->cl_boot, __entry->cl_id,
__entry->cl_rpc_users)
);
DECLARE_EVENT_CLASS(nfsd_net_class, DECLARE_EVENT_CLASS(nfsd_net_class,
TP_PROTO(const struct nfsd_net *nn), TP_PROTO(const struct nfsd_net *nn),
TP_ARGS(nn), TP_ARGS(nn),
...@@ -1534,7 +1628,7 @@ TRACE_EVENT(nfsd_cb_seq_status, ...@@ -1534,7 +1628,7 @@ TRACE_EVENT(nfsd_cb_seq_status,
__entry->seq_status = cb->cb_seq_status; __entry->seq_status = cb->cb_seq_status;
), ),
TP_printk(SUNRPC_TRACE_TASK_SPECIFIER TP_printk(SUNRPC_TRACE_TASK_SPECIFIER
" sessionid=%08x:%08x:%08x:%08x tk_status=%d seq_status=%d\n", " sessionid=%08x:%08x:%08x:%08x tk_status=%d seq_status=%d",
__entry->task_id, __entry->client_id, __entry->task_id, __entry->client_id,
__entry->cl_boot, __entry->cl_id, __entry->cl_boot, __entry->cl_id,
__entry->seqno, __entry->reserved, __entry->seqno, __entry->reserved,
...@@ -1573,7 +1667,7 @@ TRACE_EVENT(nfsd_cb_free_slot, ...@@ -1573,7 +1667,7 @@ TRACE_EVENT(nfsd_cb_free_slot,
__entry->slot_seqno = session->se_cb_seq_nr; __entry->slot_seqno = session->se_cb_seq_nr;
), ),
TP_printk(SUNRPC_TRACE_TASK_SPECIFIER TP_printk(SUNRPC_TRACE_TASK_SPECIFIER
" sessionid=%08x:%08x:%08x:%08x new slot seqno=%u\n", " sessionid=%08x:%08x:%08x:%08x new slot seqno=%u",
__entry->task_id, __entry->client_id, __entry->task_id, __entry->client_id,
__entry->cl_boot, __entry->cl_id, __entry->cl_boot, __entry->cl_id,
__entry->seqno, __entry->reserved, __entry->seqno, __entry->reserved,
...@@ -1978,7 +2072,7 @@ TRACE_EVENT(nfsd_ctl_time, ...@@ -1978,7 +2072,7 @@ TRACE_EVENT(nfsd_ctl_time,
__entry->time = time; __entry->time = time;
__assign_str(name, name); __assign_str(name, name);
), ),
TP_printk("file=%s time=%d\n", TP_printk("file=%s time=%d",
__get_str(name), __entry->time __get_str(name), __entry->time
) )
); );
......
...@@ -1422,7 +1422,7 @@ nfsd_create_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, ...@@ -1422,7 +1422,7 @@ nfsd_create_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp,
* Callers expect new file metadata to be committed even * Callers expect new file metadata to be committed even
* if the attributes have not changed. * if the attributes have not changed.
*/ */
if (iap->ia_valid) if (nfsd_attrs_valid(attrs))
status = nfsd_setattr(rqstp, resfhp, attrs, NULL); status = nfsd_setattr(rqstp, resfhp, attrs, NULL);
else else
status = nfserrno(commit_metadata(resfhp)); status = nfserrno(commit_metadata(resfhp));
......
...@@ -60,6 +60,14 @@ static inline void nfsd_attrs_free(struct nfsd_attrs *attrs) ...@@ -60,6 +60,14 @@ static inline void nfsd_attrs_free(struct nfsd_attrs *attrs)
posix_acl_release(attrs->na_dpacl); posix_acl_release(attrs->na_dpacl);
} }
static inline bool nfsd_attrs_valid(struct nfsd_attrs *attrs)
{
struct iattr *iap = attrs->na_iattr;
return (iap->ia_valid || (attrs->na_seclabel &&
attrs->na_seclabel->len));
}
__be32 nfserrno (int errno); __be32 nfserrno (int errno);
int nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp, int nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp,
struct svc_export **expp); struct svc_export **expp);
......
...@@ -518,6 +518,24 @@ struct nfsd4_free_stateid { ...@@ -518,6 +518,24 @@ struct nfsd4_free_stateid {
stateid_t fr_stateid; /* request */ stateid_t fr_stateid; /* request */
}; };
struct nfsd4_get_dir_delegation {
/* request */
u32 gdda_signal_deleg_avail;
u32 gdda_notification_types[1];
struct timespec64 gdda_child_attr_delay;
struct timespec64 gdda_dir_attr_delay;
u32 gdda_child_attributes[3];
u32 gdda_dir_attributes[3];
/* response */
u32 gddrnf_status;
nfs4_verifier gddr_cookieverf;
stateid_t gddr_stateid;
u32 gddr_notification[1];
u32 gddr_child_attributes[3];
u32 gddr_dir_attributes[3];
bool gddrnf_will_signal_deleg_avail;
};
/* also used for NVERIFY */ /* also used for NVERIFY */
struct nfsd4_verify { struct nfsd4_verify {
u32 ve_bmval[3]; /* request */ u32 ve_bmval[3]; /* request */
...@@ -674,8 +692,10 @@ struct nfsd4_copy { ...@@ -674,8 +692,10 @@ struct nfsd4_copy {
#define NFSD4_COPY_F_INTRA (1) #define NFSD4_COPY_F_INTRA (1)
#define NFSD4_COPY_F_SYNCHRONOUS (2) #define NFSD4_COPY_F_SYNCHRONOUS (2)
#define NFSD4_COPY_F_COMMITTED (3) #define NFSD4_COPY_F_COMMITTED (3)
#define NFSD4_COPY_F_COMPLETED (4)
/* response */ /* response */
__be32 nfserr;
struct nfsd42_write_res cp_res; struct nfsd42_write_res cp_res;
struct knfsd_fh fh; struct knfsd_fh fh;
...@@ -735,7 +755,8 @@ struct nfsd4_offload_status { ...@@ -735,7 +755,8 @@ struct nfsd4_offload_status {
/* response */ /* response */
u64 count; u64 count;
u32 status; __be32 status;
bool completed;
}; };
struct nfsd4_copy_notify { struct nfsd4_copy_notify {
...@@ -797,6 +818,7 @@ struct nfsd4_op { ...@@ -797,6 +818,7 @@ struct nfsd4_op {
struct nfsd4_reclaim_complete reclaim_complete; struct nfsd4_reclaim_complete reclaim_complete;
struct nfsd4_test_stateid test_stateid; struct nfsd4_test_stateid test_stateid;
struct nfsd4_free_stateid free_stateid; struct nfsd4_free_stateid free_stateid;
struct nfsd4_get_dir_delegation get_dir_delegation;
struct nfsd4_getdeviceinfo getdeviceinfo; struct nfsd4_getdeviceinfo getdeviceinfo;
struct nfsd4_layoutget layoutget; struct nfsd4_layoutget layoutget;
struct nfsd4_layoutcommit layoutcommit; struct nfsd4_layoutcommit layoutcommit;
......
...@@ -701,6 +701,12 @@ enum state_protect_how4 { ...@@ -701,6 +701,12 @@ enum state_protect_how4 {
SP4_SSV = 2 SP4_SSV = 2
}; };
/* GET_DIR_DELEGATION non-fatal status codes */
enum gddrnf4_status {
GDD4_OK = 0,
GDD4_UNAVAIL = 1
};
enum pnfs_layouttype { enum pnfs_layouttype {
LAYOUT_NFSV4_1_FILES = 1, LAYOUT_NFSV4_1_FILES = 1,
LAYOUT_OSD2_OBJECTS = 2, LAYOUT_OSD2_OBJECTS = 2,
......
...@@ -135,6 +135,9 @@ int svc_reg_xprt_class(struct svc_xprt_class *); ...@@ -135,6 +135,9 @@ int svc_reg_xprt_class(struct svc_xprt_class *);
void svc_unreg_xprt_class(struct svc_xprt_class *); void svc_unreg_xprt_class(struct svc_xprt_class *);
void svc_xprt_init(struct net *, struct svc_xprt_class *, struct svc_xprt *, void svc_xprt_init(struct net *, struct svc_xprt_class *, struct svc_xprt *,
struct svc_serv *); struct svc_serv *);
int svc_xprt_create_from_sa(struct svc_serv *serv, const char *xprt_name,
struct net *net, struct sockaddr *sap,
int flags, const struct cred *cred);
int svc_xprt_create(struct svc_serv *serv, const char *xprt_name, int svc_xprt_create(struct svc_serv *serv, const char *xprt_name,
struct net *net, const int family, struct net *net, const int family,
const unsigned short port, int flags, const unsigned short port, int flags,
...@@ -147,6 +150,8 @@ void svc_xprt_copy_addrs(struct svc_rqst *rqstp, struct svc_xprt *xprt); ...@@ -147,6 +150,8 @@ void svc_xprt_copy_addrs(struct svc_rqst *rqstp, struct svc_xprt *xprt);
void svc_xprt_close(struct svc_xprt *xprt); void svc_xprt_close(struct svc_xprt *xprt);
int svc_port_is_privileged(struct sockaddr *sin); int svc_port_is_privileged(struct sockaddr *sin);
int svc_print_xprts(char *buf, int maxlen); int svc_print_xprts(char *buf, int maxlen);
struct svc_xprt *svc_find_listener(struct svc_serv *serv, const char *xcl_name,
struct net *net, const struct sockaddr *sa);
struct svc_xprt *svc_find_xprt(struct svc_serv *serv, const char *xcl_name, struct svc_xprt *svc_find_xprt(struct svc_serv *serv, const char *xcl_name,
struct net *net, const sa_family_t af, struct net *net, const sa_family_t af,
const unsigned short port); const unsigned short port);
......
...@@ -28,7 +28,6 @@ TRACE_DEFINE_ENUM(NFSERR_FBIG); ...@@ -28,7 +28,6 @@ TRACE_DEFINE_ENUM(NFSERR_FBIG);
TRACE_DEFINE_ENUM(NFSERR_NOSPC); TRACE_DEFINE_ENUM(NFSERR_NOSPC);
TRACE_DEFINE_ENUM(NFSERR_ROFS); TRACE_DEFINE_ENUM(NFSERR_ROFS);
TRACE_DEFINE_ENUM(NFSERR_MLINK); TRACE_DEFINE_ENUM(NFSERR_MLINK);
TRACE_DEFINE_ENUM(NFSERR_OPNOTSUPP);
TRACE_DEFINE_ENUM(NFSERR_NAMETOOLONG); TRACE_DEFINE_ENUM(NFSERR_NAMETOOLONG);
TRACE_DEFINE_ENUM(NFSERR_NOTEMPTY); TRACE_DEFINE_ENUM(NFSERR_NOTEMPTY);
TRACE_DEFINE_ENUM(NFSERR_DQUOT); TRACE_DEFINE_ENUM(NFSERR_DQUOT);
...@@ -64,7 +63,6 @@ TRACE_DEFINE_ENUM(NFSERR_JUKEBOX); ...@@ -64,7 +63,6 @@ TRACE_DEFINE_ENUM(NFSERR_JUKEBOX);
{ NFSERR_NOSPC, "NOSPC" }, \ { NFSERR_NOSPC, "NOSPC" }, \
{ NFSERR_ROFS, "ROFS" }, \ { NFSERR_ROFS, "ROFS" }, \
{ NFSERR_MLINK, "MLINK" }, \ { NFSERR_MLINK, "MLINK" }, \
{ NFSERR_OPNOTSUPP, "OPNOTSUPP" }, \
{ NFSERR_NAMETOOLONG, "NAMETOOLONG" }, \ { NFSERR_NAMETOOLONG, "NAMETOOLONG" }, \
{ NFSERR_NOTEMPTY, "NOTEMPTY" }, \ { NFSERR_NOTEMPTY, "NOTEMPTY" }, \
{ NFSERR_DQUOT, "DQUOT" }, \ { NFSERR_DQUOT, "DQUOT" }, \
......
...@@ -61,7 +61,6 @@ ...@@ -61,7 +61,6 @@
NFSERR_NOSPC = 28, /* v2 v3 v4 */ NFSERR_NOSPC = 28, /* v2 v3 v4 */
NFSERR_ROFS = 30, /* v2 v3 v4 */ NFSERR_ROFS = 30, /* v2 v3 v4 */
NFSERR_MLINK = 31, /* v3 v4 */ NFSERR_MLINK = 31, /* v3 v4 */
NFSERR_OPNOTSUPP = 45, /* v2 v3 */
NFSERR_NAMETOOLONG = 63, /* v2 v3 v4 */ NFSERR_NAMETOOLONG = 63, /* v2 v3 v4 */
NFSERR_NOTEMPTY = 66, /* v2 v3 v4 */ NFSERR_NOTEMPTY = 66, /* v2 v3 v4 */
NFSERR_DQUOT = 69, /* v2 v3 v4 */ NFSERR_DQUOT = 69, /* v2 v3 v4 */
......
...@@ -29,8 +29,55 @@ enum { ...@@ -29,8 +29,55 @@ enum {
NFSD_A_RPC_STATUS_MAX = (__NFSD_A_RPC_STATUS_MAX - 1) NFSD_A_RPC_STATUS_MAX = (__NFSD_A_RPC_STATUS_MAX - 1)
}; };
enum {
NFSD_A_SERVER_THREADS = 1,
NFSD_A_SERVER_GRACETIME,
NFSD_A_SERVER_LEASETIME,
NFSD_A_SERVER_SCOPE,
__NFSD_A_SERVER_MAX,
NFSD_A_SERVER_MAX = (__NFSD_A_SERVER_MAX - 1)
};
enum {
NFSD_A_VERSION_MAJOR = 1,
NFSD_A_VERSION_MINOR,
NFSD_A_VERSION_ENABLED,
__NFSD_A_VERSION_MAX,
NFSD_A_VERSION_MAX = (__NFSD_A_VERSION_MAX - 1)
};
enum {
NFSD_A_SERVER_PROTO_VERSION = 1,
__NFSD_A_SERVER_PROTO_MAX,
NFSD_A_SERVER_PROTO_MAX = (__NFSD_A_SERVER_PROTO_MAX - 1)
};
enum {
NFSD_A_SOCK_ADDR = 1,
NFSD_A_SOCK_TRANSPORT_NAME,
__NFSD_A_SOCK_MAX,
NFSD_A_SOCK_MAX = (__NFSD_A_SOCK_MAX - 1)
};
enum {
NFSD_A_SERVER_SOCK_ADDR = 1,
__NFSD_A_SERVER_SOCK_MAX,
NFSD_A_SERVER_SOCK_MAX = (__NFSD_A_SERVER_SOCK_MAX - 1)
};
enum { enum {
NFSD_CMD_RPC_STATUS_GET = 1, NFSD_CMD_RPC_STATUS_GET = 1,
NFSD_CMD_THREADS_SET,
NFSD_CMD_THREADS_GET,
NFSD_CMD_VERSION_SET,
NFSD_CMD_VERSION_GET,
NFSD_CMD_LISTENER_SET,
NFSD_CMD_LISTENER_GET,
__NFSD_CMD_MAX, __NFSD_CMD_MAX,
NFSD_CMD_MAX = (__NFSD_CMD_MAX - 1) NFSD_CMD_MAX = (__NFSD_CMD_MAX - 1)
......
...@@ -1033,17 +1033,11 @@ svcauth_gss_proc_init_verf(struct cache_detail *cd, struct svc_rqst *rqstp, ...@@ -1033,17 +1033,11 @@ svcauth_gss_proc_init_verf(struct cache_detail *cd, struct svc_rqst *rqstp,
static void gss_free_in_token_pages(struct gssp_in_token *in_token) static void gss_free_in_token_pages(struct gssp_in_token *in_token)
{ {
u32 inlen;
int i; int i;
i = 0; i = 0;
inlen = in_token->page_len; while (in_token->pages[i])
while (inlen) { put_page(in_token->pages[i++]);
if (in_token->pages[i])
put_page(in_token->pages[i]);
inlen -= inlen > PAGE_SIZE ? PAGE_SIZE : inlen;
}
kfree(in_token->pages); kfree(in_token->pages);
in_token->pages = NULL; in_token->pages = NULL;
} }
......
...@@ -1265,8 +1265,6 @@ svc_generic_init_request(struct svc_rqst *rqstp, ...@@ -1265,8 +1265,6 @@ svc_generic_init_request(struct svc_rqst *rqstp,
if (rqstp->rq_proc >= versp->vs_nproc) if (rqstp->rq_proc >= versp->vs_nproc)
goto err_bad_proc; goto err_bad_proc;
rqstp->rq_procinfo = procp = &versp->vs_proc[rqstp->rq_proc]; rqstp->rq_procinfo = procp = &versp->vs_proc[rqstp->rq_proc];
if (!procp)
goto err_bad_proc;
/* Initialize storage for argp and resp */ /* Initialize storage for argp and resp */
memset(rqstp->rq_argp, 0, procp->pc_argzero); memset(rqstp->rq_argp, 0, procp->pc_argzero);
......
...@@ -46,7 +46,6 @@ static LIST_HEAD(svc_xprt_class_list); ...@@ -46,7 +46,6 @@ static LIST_HEAD(svc_xprt_class_list);
/* SMP locking strategy: /* SMP locking strategy:
* *
* svc_pool->sp_lock protects most of the fields of that pool.
* svc_serv->sv_lock protects sv_tempsocks, sv_permsocks, sv_tmpcnt. * svc_serv->sv_lock protects sv_tempsocks, sv_permsocks, sv_tmpcnt.
* when both need to be taken (rare), svc_serv->sv_lock is first. * when both need to be taken (rare), svc_serv->sv_lock is first.
* The "service mutex" protects svc_serv->sv_nrthread. * The "service mutex" protects svc_serv->sv_nrthread.
...@@ -211,51 +210,6 @@ void svc_xprt_init(struct net *net, struct svc_xprt_class *xcl, ...@@ -211,51 +210,6 @@ void svc_xprt_init(struct net *net, struct svc_xprt_class *xcl,
} }
EXPORT_SYMBOL_GPL(svc_xprt_init); EXPORT_SYMBOL_GPL(svc_xprt_init);
static struct svc_xprt *__svc_xpo_create(struct svc_xprt_class *xcl,
struct svc_serv *serv,
struct net *net,
const int family,
const unsigned short port,
int flags)
{
struct sockaddr_in sin = {
.sin_family = AF_INET,
.sin_addr.s_addr = htonl(INADDR_ANY),
.sin_port = htons(port),
};
#if IS_ENABLED(CONFIG_IPV6)
struct sockaddr_in6 sin6 = {
.sin6_family = AF_INET6,
.sin6_addr = IN6ADDR_ANY_INIT,
.sin6_port = htons(port),
};
#endif
struct svc_xprt *xprt;
struct sockaddr *sap;
size_t len;
switch (family) {
case PF_INET:
sap = (struct sockaddr *)&sin;
len = sizeof(sin);
break;
#if IS_ENABLED(CONFIG_IPV6)
case PF_INET6:
sap = (struct sockaddr *)&sin6;
len = sizeof(sin6);
break;
#endif
default:
return ERR_PTR(-EAFNOSUPPORT);
}
xprt = xcl->xcl_ops->xpo_create(serv, net, sap, len, flags);
if (IS_ERR(xprt))
trace_svc_xprt_create_err(serv->sv_program->pg_name,
xcl->xcl_name, sap, len, xprt);
return xprt;
}
/** /**
* svc_xprt_received - start next receiver thread * svc_xprt_received - start next receiver thread
* @xprt: controlling transport * @xprt: controlling transport
...@@ -294,9 +248,8 @@ void svc_add_new_perm_xprt(struct svc_serv *serv, struct svc_xprt *new) ...@@ -294,9 +248,8 @@ void svc_add_new_perm_xprt(struct svc_serv *serv, struct svc_xprt *new)
} }
static int _svc_xprt_create(struct svc_serv *serv, const char *xprt_name, static int _svc_xprt_create(struct svc_serv *serv, const char *xprt_name,
struct net *net, const int family, struct net *net, struct sockaddr *sap,
const unsigned short port, int flags, size_t len, int flags, const struct cred *cred)
const struct cred *cred)
{ {
struct svc_xprt_class *xcl; struct svc_xprt_class *xcl;
...@@ -312,8 +265,11 @@ static int _svc_xprt_create(struct svc_serv *serv, const char *xprt_name, ...@@ -312,8 +265,11 @@ static int _svc_xprt_create(struct svc_serv *serv, const char *xprt_name,
goto err; goto err;
spin_unlock(&svc_xprt_class_lock); spin_unlock(&svc_xprt_class_lock);
newxprt = __svc_xpo_create(xcl, serv, net, family, port, flags); newxprt = xcl->xcl_ops->xpo_create(serv, net, sap, len, flags);
if (IS_ERR(newxprt)) { if (IS_ERR(newxprt)) {
trace_svc_xprt_create_err(serv->sv_program->pg_name,
xcl->xcl_name, sap, len,
newxprt);
module_put(xcl->xcl_owner); module_put(xcl->xcl_owner);
return PTR_ERR(newxprt); return PTR_ERR(newxprt);
} }
...@@ -329,6 +285,48 @@ static int _svc_xprt_create(struct svc_serv *serv, const char *xprt_name, ...@@ -329,6 +285,48 @@ static int _svc_xprt_create(struct svc_serv *serv, const char *xprt_name,
return -EPROTONOSUPPORT; return -EPROTONOSUPPORT;
} }
/**
* svc_xprt_create_from_sa - Add a new listener to @serv from socket address
* @serv: target RPC service
* @xprt_name: transport class name
* @net: network namespace
* @sap: socket address pointer
* @flags: SVC_SOCK flags
* @cred: credential to bind to this transport
*
* Return local xprt port on success or %-EPROTONOSUPPORT on failure
*/
int svc_xprt_create_from_sa(struct svc_serv *serv, const char *xprt_name,
struct net *net, struct sockaddr *sap,
int flags, const struct cred *cred)
{
size_t len;
int err;
switch (sap->sa_family) {
case AF_INET:
len = sizeof(struct sockaddr_in);
break;
#if IS_ENABLED(CONFIG_IPV6)
case AF_INET6:
len = sizeof(struct sockaddr_in6);
break;
#endif
default:
return -EAFNOSUPPORT;
}
err = _svc_xprt_create(serv, xprt_name, net, sap, len, flags, cred);
if (err == -EPROTONOSUPPORT) {
request_module("svc%s", xprt_name);
err = _svc_xprt_create(serv, xprt_name, net, sap, len, flags,
cred);
}
return err;
}
EXPORT_SYMBOL_GPL(svc_xprt_create_from_sa);
/** /**
* svc_xprt_create - Add a new listener to @serv * svc_xprt_create - Add a new listener to @serv
* @serv: target RPC service * @serv: target RPC service
...@@ -339,23 +337,41 @@ static int _svc_xprt_create(struct svc_serv *serv, const char *xprt_name, ...@@ -339,23 +337,41 @@ static int _svc_xprt_create(struct svc_serv *serv, const char *xprt_name,
* @flags: SVC_SOCK flags * @flags: SVC_SOCK flags
* @cred: credential to bind to this transport * @cred: credential to bind to this transport
* *
* Return values: * Return local xprt port on success or %-EPROTONOSUPPORT on failure
* %0: New listener added successfully
* %-EPROTONOSUPPORT: Requested transport type not supported
*/ */
int svc_xprt_create(struct svc_serv *serv, const char *xprt_name, int svc_xprt_create(struct svc_serv *serv, const char *xprt_name,
struct net *net, const int family, struct net *net, const int family,
const unsigned short port, int flags, const unsigned short port, int flags,
const struct cred *cred) const struct cred *cred)
{ {
int err; struct sockaddr_in sin = {
.sin_family = AF_INET,
.sin_addr.s_addr = htonl(INADDR_ANY),
.sin_port = htons(port),
};
#if IS_ENABLED(CONFIG_IPV6)
struct sockaddr_in6 sin6 = {
.sin6_family = AF_INET6,
.sin6_addr = IN6ADDR_ANY_INIT,
.sin6_port = htons(port),
};
#endif
struct sockaddr *sap;
err = _svc_xprt_create(serv, xprt_name, net, family, port, flags, cred); switch (family) {
if (err == -EPROTONOSUPPORT) { case PF_INET:
request_module("svc%s", xprt_name); sap = (struct sockaddr *)&sin;
err = _svc_xprt_create(serv, xprt_name, net, family, port, flags, cred); break;
#if IS_ENABLED(CONFIG_IPV6)
case PF_INET6:
sap = (struct sockaddr *)&sin6;
break;
#endif
default:
return -EAFNOSUPPORT;
} }
return err;
return svc_xprt_create_from_sa(serv, xprt_name, net, sap, flags, cred);
} }
EXPORT_SYMBOL_GPL(svc_xprt_create); EXPORT_SYMBOL_GPL(svc_xprt_create);
...@@ -1259,6 +1275,40 @@ static struct svc_deferred_req *svc_deferred_dequeue(struct svc_xprt *xprt) ...@@ -1259,6 +1275,40 @@ static struct svc_deferred_req *svc_deferred_dequeue(struct svc_xprt *xprt)
return dr; return dr;
} }
/**
* svc_find_listener - find an RPC transport instance
* @serv: pointer to svc_serv to search
* @xcl_name: C string containing transport's class name
* @net: owner net pointer
* @sa: sockaddr containing address
*
* Return the transport instance pointer for the endpoint accepting
* connections/peer traffic from the specified transport class,
* and matching sockaddr.
*/
struct svc_xprt *svc_find_listener(struct svc_serv *serv, const char *xcl_name,
struct net *net, const struct sockaddr *sa)
{
struct svc_xprt *xprt;
struct svc_xprt *found = NULL;
spin_lock_bh(&serv->sv_lock);
list_for_each_entry(xprt, &serv->sv_permsocks, xpt_list) {
if (xprt->xpt_net != net)
continue;
if (strcmp(xprt->xpt_class->xcl_name, xcl_name))
continue;
if (!rpc_cmp_addr_port(sa, (struct sockaddr *)&xprt->xpt_local))
continue;
found = xprt;
svc_xprt_get(xprt);
break;
}
spin_unlock_bh(&serv->sv_lock);
return found;
}
EXPORT_SYMBOL_GPL(svc_find_listener);
/** /**
* svc_find_xprt - find an RPC transport instance * svc_find_xprt - find an RPC transport instance
* @serv: pointer to svc_serv to search * @serv: pointer to svc_serv to search
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment