mirror of
https://github.com/torvalds/linux.git
synced 2026-05-12 16:18:45 +02:00
Now that all NLMv4 server-side procedures use XDR encoder and decoder functions generated by xdrgen, the hand-written code in fs/lockd/xdr4.c is no longer needed. This file contained the original XDR processing logic that has been systematically replaced throughout this series. Remove the file and its Makefile reference to eliminate the dead code. The helper function nlm4svc_set_file_lock_range() is still needed by the generated code, so move it to xdr4.h as an inline function where it remains accessible. Reviewed-by: Jeff Layton <jlayton@kernel.org> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
1425 lines
40 KiB
C
1425 lines
40 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* linux/fs/lockd/svc4proc.c
|
|
*
|
|
* Lockd server procedures. We don't implement the NLM_*_RES
|
|
* procedures because we don't use the async procedures.
|
|
*
|
|
* Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
|
|
*/
|
|
|
|
#include <linux/types.h>
|
|
#include <linux/time.h>
|
|
#include <linux/sunrpc/svc_xprt.h>
|
|
|
|
#include "lockd.h"
|
|
|
|
/*
|
|
* xdr.h defines SM_MAXSTRLEN and SM_PRIV_SIZE as macros.
|
|
* nlm4xdr_gen.h defines them as enum constants. Undefine the
|
|
* macros to allow the xdrgen enum definitions to be used.
|
|
*/
|
|
#undef SM_MAXSTRLEN
|
|
#undef SM_PRIV_SIZE
|
|
|
|
#include "share.h"
|
|
#include "nlm4xdr_gen.h"
|
|
|
|
/*
|
|
* Wrapper structures combine xdrgen types with legacy nlm_lock.
|
|
* The xdrgen field must be first so the structure can be cast
|
|
* to its XDR type for the RPC dispatch layer.
|
|
*/
|
|
struct nlm4_testargs_wrapper {
|
|
struct nlm4_testargs xdrgen;
|
|
struct nlm_lock lock;
|
|
};
|
|
|
|
static_assert(offsetof(struct nlm4_testargs_wrapper, xdrgen) == 0);
|
|
|
|
struct nlm4_lockargs_wrapper {
|
|
struct nlm4_lockargs xdrgen;
|
|
struct nlm_cookie cookie;
|
|
struct nlm_lock lock;
|
|
};
|
|
|
|
static_assert(offsetof(struct nlm4_lockargs_wrapper, xdrgen) == 0);
|
|
|
|
struct nlm4_cancargs_wrapper {
|
|
struct nlm4_cancargs xdrgen;
|
|
struct nlm_lock lock;
|
|
};
|
|
|
|
static_assert(offsetof(struct nlm4_cancargs_wrapper, xdrgen) == 0);
|
|
|
|
struct nlm4_unlockargs_wrapper {
|
|
struct nlm4_unlockargs xdrgen;
|
|
struct nlm_lock lock;
|
|
};
|
|
|
|
static_assert(offsetof(struct nlm4_unlockargs_wrapper, xdrgen) == 0);
|
|
|
|
struct nlm4_notifyargs_wrapper {
|
|
struct nlm4_notifyargs xdrgen;
|
|
struct nlm_reboot reboot;
|
|
};
|
|
|
|
static_assert(offsetof(struct nlm4_notifyargs_wrapper, xdrgen) == 0);
|
|
|
|
struct nlm4_notify_wrapper {
|
|
struct nlm4_notify xdrgen;
|
|
};
|
|
|
|
static_assert(offsetof(struct nlm4_notify_wrapper, xdrgen) == 0);
|
|
|
|
struct nlm4_testres_wrapper {
|
|
struct nlm4_testres xdrgen;
|
|
struct nlm_lock lock;
|
|
};
|
|
|
|
struct nlm4_shareargs_wrapper {
|
|
struct nlm4_shareargs xdrgen;
|
|
struct nlm_lock lock;
|
|
};
|
|
|
|
static_assert(offsetof(struct nlm4_shareargs_wrapper, xdrgen) == 0);
|
|
|
|
static_assert(offsetof(struct nlm4_testres_wrapper, xdrgen) == 0);
|
|
|
|
struct nlm4_res_wrapper {
|
|
struct nlm4_res xdrgen;
|
|
struct nlm_cookie cookie;
|
|
};
|
|
|
|
static_assert(offsetof(struct nlm4_res_wrapper, xdrgen) == 0);
|
|
|
|
struct nlm4_shareres_wrapper {
|
|
struct nlm4_shareres xdrgen;
|
|
};
|
|
|
|
static_assert(offsetof(struct nlm4_shareres_wrapper, xdrgen) == 0);
|
|
|
|
static __be32
|
|
nlm4_netobj_to_cookie(struct nlm_cookie *cookie, netobj *object)
|
|
{
|
|
if (object->len > NLM_MAXCOOKIELEN)
|
|
return nlm_lck_denied_nolocks;
|
|
cookie->len = object->len;
|
|
memcpy(cookie->data, object->data, object->len);
|
|
return nlm_granted;
|
|
}
|
|
|
|
static __be32
|
|
nlm4_lock_to_nlm_lock(struct nlm_lock *lock, struct nlm4_lock *alock)
|
|
{
|
|
if (alock->fh.len > NFS_MAXFHSIZE)
|
|
return nlm_lck_denied;
|
|
lock->fh.size = alock->fh.len;
|
|
memcpy(lock->fh.data, alock->fh.data, alock->fh.len);
|
|
lock->oh.len = alock->oh.len;
|
|
lock->oh.data = alock->oh.data;
|
|
lock->svid = alock->svid;
|
|
locks_init_lock(&lock->fl);
|
|
lockd_set_file_lock_range4(&lock->fl, alock->l_offset, alock->l_len);
|
|
return nlm_granted;
|
|
}
|
|
|
|
static struct nlm_host *
|
|
nlm4svc_lookup_host(struct svc_rqst *rqstp, string caller, bool monitored)
|
|
{
|
|
struct nlm_host *host;
|
|
|
|
if (!nlmsvc_ops)
|
|
return NULL;
|
|
host = nlmsvc_lookup_host(rqstp, caller.data, caller.len);
|
|
if (!host)
|
|
return NULL;
|
|
if (monitored && nsm_monitor(host) < 0) {
|
|
nlmsvc_release_host(host);
|
|
return NULL;
|
|
}
|
|
return host;
|
|
}
|
|
|
|
static __be32
|
|
nlm4svc_lookup_file(struct svc_rqst *rqstp, struct nlm_host *host,
|
|
struct nlm_lock *lock, struct nlm_file **filp,
|
|
struct nlm4_lock *xdr_lock, unsigned char type)
|
|
{
|
|
struct file_lock *fl = &lock->fl;
|
|
struct nlm_file *file = NULL;
|
|
__be32 error;
|
|
|
|
if (xdr_lock->fh.len > NFS_MAXFHSIZE)
|
|
return nlm_lck_denied_nolocks;
|
|
lock->fh.size = xdr_lock->fh.len;
|
|
memcpy(lock->fh.data, xdr_lock->fh.data, xdr_lock->fh.len);
|
|
|
|
lock->oh.len = xdr_lock->oh.len;
|
|
lock->oh.data = xdr_lock->oh.data;
|
|
|
|
lock->svid = xdr_lock->svid;
|
|
lock->lock_start = xdr_lock->l_offset;
|
|
lock->lock_len = xdr_lock->l_len;
|
|
|
|
if (lock->lock_start > OFFSET_MAX ||
|
|
(lock->lock_len && ((lock->lock_len - 1) > (OFFSET_MAX - lock->lock_start))))
|
|
return nlm4_fbig;
|
|
|
|
locks_init_lock(fl);
|
|
fl->c.flc_type = type;
|
|
lockd_set_file_lock_range4(fl, lock->lock_start, lock->lock_len);
|
|
|
|
error = nlm_lookup_file(rqstp, &file, lock);
|
|
switch (error) {
|
|
case nlm_granted:
|
|
break;
|
|
case nlm__int__stale_fh:
|
|
return nlm4_stale_fh;
|
|
case nlm__int__failed:
|
|
return nlm4_failed;
|
|
default:
|
|
return error;
|
|
}
|
|
*filp = file;
|
|
|
|
fl->c.flc_flags = FL_POSIX;
|
|
fl->c.flc_file = file->f_file[lock_to_openmode(fl)];
|
|
fl->c.flc_pid = current->tgid;
|
|
fl->fl_lmops = &nlmsvc_lock_operations;
|
|
nlmsvc_locks_init_private(fl, host, (pid_t)lock->svid);
|
|
if (!fl->c.flc_owner)
|
|
return nlm_lck_denied_nolocks;
|
|
|
|
return nlm_granted;
|
|
}
|
|
|
|
/**
|
|
* nlm4svc_proc_null - NULL: Test for presence of service
|
|
* @rqstp: RPC transaction context
|
|
*
|
|
* Returns:
|
|
* %rpc_success: RPC executed successfully
|
|
*
|
|
* RPC synopsis:
|
|
* void NLMPROC4_NULL(void) = 0;
|
|
*/
|
|
static __be32
|
|
nlm4svc_proc_null(struct svc_rqst *rqstp)
|
|
{
|
|
return rpc_success;
|
|
}
|
|
|
|
/**
|
|
* nlm4svc_proc_test - TEST: Check for conflicting lock
|
|
* @rqstp: RPC transaction context
|
|
*
|
|
* Returns:
|
|
* %rpc_success: RPC executed successfully.
|
|
* %rpc_drop_reply: Do not send an RPC reply.
|
|
*
|
|
* RPC synopsis:
|
|
* nlm4_testres NLMPROC4_TEST(nlm4_testargs) = 1;
|
|
*
|
|
* Permissible procedure status codes:
|
|
* %NLM4_GRANTED: The server would be able to grant the
|
|
* requested lock.
|
|
* %NLM4_DENIED: The requested lock conflicted with existing
|
|
* lock reservations for the file.
|
|
* %NLM4_DENIED_NOLOCKS: The server could not allocate the resources
|
|
* needed to process the request.
|
|
* %NLM4_DENIED_GRACE_PERIOD: The server has recently restarted and is
|
|
* re-establishing existing locks, and is not
|
|
* yet ready to accept normal service requests.
|
|
*
|
|
* The Linux NLM server implementation also returns:
|
|
* %NLM4_STALE_FH: The request specified an invalid file handle.
|
|
* %NLM4_FBIG: The request specified a length or offset
|
|
* that exceeds the range supported by the
|
|
* server.
|
|
* %NLM4_FAILED: The request failed for an unspecified reason.
|
|
*/
|
|
static __be32 nlm4svc_proc_test(struct svc_rqst *rqstp)
|
|
{
|
|
struct nlm4_testargs_wrapper *argp = rqstp->rq_argp;
|
|
unsigned char type = argp->xdrgen.exclusive ? F_WRLCK : F_RDLCK;
|
|
struct nlm4_testres_wrapper *resp = rqstp->rq_resp;
|
|
struct nlm_file *file = NULL;
|
|
struct nlm_host *host;
|
|
|
|
resp->xdrgen.cookie = argp->xdrgen.cookie;
|
|
|
|
resp->xdrgen.stat.stat = nlm_lck_denied_nolocks;
|
|
host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false);
|
|
if (!host)
|
|
goto out;
|
|
|
|
resp->xdrgen.stat.stat = nlm4svc_lookup_file(rqstp, host, &argp->lock,
|
|
&file, &argp->xdrgen.alock,
|
|
type);
|
|
if (resp->xdrgen.stat.stat)
|
|
goto out;
|
|
|
|
resp->xdrgen.stat.stat = nlmsvc_testlock(rqstp, file, host,
|
|
&argp->lock, &resp->lock);
|
|
nlmsvc_release_lockowner(&argp->lock);
|
|
|
|
if (resp->xdrgen.stat.stat == nlm_lck_denied) {
|
|
struct nlm_lock *conf = &resp->lock;
|
|
struct nlm4_holder *holder = &resp->xdrgen.stat.u.holder;
|
|
|
|
holder->exclusive = (conf->fl.c.flc_type != F_RDLCK);
|
|
holder->svid = conf->svid;
|
|
holder->oh.len = conf->oh.len;
|
|
holder->oh.data = conf->oh.data;
|
|
holder->l_offset = conf->fl.fl_start;
|
|
if (conf->fl.fl_end == OFFSET_MAX)
|
|
holder->l_len = 0;
|
|
else
|
|
holder->l_len = conf->fl.fl_end - conf->fl.fl_start + 1;
|
|
}
|
|
|
|
out:
|
|
if (file)
|
|
nlm_release_file(file);
|
|
nlmsvc_release_host(host);
|
|
return resp->xdrgen.stat.stat == nlm__int__drop_reply ?
|
|
rpc_drop_reply : rpc_success;
|
|
}
|
|
|
|
static __be32
|
|
nlm4svc_do_lock(struct svc_rqst *rqstp, bool monitored)
|
|
{
|
|
struct nlm4_lockargs_wrapper *argp = rqstp->rq_argp;
|
|
unsigned char type = argp->xdrgen.exclusive ? F_WRLCK : F_RDLCK;
|
|
struct nlm4_res_wrapper *resp = rqstp->rq_resp;
|
|
struct nlm_file *file = NULL;
|
|
struct nlm_host *host = NULL;
|
|
|
|
resp->xdrgen.cookie = argp->xdrgen.cookie;
|
|
|
|
resp->xdrgen.stat.stat = nlm4_netobj_to_cookie(&argp->cookie,
|
|
&argp->xdrgen.cookie);
|
|
if (resp->xdrgen.stat.stat)
|
|
goto out;
|
|
|
|
resp->xdrgen.stat.stat = nlm_lck_denied_nolocks;
|
|
host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name,
|
|
monitored);
|
|
if (!host)
|
|
goto out;
|
|
|
|
resp->xdrgen.stat.stat = nlm4svc_lookup_file(rqstp, host, &argp->lock,
|
|
&file, &argp->xdrgen.alock,
|
|
type);
|
|
if (resp->xdrgen.stat.stat)
|
|
goto out;
|
|
|
|
resp->xdrgen.stat.stat = nlmsvc_lock(rqstp, file, host, &argp->lock,
|
|
argp->xdrgen.block, &argp->cookie,
|
|
argp->xdrgen.reclaim);
|
|
if (resp->xdrgen.stat.stat == nlm__int__deadlock)
|
|
resp->xdrgen.stat.stat = nlm4_deadlock;
|
|
|
|
nlmsvc_release_lockowner(&argp->lock);
|
|
|
|
out:
|
|
if (file)
|
|
nlm_release_file(file);
|
|
nlmsvc_release_host(host);
|
|
return resp->xdrgen.stat.stat == nlm__int__drop_reply ?
|
|
rpc_drop_reply : rpc_success;
|
|
}
|
|
|
|
/**
|
|
* nlm4svc_proc_lock - LOCK: Establish a monitored lock
|
|
* @rqstp: RPC transaction context
|
|
*
|
|
* Returns:
|
|
* %rpc_success: RPC executed successfully.
|
|
* %rpc_drop_reply: Do not send an RPC reply.
|
|
*
|
|
* RPC synopsis:
|
|
* nlm4_res NLMPROC4_LOCK(nlm4_lockargs) = 2;
|
|
*
|
|
* Permissible procedure status codes:
|
|
* %NLM4_GRANTED: The requested lock was granted.
|
|
* %NLM4_DENIED: The requested lock conflicted with existing
|
|
* lock reservations for the file.
|
|
* %NLM4_DENIED_NOLOCKS: The server could not allocate the resources
|
|
* needed to process the request.
|
|
* %NLM4_BLOCKED: The blocking request cannot be granted
|
|
* immediately. The server will send an
|
|
* NLMPROC4_GRANTED callback to the client when
|
|
* the lock can be granted.
|
|
* %NLM4_DENIED_GRACE_PERIOD: The server has recently restarted and is
|
|
* re-establishing existing locks, and is not
|
|
* yet ready to accept normal service requests.
|
|
*
|
|
* The Linux NLM server implementation also returns:
|
|
* %NLM4_DEADLCK: The request could not be granted and
|
|
* blocking would cause a deadlock.
|
|
* %NLM4_STALE_FH: The request specified an invalid file handle.
|
|
* %NLM4_FBIG: The request specified a length or offset
|
|
* that exceeds the range supported by the
|
|
* server.
|
|
* %NLM4_FAILED: The request failed for an unspecified reason.
|
|
*/
|
|
static __be32
|
|
nlm4svc_proc_lock(struct svc_rqst *rqstp)
|
|
{
|
|
return nlm4svc_do_lock(rqstp, true);
|
|
}
|
|
|
|
/**
|
|
* nlm4svc_proc_cancel - CANCEL: Cancel an outstanding blocked lock request
|
|
* @rqstp: RPC transaction context
|
|
*
|
|
* Returns:
|
|
* %rpc_success: RPC executed successfully
|
|
* %rpc_drop_reply: Do not send an RPC reply
|
|
*
|
|
* RPC synopsis:
|
|
* nlm4_res NLMPROC4_CANCEL(nlm4_cancargs) = 3;
|
|
*
|
|
* Permissible procedure status codes:
|
|
* %NLM4_LCK_GRANTED: The requested lock was canceled.
|
|
* %NLM4_LCK_DENIED: There was no lock to cancel.
|
|
* %NLM4_DENIED_GRACE_PERIOD: The server has recently restarted and is
|
|
* re-establishing existing locks, and is not
|
|
* yet ready to accept normal service requests.
|
|
*
|
|
* The Linux NLM server implementation also returns:
|
|
* %NLM4_DENIED_NOLOCKS: A needed resource could not be allocated.
|
|
* %NLM4_STALE_FH: The request specified an invalid file handle.
|
|
* %NLM4_FBIG: The request specified a length or offset
|
|
* that exceeds the range supported by the
|
|
* server.
|
|
* %NLM4_FAILED: The request failed for an unspecified reason.
|
|
*/
|
|
static __be32
|
|
nlm4svc_proc_cancel(struct svc_rqst *rqstp)
|
|
{
|
|
struct nlm4_cancargs_wrapper *argp = rqstp->rq_argp;
|
|
unsigned char type = argp->xdrgen.exclusive ? F_WRLCK : F_RDLCK;
|
|
struct nlm4_res_wrapper *resp = rqstp->rq_resp;
|
|
struct net *net = SVC_NET(rqstp);
|
|
struct nlm_host *host = NULL;
|
|
struct nlm_file *file = NULL;
|
|
|
|
resp->xdrgen.cookie = argp->xdrgen.cookie;
|
|
|
|
resp->xdrgen.stat.stat = nlm_lck_denied_grace_period;
|
|
if (locks_in_grace(net))
|
|
goto out;
|
|
|
|
resp->xdrgen.stat.stat = nlm_lck_denied_nolocks;
|
|
host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false);
|
|
if (!host)
|
|
goto out;
|
|
|
|
resp->xdrgen.stat.stat = nlm4svc_lookup_file(rqstp, host, &argp->lock,
|
|
&file, &argp->xdrgen.alock,
|
|
type);
|
|
if (resp->xdrgen.stat.stat)
|
|
goto out;
|
|
|
|
resp->xdrgen.stat.stat = nlmsvc_cancel_blocked(net, file, &argp->lock);
|
|
nlmsvc_release_lockowner(&argp->lock);
|
|
|
|
out:
|
|
if (file)
|
|
nlm_release_file(file);
|
|
nlmsvc_release_host(host);
|
|
return resp->xdrgen.stat.stat == nlm__int__drop_reply ?
|
|
rpc_drop_reply : rpc_success;
|
|
}
|
|
|
|
/**
|
|
* nlm4svc_proc_unlock - UNLOCK: Remove a lock
|
|
* @rqstp: RPC transaction context
|
|
*
|
|
* Returns:
|
|
* %rpc_success: RPC executed successfully.
|
|
* %rpc_drop_reply: Do not send an RPC reply.
|
|
*
|
|
* RPC synopsis:
|
|
* nlm4_res NLMPROC4_UNLOCK(nlm4_unlockargs) = 4;
|
|
*
|
|
* Permissible procedure status codes:
|
|
* %NLM4_GRANTED: The requested lock was released.
|
|
* %NLM4_DENIED_GRACE_PERIOD: The server has recently restarted and is
|
|
* re-establishing existing locks, and is not
|
|
* yet ready to accept normal service requests.
|
|
*
|
|
* The Linux NLM server implementation also returns:
|
|
* %NLM4_DENIED_NOLOCKS: A needed resource could not be allocated.
|
|
* %NLM4_STALE_FH: The request specified an invalid file handle.
|
|
* %NLM4_FBIG: The request specified a length or offset
|
|
* that exceeds the range supported by the
|
|
* server.
|
|
* %NLM4_FAILED: The request failed for an unspecified reason.
|
|
*/
|
|
static __be32
|
|
nlm4svc_proc_unlock(struct svc_rqst *rqstp)
|
|
{
|
|
struct nlm4_unlockargs_wrapper *argp = rqstp->rq_argp;
|
|
struct nlm4_res_wrapper *resp = rqstp->rq_resp;
|
|
struct net *net = SVC_NET(rqstp);
|
|
struct nlm_host *host = NULL;
|
|
struct nlm_file *file = NULL;
|
|
|
|
resp->xdrgen.cookie = argp->xdrgen.cookie;
|
|
|
|
resp->xdrgen.stat.stat = nlm_lck_denied_grace_period;
|
|
if (locks_in_grace(net))
|
|
goto out;
|
|
|
|
resp->xdrgen.stat.stat = nlm_lck_denied_nolocks;
|
|
host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false);
|
|
if (!host)
|
|
goto out;
|
|
|
|
resp->xdrgen.stat.stat = nlm4svc_lookup_file(rqstp, host, &argp->lock,
|
|
&file, &argp->xdrgen.alock,
|
|
F_UNLCK);
|
|
if (resp->xdrgen.stat.stat)
|
|
goto out;
|
|
|
|
resp->xdrgen.stat.stat = nlmsvc_unlock(net, file, &argp->lock);
|
|
nlmsvc_release_lockowner(&argp->lock);
|
|
|
|
out:
|
|
if (file)
|
|
nlm_release_file(file);
|
|
nlmsvc_release_host(host);
|
|
return resp->xdrgen.stat.stat == nlm__int__drop_reply ?
|
|
rpc_drop_reply : rpc_success;
|
|
}
|
|
|
|
/**
|
|
* nlm4svc_proc_granted - GRANTED: Server grants a previously blocked lock
|
|
* @rqstp: RPC transaction context
|
|
*
|
|
* Returns:
|
|
* %rpc_success: RPC executed successfully.
|
|
*
|
|
* RPC synopsis:
|
|
* nlm4_res NLMPROC4_GRANTED(nlm4_testargs) = 5;
|
|
*
|
|
* Permissible procedure status codes:
|
|
* %NLM4_GRANTED: The requested lock was granted.
|
|
* %NLM4_DENIED: The server could not allocate the resources
|
|
* needed to process the request.
|
|
* %NLM4_DENIED_GRACE_PERIOD: The server has recently restarted and is
|
|
* re-establishing existing locks, and is not
|
|
* yet ready to accept normal service requests.
|
|
*/
|
|
static __be32
|
|
nlm4svc_proc_granted(struct svc_rqst *rqstp)
|
|
{
|
|
struct nlm4_testargs_wrapper *argp = rqstp->rq_argp;
|
|
struct nlm4_res_wrapper *resp = rqstp->rq_resp;
|
|
|
|
resp->xdrgen.cookie = argp->xdrgen.cookie;
|
|
|
|
resp->xdrgen.stat.stat = nlm4_lock_to_nlm_lock(&argp->lock,
|
|
&argp->xdrgen.alock);
|
|
if (resp->xdrgen.stat.stat)
|
|
goto out;
|
|
|
|
resp->xdrgen.stat.stat = nlmclnt_grant(svc_addr(rqstp), &argp->lock);
|
|
|
|
out:
|
|
return rpc_success;
|
|
}
|
|
|
|
/*
|
|
* This is the generic lockd callback for async RPC calls
|
|
*/
|
|
static void nlm4svc_callback_exit(struct rpc_task *task, void *data)
|
|
{
|
|
}
|
|
|
|
static void nlm4svc_callback_release(void *data)
|
|
{
|
|
nlmsvc_release_call(data);
|
|
}
|
|
|
|
static const struct rpc_call_ops nlm4svc_callback_ops = {
|
|
.rpc_call_done = nlm4svc_callback_exit,
|
|
.rpc_release = nlm4svc_callback_release,
|
|
};
|
|
|
|
/*
|
|
* Dispatch an async callback RPC to a client with a pre-resolved host.
|
|
* Caller provides a reference to @host; this function takes ownership
|
|
* and releases it via nlmsvc_release_host() before returning.
|
|
*/
|
|
static __be32
|
|
nlm4svc_callback(struct svc_rqst *rqstp, struct nlm_host *host, u32 proc,
|
|
__be32 (*func)(struct svc_rqst *, struct nlm_res *))
|
|
{
|
|
struct nlm_rqst *call;
|
|
__be32 stat;
|
|
|
|
call = nlm_alloc_call(host);
|
|
nlmsvc_release_host(host);
|
|
if (call == NULL)
|
|
return rpc_system_err;
|
|
|
|
stat = func(rqstp, &call->a_res);
|
|
if (stat != 0) {
|
|
nlmsvc_release_call(call);
|
|
return stat;
|
|
}
|
|
|
|
call->a_flags = RPC_TASK_ASYNC;
|
|
if (nlm_async_reply(call, proc, &nlm4svc_callback_ops) < 0)
|
|
return rpc_system_err;
|
|
return rpc_success;
|
|
}
|
|
|
|
static __be32
|
|
__nlm4svc_proc_test_msg(struct svc_rqst *rqstp, struct nlm_res *resp)
|
|
{
|
|
struct nlm4_testargs_wrapper *argp = rqstp->rq_argp;
|
|
unsigned char type = argp->xdrgen.exclusive ? F_WRLCK : F_RDLCK;
|
|
struct nlm_lockowner *owner;
|
|
struct nlm_file *file = NULL;
|
|
struct nlm_host *host = NULL;
|
|
|
|
resp->status = nlm_lck_denied_nolocks;
|
|
if (nlm4_netobj_to_cookie(&resp->cookie, &argp->xdrgen.cookie))
|
|
goto out;
|
|
|
|
host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false);
|
|
if (!host)
|
|
goto out;
|
|
|
|
resp->status = nlm4svc_lookup_file(rqstp, host, &argp->lock,
|
|
&file, &argp->xdrgen.alock, type);
|
|
if (resp->status)
|
|
goto out;
|
|
|
|
owner = argp->lock.fl.c.flc_owner;
|
|
resp->status = nlmsvc_testlock(rqstp, file, host, &argp->lock,
|
|
&resp->lock);
|
|
nlmsvc_put_lockowner(owner);
|
|
|
|
out:
|
|
if (file)
|
|
nlm_release_file(file);
|
|
nlmsvc_release_host(host);
|
|
return resp->status == nlm__int__drop_reply ? rpc_drop_reply : rpc_success;
|
|
}
|
|
|
|
/**
|
|
* nlm4svc_proc_test_msg - TEST_MSG: Check for conflicting lock
|
|
* @rqstp: RPC transaction context
|
|
*
|
|
* Returns:
|
|
* %rpc_success: RPC executed successfully.
|
|
* %rpc_system_err: RPC execution failed.
|
|
*
|
|
* RPC synopsis:
|
|
* void NLMPROC4_TEST_MSG(nlm4_testargs) = 6;
|
|
*
|
|
* The response to this request is delivered via the TEST_RES procedure.
|
|
*/
|
|
static __be32 nlm4svc_proc_test_msg(struct svc_rqst *rqstp)
|
|
{
|
|
struct nlm4_testargs_wrapper *argp = rqstp->rq_argp;
|
|
struct nlm_host *host;
|
|
|
|
host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false);
|
|
if (!host)
|
|
return rpc_system_err;
|
|
|
|
return nlm4svc_callback(rqstp, host, NLMPROC4_TEST_RES,
|
|
__nlm4svc_proc_test_msg);
|
|
}
|
|
|
|
static __be32
|
|
__nlm4svc_proc_lock_msg(struct svc_rqst *rqstp, struct nlm_res *resp)
|
|
{
|
|
struct nlm4_lockargs_wrapper *argp = rqstp->rq_argp;
|
|
unsigned char type = argp->xdrgen.exclusive ? F_WRLCK : F_RDLCK;
|
|
struct nlm_file *file = NULL;
|
|
struct nlm_host *host = NULL;
|
|
|
|
resp->status = nlm_lck_denied_nolocks;
|
|
if (nlm4_netobj_to_cookie(&resp->cookie, &argp->xdrgen.cookie))
|
|
goto out;
|
|
|
|
host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, true);
|
|
if (!host)
|
|
goto out;
|
|
|
|
resp->status = nlm4svc_lookup_file(rqstp, host, &argp->lock,
|
|
&file, &argp->xdrgen.alock, type);
|
|
if (resp->status)
|
|
goto out;
|
|
|
|
resp->status = nlmsvc_lock(rqstp, file, host, &argp->lock,
|
|
argp->xdrgen.block, &resp->cookie,
|
|
argp->xdrgen.reclaim);
|
|
nlmsvc_release_lockowner(&argp->lock);
|
|
|
|
out:
|
|
if (file)
|
|
nlm_release_file(file);
|
|
nlmsvc_release_host(host);
|
|
return resp->status == nlm__int__drop_reply ?
|
|
rpc_drop_reply : rpc_success;
|
|
}
|
|
|
|
/**
|
|
* nlm4svc_proc_lock_msg - LOCK_MSG: Establish a monitored lock
|
|
* @rqstp: RPC transaction context
|
|
*
|
|
* Returns:
|
|
* %rpc_success: RPC executed successfully.
|
|
* %rpc_system_err: RPC execution failed.
|
|
*
|
|
* RPC synopsis:
|
|
* void NLMPROC4_LOCK_MSG(nlm4_lockargs) = 7;
|
|
*
|
|
* The response to this request is delivered via the LOCK_RES procedure.
|
|
*/
|
|
static __be32 nlm4svc_proc_lock_msg(struct svc_rqst *rqstp)
|
|
{
|
|
struct nlm4_lockargs_wrapper *argp = rqstp->rq_argp;
|
|
struct nlm_host *host;
|
|
|
|
host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, true);
|
|
if (!host)
|
|
return rpc_system_err;
|
|
|
|
return nlm4svc_callback(rqstp, host, NLMPROC4_LOCK_RES,
|
|
__nlm4svc_proc_lock_msg);
|
|
}
|
|
|
|
static __be32
|
|
__nlm4svc_proc_cancel_msg(struct svc_rqst *rqstp, struct nlm_res *resp)
|
|
{
|
|
struct nlm4_cancargs_wrapper *argp = rqstp->rq_argp;
|
|
unsigned char type = argp->xdrgen.exclusive ? F_WRLCK : F_RDLCK;
|
|
struct net *net = SVC_NET(rqstp);
|
|
struct nlm_file *file = NULL;
|
|
struct nlm_host *host = NULL;
|
|
|
|
resp->status = nlm_lck_denied_nolocks;
|
|
if (nlm4_netobj_to_cookie(&resp->cookie, &argp->xdrgen.cookie))
|
|
goto out;
|
|
|
|
resp->status = nlm_lck_denied_grace_period;
|
|
if (locks_in_grace(net))
|
|
goto out;
|
|
|
|
resp->status = nlm_lck_denied_nolocks;
|
|
host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false);
|
|
if (!host)
|
|
goto out;
|
|
|
|
resp->status = nlm4svc_lookup_file(rqstp, host, &argp->lock,
|
|
&file, &argp->xdrgen.alock, type);
|
|
if (resp->status)
|
|
goto out;
|
|
|
|
resp->status = nlmsvc_cancel_blocked(net, file, &argp->lock);
|
|
nlmsvc_release_lockowner(&argp->lock);
|
|
|
|
out:
|
|
if (file)
|
|
nlm_release_file(file);
|
|
nlmsvc_release_host(host);
|
|
return resp->status == nlm__int__drop_reply ?
|
|
rpc_drop_reply : rpc_success;
|
|
}
|
|
|
|
/**
|
|
* nlm4svc_proc_cancel_msg - CANCEL_MSG: Cancel an outstanding lock request
|
|
* @rqstp: RPC transaction context
|
|
*
|
|
* Returns:
|
|
* %rpc_success: RPC executed successfully.
|
|
* %rpc_system_err: RPC execution failed.
|
|
*
|
|
* RPC synopsis:
|
|
* void NLMPROC4_CANCEL_MSG(nlm4_cancargs) = 8;
|
|
*
|
|
* The response to this request is delivered via the CANCEL_RES procedure.
|
|
*/
|
|
static __be32 nlm4svc_proc_cancel_msg(struct svc_rqst *rqstp)
|
|
{
|
|
struct nlm4_cancargs_wrapper *argp = rqstp->rq_argp;
|
|
struct nlm_host *host;
|
|
|
|
host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false);
|
|
if (!host)
|
|
return rpc_system_err;
|
|
|
|
return nlm4svc_callback(rqstp, host, NLMPROC4_CANCEL_RES,
|
|
__nlm4svc_proc_cancel_msg);
|
|
}
|
|
|
|
static __be32
|
|
__nlm4svc_proc_unlock_msg(struct svc_rqst *rqstp, struct nlm_res *resp)
|
|
{
|
|
struct nlm4_unlockargs_wrapper *argp = rqstp->rq_argp;
|
|
struct net *net = SVC_NET(rqstp);
|
|
struct nlm_file *file = NULL;
|
|
struct nlm_host *host = NULL;
|
|
|
|
resp->status = nlm_lck_denied_nolocks;
|
|
if (nlm4_netobj_to_cookie(&resp->cookie, &argp->xdrgen.cookie))
|
|
goto out;
|
|
|
|
resp->status = nlm_lck_denied_grace_period;
|
|
if (locks_in_grace(net))
|
|
goto out;
|
|
|
|
resp->status = nlm_lck_denied_nolocks;
|
|
host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false);
|
|
if (!host)
|
|
goto out;
|
|
|
|
resp->status = nlm4svc_lookup_file(rqstp, host, &argp->lock,
|
|
&file, &argp->xdrgen.alock, F_UNLCK);
|
|
if (resp->status)
|
|
goto out;
|
|
|
|
resp->status = nlmsvc_unlock(net, file, &argp->lock);
|
|
nlmsvc_release_lockowner(&argp->lock);
|
|
|
|
out:
|
|
if (file)
|
|
nlm_release_file(file);
|
|
nlmsvc_release_host(host);
|
|
return resp->status == nlm__int__drop_reply ?
|
|
rpc_drop_reply : rpc_success;
|
|
}
|
|
|
|
/**
|
|
* nlm4svc_proc_unlock_msg - UNLOCK_MSG: Remove an existing lock
|
|
* @rqstp: RPC transaction context
|
|
*
|
|
* Returns:
|
|
* %rpc_success: RPC executed successfully.
|
|
* %rpc_system_err: RPC execution failed.
|
|
*
|
|
* RPC synopsis:
|
|
* void NLMPROC4_UNLOCK_MSG(nlm4_unlockargs) = 9;
|
|
*
|
|
* The response to this request is delivered via the UNLOCK_RES procedure.
|
|
*/
|
|
static __be32 nlm4svc_proc_unlock_msg(struct svc_rqst *rqstp)
|
|
{
|
|
struct nlm4_unlockargs_wrapper *argp = rqstp->rq_argp;
|
|
struct nlm_host *host;
|
|
|
|
host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false);
|
|
if (!host)
|
|
return rpc_system_err;
|
|
|
|
return nlm4svc_callback(rqstp, host, NLMPROC4_UNLOCK_RES,
|
|
__nlm4svc_proc_unlock_msg);
|
|
}
|
|
|
|
static __be32
|
|
__nlm4svc_proc_granted_msg(struct svc_rqst *rqstp, struct nlm_res *resp)
|
|
{
|
|
struct nlm4_testargs_wrapper *argp = rqstp->rq_argp;
|
|
|
|
resp->status = nlm_lck_denied;
|
|
if (nlm4_netobj_to_cookie(&resp->cookie, &argp->xdrgen.cookie))
|
|
goto out;
|
|
|
|
if (nlm4_lock_to_nlm_lock(&argp->lock, &argp->xdrgen.alock))
|
|
goto out;
|
|
|
|
resp->status = nlmclnt_grant(svc_addr(rqstp), &argp->lock);
|
|
|
|
out:
|
|
return rpc_success;
|
|
}
|
|
|
|
/**
|
|
* nlm4svc_proc_granted_msg - GRANTED_MSG: Blocked lock has been granted
|
|
* @rqstp: RPC transaction context
|
|
*
|
|
* Returns:
|
|
* %rpc_success: RPC executed successfully.
|
|
* %rpc_system_err: RPC execution failed.
|
|
*
|
|
* RPC synopsis:
|
|
* void NLMPROC4_GRANTED_MSG(nlm4_testargs) = 10;
|
|
*
|
|
* The response to this request is delivered via the GRANTED_RES procedure.
|
|
*/
|
|
static __be32 nlm4svc_proc_granted_msg(struct svc_rqst *rqstp)
|
|
{
|
|
struct nlm4_testargs_wrapper *argp = rqstp->rq_argp;
|
|
struct nlm_host *host;
|
|
|
|
host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false);
|
|
if (!host)
|
|
return rpc_system_err;
|
|
|
|
return nlm4svc_callback(rqstp, host, NLMPROC4_GRANTED_RES,
|
|
__nlm4svc_proc_granted_msg);
|
|
}
|
|
|
|
/**
|
|
* nlm4svc_proc_granted_res - GRANTED_RES: Lock Granted result
|
|
* @rqstp: RPC transaction context
|
|
*
|
|
* Returns:
|
|
* %rpc_success: RPC executed successfully.
|
|
*
|
|
* RPC synopsis:
|
|
* void NLMPROC4_GRANTED_RES(nlm4_res) = 15;
|
|
*/
|
|
static __be32 nlm4svc_proc_granted_res(struct svc_rqst *rqstp)
|
|
{
|
|
struct nlm4_res_wrapper *argp = rqstp->rq_argp;
|
|
|
|
if (!nlmsvc_ops)
|
|
return rpc_success;
|
|
|
|
if (nlm4_netobj_to_cookie(&argp->cookie, &argp->xdrgen.cookie))
|
|
return rpc_success;
|
|
nlmsvc_grant_reply(&argp->cookie, argp->xdrgen.stat.stat);
|
|
|
|
return rpc_success;
|
|
}
|
|
|
|
/**
|
|
* nlm4svc_proc_sm_notify - SM_NOTIFY: Peer has rebooted
|
|
* @rqstp: RPC transaction context
|
|
*
|
|
* Returns:
|
|
* %rpc_success: RPC executed successfully.
|
|
* %rpc_system_err: RPC execution failed.
|
|
*
|
|
* The SM_NOTIFY procedure is a private callback from Linux statd and is
|
|
* not part of the official NLM protocol.
|
|
*
|
|
* RPC synopsis:
|
|
* void NLMPROC4_SM_NOTIFY(nlm4_notifyargs) = 16;
|
|
*/
|
|
static __be32 nlm4svc_proc_sm_notify(struct svc_rqst *rqstp)
|
|
{
|
|
struct nlm4_notifyargs_wrapper *argp = rqstp->rq_argp;
|
|
struct nlm_reboot *reboot = &argp->reboot;
|
|
|
|
if (!nlm_privileged_requester(rqstp)) {
|
|
char buf[RPC_MAX_ADDRBUFLEN];
|
|
|
|
pr_warn("lockd: rejected NSM callback from %s\n",
|
|
svc_print_addr(rqstp, buf, sizeof(buf)));
|
|
return rpc_system_err;
|
|
}
|
|
|
|
reboot->len = argp->xdrgen.notify.name.len;
|
|
reboot->mon = (char *)argp->xdrgen.notify.name.data;
|
|
reboot->state = argp->xdrgen.notify.state;
|
|
memcpy(&reboot->priv.data, argp->xdrgen.private,
|
|
sizeof(reboot->priv.data));
|
|
|
|
nlm_host_rebooted(SVC_NET(rqstp), reboot);
|
|
|
|
return rpc_success;
|
|
}
|
|
|
|
/**
|
|
* nlm4svc_proc_unused - stub for unused procedures
|
|
* @rqstp: RPC transaction context
|
|
*
|
|
* Returns:
|
|
* %rpc_proc_unavail: Program can't support procedure.
|
|
*/
|
|
static __be32 nlm4svc_proc_unused(struct svc_rqst *rqstp)
|
|
{
|
|
return rpc_proc_unavail;
|
|
}
|
|
|
|
/**
|
|
* nlm4svc_proc_share - SHARE: Open a file using DOS file-sharing modes
|
|
* @rqstp: RPC transaction context
|
|
*
|
|
* Returns:
|
|
* %rpc_success: RPC executed successfully.
|
|
* %rpc_drop_reply: Do not send an RPC reply.
|
|
*
|
|
* RPC synopsis:
|
|
* nlm4_shareres NLMPROC4_SHARE(nlm4_shareargs) = 20;
|
|
*
|
|
* Permissible procedure status codes:
|
|
* %NLM4_GRANTED: The requested share lock was granted.
|
|
* %NLM4_DENIED: The requested lock conflicted with existing
|
|
* lock reservations for the file.
|
|
* %NLM4_DENIED_GRACE_PERIOD: The server has recently restarted and is
|
|
* re-establishing existing locks, and is not
|
|
* yet ready to accept normal service requests.
|
|
*
|
|
* The Linux NLM server implementation also returns:
|
|
* %NLM4_DENIED_NOLOCKS: A needed resource could not be allocated.
|
|
* %NLM4_STALE_FH: The request specified an invalid file handle.
|
|
* %NLM4_FBIG: The request specified a length or offset
|
|
* that exceeds the range supported by the
|
|
* server.
|
|
* %NLM4_FAILED: The request failed for an unspecified reason.
|
|
*/
|
|
static __be32 nlm4svc_proc_share(struct svc_rqst *rqstp)
|
|
{
|
|
struct nlm4_shareargs_wrapper *argp = rqstp->rq_argp;
|
|
struct nlm4_shareres_wrapper *resp = rqstp->rq_resp;
|
|
struct nlm_lock *lock = &argp->lock;
|
|
struct nlm_host *host = NULL;
|
|
struct nlm_file *file = NULL;
|
|
struct nlm4_lock xdr_lock = {
|
|
.fh = argp->xdrgen.share.fh,
|
|
.oh = argp->xdrgen.share.oh,
|
|
.svid = LOCKD_SHARE_SVID,
|
|
};
|
|
|
|
resp->xdrgen.cookie = argp->xdrgen.cookie;
|
|
|
|
resp->xdrgen.stat = nlm_lck_denied_grace_period;
|
|
if (locks_in_grace(SVC_NET(rqstp)) && !argp->xdrgen.reclaim)
|
|
goto out;
|
|
|
|
resp->xdrgen.stat = nlm_lck_denied_nolocks;
|
|
host = nlm4svc_lookup_host(rqstp, argp->xdrgen.share.caller_name, true);
|
|
if (!host)
|
|
goto out;
|
|
|
|
resp->xdrgen.stat = nlm4svc_lookup_file(rqstp, host, lock, &file,
|
|
&xdr_lock, F_RDLCK);
|
|
if (resp->xdrgen.stat)
|
|
goto out;
|
|
|
|
resp->xdrgen.stat = nlmsvc_share_file(host, file, &lock->oh,
|
|
argp->xdrgen.share.access,
|
|
argp->xdrgen.share.mode);
|
|
|
|
nlmsvc_release_lockowner(lock);
|
|
|
|
out:
|
|
if (file)
|
|
nlm_release_file(file);
|
|
nlmsvc_release_host(host);
|
|
return resp->xdrgen.stat == nlm__int__drop_reply ?
|
|
rpc_drop_reply : rpc_success;
|
|
}
|
|
|
|
/**
|
|
* nlm4svc_proc_unshare - UNSHARE: Release a share reservation
|
|
* @rqstp: RPC transaction context
|
|
*
|
|
* Returns:
|
|
* %rpc_success: RPC executed successfully.
|
|
* %rpc_drop_reply: Do not send an RPC reply.
|
|
*
|
|
* RPC synopsis:
|
|
* nlm4_shareres NLMPROC4_UNSHARE(nlm4_shareargs) = 21;
|
|
*
|
|
* Permissible procedure status codes:
|
|
* %NLM4_GRANTED: The share reservation was released.
|
|
* %NLM4_DENIED_GRACE_PERIOD: The server has recently restarted and is
|
|
* re-establishing existing locks, and is not
|
|
* yet ready to accept normal service requests.
|
|
*
|
|
* The Linux NLM server implementation also returns:
|
|
* %NLM4_DENIED_NOLOCKS: A needed resource could not be allocated.
|
|
* %NLM4_STALE_FH: The request specified an invalid file handle.
|
|
* %NLM4_FBIG: The request specified a length or offset
|
|
* that exceeds the range supported by the
|
|
* server.
|
|
* %NLM4_FAILED: The request failed for an unspecified reason.
|
|
*/
|
|
static __be32 nlm4svc_proc_unshare(struct svc_rqst *rqstp)
|
|
{
|
|
struct nlm4_shareargs_wrapper *argp = rqstp->rq_argp;
|
|
struct nlm4_shareres_wrapper *resp = rqstp->rq_resp;
|
|
struct nlm_lock *lock = &argp->lock;
|
|
struct nlm4_lock xdr_lock = {
|
|
.fh = argp->xdrgen.share.fh,
|
|
.oh = argp->xdrgen.share.oh,
|
|
.svid = LOCKD_SHARE_SVID,
|
|
};
|
|
struct nlm_host *host = NULL;
|
|
struct nlm_file *file = NULL;
|
|
|
|
resp->xdrgen.cookie = argp->xdrgen.cookie;
|
|
|
|
resp->xdrgen.stat = nlm_lck_denied_grace_period;
|
|
if (locks_in_grace(SVC_NET(rqstp)))
|
|
goto out;
|
|
|
|
resp->xdrgen.stat = nlm_lck_denied_nolocks;
|
|
host = nlm4svc_lookup_host(rqstp, argp->xdrgen.share.caller_name, true);
|
|
if (!host)
|
|
goto out;
|
|
|
|
resp->xdrgen.stat = nlm4svc_lookup_file(rqstp, host, lock, &file,
|
|
&xdr_lock, F_RDLCK);
|
|
if (resp->xdrgen.stat)
|
|
goto out;
|
|
|
|
resp->xdrgen.stat = nlmsvc_unshare_file(host, file, &lock->oh);
|
|
|
|
nlmsvc_release_lockowner(lock);
|
|
|
|
out:
|
|
if (file)
|
|
nlm_release_file(file);
|
|
nlmsvc_release_host(host);
|
|
return resp->xdrgen.stat == nlm__int__drop_reply ?
|
|
rpc_drop_reply : rpc_success;
|
|
}
|
|
|
|
/**
|
|
* nlm4svc_proc_nm_lock - NM_LOCK: Establish a non-monitored lock
|
|
* @rqstp: RPC transaction context
|
|
*
|
|
* Returns:
|
|
* %rpc_success: RPC executed successfully.
|
|
* %rpc_drop_reply: Do not send an RPC reply.
|
|
*
|
|
* RPC synopsis:
|
|
* nlm4_res NLMPROC4_NM_LOCK(nlm4_lockargs) = 22;
|
|
*
|
|
* Permissible procedure status codes:
|
|
* %NLM4_GRANTED: The requested lock was granted.
|
|
* %NLM4_DENIED: The requested lock conflicted with existing
|
|
* lock reservations for the file.
|
|
* %NLM4_DENIED_NOLOCKS: The server could not allocate the resources
|
|
* needed to process the request.
|
|
* %NLM4_BLOCKED: The blocking request cannot be granted
|
|
* immediately. The server will send an
|
|
* NLMPROC4_GRANTED callback to the client when
|
|
* the lock can be granted.
|
|
* %NLM4_DENIED_GRACE_PERIOD: The server has recently restarted and is
|
|
* re-establishing existing locks, and is not
|
|
* yet ready to accept normal service requests.
|
|
*
|
|
* The Linux NLM server implementation also returns:
|
|
* %NLM4_DEADLCK: The request could not be granted and
|
|
* blocking would cause a deadlock.
|
|
* %NLM4_STALE_FH: The request specified an invalid file handle.
|
|
* %NLM4_FBIG: The request specified a length or offset
|
|
* that exceeds the range supported by the
|
|
* server.
|
|
* %NLM4_FAILED: The request failed for an unspecified reason.
|
|
*/
|
|
static __be32 nlm4svc_proc_nm_lock(struct svc_rqst *rqstp)
|
|
{
|
|
return nlm4svc_do_lock(rqstp, false);
|
|
}
|
|
|
|
/**
|
|
* nlm4svc_proc_free_all - FREE_ALL: Discard client's lock and share state
|
|
* @rqstp: RPC transaction context
|
|
*
|
|
* Returns:
|
|
* %rpc_success: RPC executed successfully.
|
|
*
|
|
* RPC synopsis:
|
|
* void NLMPROC4_FREE_ALL(nlm4_notify) = 23;
|
|
*/
|
|
static __be32 nlm4svc_proc_free_all(struct svc_rqst *rqstp)
|
|
{
|
|
struct nlm4_notify_wrapper *argp = rqstp->rq_argp;
|
|
struct nlm_host *host;
|
|
|
|
host = nlm4svc_lookup_host(rqstp, argp->xdrgen.name, false);
|
|
if (!host)
|
|
goto out;
|
|
|
|
nlmsvc_free_host_resources(host);
|
|
|
|
nlmsvc_release_host(host);
|
|
|
|
out:
|
|
return rpc_success;
|
|
}
|
|
|
|
|
|
/*
|
|
* NLMv4 Server procedures.
|
|
*/
|
|
|
|
static const struct svc_procedure nlm4svc_procedures[24] = {
|
|
[NLMPROC4_NULL] = {
|
|
.pc_func = nlm4svc_proc_null,
|
|
.pc_decode = nlm4_svc_decode_void,
|
|
.pc_encode = nlm4_svc_encode_void,
|
|
.pc_argsize = XDR_void,
|
|
.pc_argzero = 0,
|
|
.pc_ressize = 0,
|
|
.pc_xdrressize = XDR_void,
|
|
.pc_name = "NULL",
|
|
},
|
|
[NLMPROC4_TEST] = {
|
|
.pc_func = nlm4svc_proc_test,
|
|
.pc_decode = nlm4_svc_decode_nlm4_testargs,
|
|
.pc_encode = nlm4_svc_encode_nlm4_testres,
|
|
.pc_argsize = sizeof(struct nlm4_testargs_wrapper),
|
|
.pc_argzero = 0,
|
|
.pc_ressize = sizeof(struct nlm4_testres_wrapper),
|
|
.pc_xdrressize = NLM4_nlm4_testres_sz,
|
|
.pc_name = "TEST",
|
|
},
|
|
[NLMPROC4_LOCK] = {
|
|
.pc_func = nlm4svc_proc_lock,
|
|
.pc_decode = nlm4_svc_decode_nlm4_lockargs,
|
|
.pc_encode = nlm4_svc_encode_nlm4_res,
|
|
.pc_argsize = sizeof(struct nlm4_lockargs_wrapper),
|
|
.pc_argzero = 0,
|
|
.pc_ressize = sizeof(struct nlm4_res_wrapper),
|
|
.pc_xdrressize = NLM4_nlm4_res_sz,
|
|
.pc_name = "LOCK",
|
|
},
|
|
[NLMPROC4_CANCEL] = {
|
|
.pc_func = nlm4svc_proc_cancel,
|
|
.pc_decode = nlm4_svc_decode_nlm4_cancargs,
|
|
.pc_encode = nlm4_svc_encode_nlm4_res,
|
|
.pc_argsize = sizeof(struct nlm4_cancargs_wrapper),
|
|
.pc_argzero = 0,
|
|
.pc_ressize = sizeof(struct nlm4_res_wrapper),
|
|
.pc_xdrressize = NLM4_nlm4_res_sz,
|
|
.pc_name = "CANCEL",
|
|
},
|
|
[NLMPROC4_UNLOCK] = {
|
|
.pc_func = nlm4svc_proc_unlock,
|
|
.pc_decode = nlm4_svc_decode_nlm4_unlockargs,
|
|
.pc_encode = nlm4_svc_encode_nlm4_res,
|
|
.pc_argsize = sizeof(struct nlm4_unlockargs_wrapper),
|
|
.pc_argzero = 0,
|
|
.pc_ressize = sizeof(struct nlm4_res_wrapper),
|
|
.pc_xdrressize = NLM4_nlm4_res_sz,
|
|
.pc_name = "UNLOCK",
|
|
},
|
|
[NLMPROC4_GRANTED] = {
|
|
.pc_func = nlm4svc_proc_granted,
|
|
.pc_decode = nlm4_svc_decode_nlm4_testargs,
|
|
.pc_encode = nlm4_svc_encode_nlm4_res,
|
|
.pc_argsize = sizeof(struct nlm4_testargs_wrapper),
|
|
.pc_argzero = 0,
|
|
.pc_ressize = sizeof(struct nlm4_res_wrapper),
|
|
.pc_xdrressize = NLM4_nlm4_res_sz,
|
|
.pc_name = "GRANTED",
|
|
},
|
|
[NLMPROC4_TEST_MSG] = {
|
|
.pc_func = nlm4svc_proc_test_msg,
|
|
.pc_decode = nlm4_svc_decode_nlm4_testargs,
|
|
.pc_encode = nlm4_svc_encode_void,
|
|
.pc_argsize = sizeof(struct nlm4_testargs_wrapper),
|
|
.pc_argzero = 0,
|
|
.pc_ressize = 0,
|
|
.pc_xdrressize = XDR_void,
|
|
.pc_name = "TEST_MSG",
|
|
},
|
|
[NLMPROC4_LOCK_MSG] = {
|
|
.pc_func = nlm4svc_proc_lock_msg,
|
|
.pc_decode = nlm4_svc_decode_nlm4_lockargs,
|
|
.pc_encode = nlm4_svc_encode_void,
|
|
.pc_argsize = sizeof(struct nlm4_lockargs_wrapper),
|
|
.pc_argzero = 0,
|
|
.pc_ressize = 0,
|
|
.pc_xdrressize = XDR_void,
|
|
.pc_name = "LOCK_MSG",
|
|
},
|
|
[NLMPROC4_CANCEL_MSG] = {
|
|
.pc_func = nlm4svc_proc_cancel_msg,
|
|
.pc_decode = nlm4_svc_decode_nlm4_cancargs,
|
|
.pc_encode = nlm4_svc_encode_void,
|
|
.pc_argsize = sizeof(struct nlm4_cancargs_wrapper),
|
|
.pc_argzero = 0,
|
|
.pc_ressize = 0,
|
|
.pc_xdrressize = XDR_void,
|
|
.pc_name = "CANCEL_MSG",
|
|
},
|
|
[NLMPROC4_UNLOCK_MSG] = {
|
|
.pc_func = nlm4svc_proc_unlock_msg,
|
|
.pc_decode = nlm4_svc_decode_nlm4_unlockargs,
|
|
.pc_encode = nlm4_svc_encode_void,
|
|
.pc_argsize = sizeof(struct nlm4_unlockargs_wrapper),
|
|
.pc_argzero = 0,
|
|
.pc_ressize = 0,
|
|
.pc_xdrressize = XDR_void,
|
|
.pc_name = "UNLOCK_MSG",
|
|
},
|
|
[NLMPROC4_GRANTED_MSG] = {
|
|
.pc_func = nlm4svc_proc_granted_msg,
|
|
.pc_decode = nlm4_svc_decode_nlm4_testargs,
|
|
.pc_encode = nlm4_svc_encode_void,
|
|
.pc_argsize = sizeof(struct nlm4_testargs_wrapper),
|
|
.pc_argzero = 0,
|
|
.pc_ressize = 0,
|
|
.pc_xdrressize = XDR_void,
|
|
.pc_name = "GRANTED_MSG",
|
|
},
|
|
[NLMPROC4_TEST_RES] = {
|
|
.pc_func = nlm4svc_proc_null,
|
|
.pc_decode = nlm4_svc_decode_nlm4_testres,
|
|
.pc_encode = nlm4_svc_encode_void,
|
|
.pc_argsize = sizeof(struct nlm4_testres),
|
|
.pc_argzero = 0,
|
|
.pc_ressize = 0,
|
|
.pc_xdrressize = XDR_void,
|
|
.pc_name = "TEST_RES",
|
|
},
|
|
[NLMPROC4_LOCK_RES] = {
|
|
.pc_func = nlm4svc_proc_null,
|
|
.pc_decode = nlm4_svc_decode_nlm4_res,
|
|
.pc_encode = nlm4_svc_encode_void,
|
|
.pc_argsize = sizeof(struct nlm4_res),
|
|
.pc_argzero = 0,
|
|
.pc_ressize = 0,
|
|
.pc_xdrressize = XDR_void,
|
|
.pc_name = "LOCK_RES",
|
|
},
|
|
[NLMPROC4_CANCEL_RES] = {
|
|
.pc_func = nlm4svc_proc_null,
|
|
.pc_decode = nlm4_svc_decode_nlm4_res,
|
|
.pc_encode = nlm4_svc_encode_void,
|
|
.pc_argsize = sizeof(struct nlm4_res),
|
|
.pc_argzero = 0,
|
|
.pc_ressize = 0,
|
|
.pc_xdrressize = XDR_void,
|
|
.pc_name = "CANCEL_RES",
|
|
},
|
|
[NLMPROC4_UNLOCK_RES] = {
|
|
.pc_func = nlm4svc_proc_null,
|
|
.pc_decode = nlm4_svc_decode_nlm4_res,
|
|
.pc_encode = nlm4_svc_encode_void,
|
|
.pc_argsize = sizeof(struct nlm4_res),
|
|
.pc_argzero = 0,
|
|
.pc_ressize = 0,
|
|
.pc_xdrressize = XDR_void,
|
|
.pc_name = "UNLOCK_RES",
|
|
},
|
|
[NLMPROC4_GRANTED_RES] = {
|
|
.pc_func = nlm4svc_proc_granted_res,
|
|
.pc_decode = nlm4_svc_decode_nlm4_res,
|
|
.pc_encode = nlm4_svc_encode_void,
|
|
.pc_argsize = sizeof(struct nlm4_res_wrapper),
|
|
.pc_argzero = 0,
|
|
.pc_ressize = 0,
|
|
.pc_xdrressize = XDR_void,
|
|
.pc_name = "GRANTED_RES",
|
|
},
|
|
[NLMPROC4_SM_NOTIFY] = {
|
|
.pc_func = nlm4svc_proc_sm_notify,
|
|
.pc_decode = nlm4_svc_decode_nlm4_notifyargs,
|
|
.pc_encode = nlm4_svc_encode_void,
|
|
.pc_argsize = sizeof(struct nlm4_notifyargs_wrapper),
|
|
.pc_argzero = 0,
|
|
.pc_ressize = 0,
|
|
.pc_xdrressize = XDR_void,
|
|
.pc_name = "SM_NOTIFY",
|
|
},
|
|
[17] = {
|
|
.pc_func = nlm4svc_proc_unused,
|
|
.pc_decode = nlm4_svc_decode_void,
|
|
.pc_encode = nlm4_svc_encode_void,
|
|
.pc_argsize = 0,
|
|
.pc_argzero = 0,
|
|
.pc_ressize = 0,
|
|
.pc_xdrressize = XDR_void,
|
|
.pc_name = "UNUSED",
|
|
},
|
|
[18] = {
|
|
.pc_func = nlm4svc_proc_unused,
|
|
.pc_decode = nlm4_svc_decode_void,
|
|
.pc_encode = nlm4_svc_encode_void,
|
|
.pc_argsize = 0,
|
|
.pc_argzero = 0,
|
|
.pc_ressize = 0,
|
|
.pc_xdrressize = XDR_void,
|
|
.pc_name = "UNUSED",
|
|
},
|
|
[19] = {
|
|
.pc_func = nlm4svc_proc_unused,
|
|
.pc_decode = nlm4_svc_decode_void,
|
|
.pc_encode = nlm4_svc_encode_void,
|
|
.pc_argsize = 0,
|
|
.pc_argzero = 0,
|
|
.pc_ressize = 0,
|
|
.pc_xdrressize = XDR_void,
|
|
.pc_name = "UNUSED",
|
|
},
|
|
[NLMPROC4_SHARE] = {
|
|
.pc_func = nlm4svc_proc_share,
|
|
.pc_decode = nlm4_svc_decode_nlm4_shareargs,
|
|
.pc_encode = nlm4_svc_encode_nlm4_shareres,
|
|
.pc_argsize = sizeof(struct nlm4_shareargs_wrapper),
|
|
.pc_argzero = 0,
|
|
.pc_ressize = sizeof(struct nlm4_shareres_wrapper),
|
|
.pc_xdrressize = NLM4_nlm4_shareres_sz,
|
|
.pc_name = "SHARE",
|
|
},
|
|
[NLMPROC4_UNSHARE] = {
|
|
.pc_func = nlm4svc_proc_unshare,
|
|
.pc_decode = nlm4_svc_decode_nlm4_shareargs,
|
|
.pc_encode = nlm4_svc_encode_nlm4_shareres,
|
|
.pc_argsize = sizeof(struct nlm4_shareargs_wrapper),
|
|
.pc_argzero = 0,
|
|
.pc_ressize = sizeof(struct nlm4_shareres_wrapper),
|
|
.pc_xdrressize = NLM4_nlm4_shareres_sz,
|
|
.pc_name = "UNSHARE",
|
|
},
|
|
[NLMPROC4_NM_LOCK] = {
|
|
.pc_func = nlm4svc_proc_nm_lock,
|
|
.pc_decode = nlm4_svc_decode_nlm4_lockargs,
|
|
.pc_encode = nlm4_svc_encode_nlm4_res,
|
|
.pc_argsize = sizeof(struct nlm4_lockargs_wrapper),
|
|
.pc_argzero = 0,
|
|
.pc_ressize = sizeof(struct nlm4_res_wrapper),
|
|
.pc_xdrressize = NLM4_nlm4_res_sz,
|
|
.pc_name = "NM_LOCK",
|
|
},
|
|
[NLMPROC4_FREE_ALL] = {
|
|
.pc_func = nlm4svc_proc_free_all,
|
|
.pc_decode = nlm4_svc_decode_nlm4_notify,
|
|
.pc_encode = nlm4_svc_encode_void,
|
|
.pc_argsize = sizeof(struct nlm4_notify_wrapper),
|
|
.pc_argzero = 0,
|
|
.pc_ressize = 0,
|
|
.pc_xdrressize = XDR_void,
|
|
.pc_name = "FREE_ALL",
|
|
},
|
|
};
|
|
|
|
/*
|
|
* Storage requirements for XDR arguments and results
|
|
*/
|
|
union nlm4svc_xdrstore {
|
|
struct nlm4_testargs_wrapper testargs;
|
|
struct nlm4_lockargs_wrapper lockargs;
|
|
struct nlm4_cancargs_wrapper cancargs;
|
|
struct nlm4_unlockargs_wrapper unlockargs;
|
|
struct nlm4_notifyargs_wrapper notifyargs;
|
|
struct nlm4_shareargs_wrapper shareargs;
|
|
struct nlm4_notify_wrapper notify;
|
|
struct nlm4_testres_wrapper testres;
|
|
struct nlm4_res_wrapper res;
|
|
struct nlm4_shareres_wrapper shareres;
|
|
};
|
|
|
|
static DEFINE_PER_CPU_ALIGNED(unsigned long,
|
|
nlm4svc_call_counters[ARRAY_SIZE(nlm4svc_procedures)]);
|
|
|
|
const struct svc_version nlmsvc_version4 = {
|
|
.vs_vers = 4,
|
|
.vs_nproc = ARRAY_SIZE(nlm4svc_procedures),
|
|
.vs_proc = nlm4svc_procedures,
|
|
.vs_count = nlm4svc_call_counters,
|
|
.vs_dispatch = nlmsvc_dispatch,
|
|
.vs_xdrsize = sizeof(union nlm4svc_xdrstore),
|
|
};
|