Merge branch 'for-2.6.29' of git://linux-nfs.org/~bfields/linux
* 'for-2.6.29' of git://linux-nfs.org/~bfields/linux: (67 commits) nfsd: get rid of NFSD_VERSION nfsd: last_byte_offset nfsd: delete wrong file comment from nfsd/nfs4xdr.c nfsd: git rid of nfs4_cb_null_ops declaration nfsd: dprint each op status in nfsd4_proc_compound nfsd: add etoosmall to nfserrno NFSD: FIDs need to take precedence over UUIDs SUNRPC: The sunrpc server code should not be used by out-of-tree modules svc: Clean up deferred requests on transport destruction nfsd: fix double-locks of directory mutex svc: Move kfree of deferral record to common code CRED: Fix NFSD regression NLM: Clean up flow of control in make_socks() function NLM: Refactor make_socks() function nfsd: Ensure nfsv4 calls the underlying filesystem on LOCKT SUNRPC: Ensure the server closes sockets in a timely fashion NFSD: Add documenting comments for nfsctl interface NFSD: Replace open-coded integer with macro NFSD: Fix a handful of coding style issues in write_filehandle() NFSD: clean up failover sysctl function naming ...
This commit is contained in:
commit
713404d608
|
@ -16,7 +16,6 @@
|
|||
#include <linux/sunrpc/clnt.h>
|
||||
#include <linux/sunrpc/svc.h>
|
||||
#include <linux/lockd/lockd.h>
|
||||
#include <linux/lockd/sm_inter.h>
|
||||
|
||||
#define NLMDBG_FACILITY NLMDBG_CLIENT
|
||||
#define NLMCLNT_GRACE_WAIT (5*HZ)
|
||||
|
@ -518,11 +517,9 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
|
|||
unsigned char fl_type;
|
||||
int status = -ENOLCK;
|
||||
|
||||
if (nsm_monitor(host) < 0) {
|
||||
printk(KERN_NOTICE "lockd: failed to monitor %s\n",
|
||||
host->h_name);
|
||||
if (nsm_monitor(host) < 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
fl->fl_flags |= FL_ACCESS;
|
||||
status = do_vfs_lock(fl);
|
||||
fl->fl_flags = fl_flags;
|
||||
|
|
170
fs/lockd/host.c
170
fs/lockd/host.c
|
@ -15,7 +15,6 @@
|
|||
#include <linux/sunrpc/clnt.h>
|
||||
#include <linux/sunrpc/svc.h>
|
||||
#include <linux/lockd/lockd.h>
|
||||
#include <linux/lockd/sm_inter.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#include <net/ipv6.h>
|
||||
|
@ -32,11 +31,6 @@ static int nrhosts;
|
|||
static DEFINE_MUTEX(nlm_host_mutex);
|
||||
|
||||
static void nlm_gc_hosts(void);
|
||||
static struct nsm_handle *nsm_find(const struct sockaddr *sap,
|
||||
const size_t salen,
|
||||
const char *hostname,
|
||||
const size_t hostname_len,
|
||||
const int create);
|
||||
|
||||
struct nlm_lookup_host_info {
|
||||
const int server; /* search for server|client */
|
||||
|
@ -105,32 +99,6 @@ static void nlm_clear_port(struct sockaddr *sap)
|
|||
}
|
||||
}
|
||||
|
||||
static void nlm_display_address(const struct sockaddr *sap,
|
||||
char *buf, const size_t len)
|
||||
{
|
||||
const struct sockaddr_in *sin = (struct sockaddr_in *)sap;
|
||||
const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
|
||||
|
||||
switch (sap->sa_family) {
|
||||
case AF_UNSPEC:
|
||||
snprintf(buf, len, "unspecified");
|
||||
break;
|
||||
case AF_INET:
|
||||
snprintf(buf, len, "%pI4", &sin->sin_addr.s_addr);
|
||||
break;
|
||||
case AF_INET6:
|
||||
if (ipv6_addr_v4mapped(&sin6->sin6_addr))
|
||||
snprintf(buf, len, "%pI4",
|
||||
&sin6->sin6_addr.s6_addr32[3]);
|
||||
else
|
||||
snprintf(buf, len, "%pI6", &sin6->sin6_addr);
|
||||
break;
|
||||
default:
|
||||
snprintf(buf, len, "unsupported address family");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Common host lookup routine for server & client
|
||||
*/
|
||||
|
@ -190,8 +158,8 @@ static struct nlm_host *nlm_lookup_host(struct nlm_lookup_host_info *ni)
|
|||
atomic_inc(&nsm->sm_count);
|
||||
else {
|
||||
host = NULL;
|
||||
nsm = nsm_find(ni->sap, ni->salen,
|
||||
ni->hostname, ni->hostname_len, 1);
|
||||
nsm = nsm_get_handle(ni->sap, ni->salen,
|
||||
ni->hostname, ni->hostname_len);
|
||||
if (!nsm) {
|
||||
dprintk("lockd: nlm_lookup_host failed; "
|
||||
"no nsm handle\n");
|
||||
|
@ -206,6 +174,7 @@ static struct nlm_host *nlm_lookup_host(struct nlm_lookup_host_info *ni)
|
|||
goto out;
|
||||
}
|
||||
host->h_name = nsm->sm_name;
|
||||
host->h_addrbuf = nsm->sm_addrbuf;
|
||||
memcpy(nlm_addr(host), ni->sap, ni->salen);
|
||||
host->h_addrlen = ni->salen;
|
||||
nlm_clear_port(nlm_addr(host));
|
||||
|
@ -232,11 +201,6 @@ static struct nlm_host *nlm_lookup_host(struct nlm_lookup_host_info *ni)
|
|||
|
||||
nrhosts++;
|
||||
|
||||
nlm_display_address((struct sockaddr *)&host->h_addr,
|
||||
host->h_addrbuf, sizeof(host->h_addrbuf));
|
||||
nlm_display_address((struct sockaddr *)&host->h_srcaddr,
|
||||
host->h_srcaddrbuf, sizeof(host->h_srcaddrbuf));
|
||||
|
||||
dprintk("lockd: nlm_lookup_host created host %s\n",
|
||||
host->h_name);
|
||||
|
||||
|
@ -256,10 +220,8 @@ nlm_destroy_host(struct nlm_host *host)
|
|||
BUG_ON(!list_empty(&host->h_lockowners));
|
||||
BUG_ON(atomic_read(&host->h_count));
|
||||
|
||||
/*
|
||||
* Release NSM handle and unmonitor host.
|
||||
*/
|
||||
nsm_unmonitor(host);
|
||||
nsm_release(host->h_nsmhandle);
|
||||
|
||||
clnt = host->h_rpcclnt;
|
||||
if (clnt != NULL)
|
||||
|
@ -378,8 +340,8 @@ nlm_bind_host(struct nlm_host *host)
|
|||
{
|
||||
struct rpc_clnt *clnt;
|
||||
|
||||
dprintk("lockd: nlm_bind_host %s (%s), my addr=%s\n",
|
||||
host->h_name, host->h_addrbuf, host->h_srcaddrbuf);
|
||||
dprintk("lockd: nlm_bind_host %s (%s)\n",
|
||||
host->h_name, host->h_addrbuf);
|
||||
|
||||
/* Lock host handle */
|
||||
mutex_lock(&host->h_mutex);
|
||||
|
@ -481,35 +443,23 @@ void nlm_release_host(struct nlm_host *host)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We were notified that the host indicated by address &sin
|
||||
* has rebooted.
|
||||
* Release all resources held by that peer.
|
||||
/**
|
||||
* nlm_host_rebooted - Release all resources held by rebooted host
|
||||
* @info: pointer to decoded results of NLM_SM_NOTIFY call
|
||||
*
|
||||
* We were notified that the specified host has rebooted. Release
|
||||
* all resources held by that peer.
|
||||
*/
|
||||
void nlm_host_rebooted(const struct sockaddr_in *sin,
|
||||
const char *hostname,
|
||||
unsigned int hostname_len,
|
||||
u32 new_state)
|
||||
void nlm_host_rebooted(const struct nlm_reboot *info)
|
||||
{
|
||||
struct hlist_head *chain;
|
||||
struct hlist_node *pos;
|
||||
struct nsm_handle *nsm;
|
||||
struct nlm_host *host;
|
||||
|
||||
nsm = nsm_find((struct sockaddr *)sin, sizeof(*sin),
|
||||
hostname, hostname_len, 0);
|
||||
if (nsm == NULL) {
|
||||
dprintk("lockd: never saw rebooted peer '%.*s' before\n",
|
||||
hostname_len, hostname);
|
||||
nsm = nsm_reboot_lookup(info);
|
||||
if (unlikely(nsm == NULL))
|
||||
return;
|
||||
}
|
||||
|
||||
dprintk("lockd: nlm_host_rebooted(%.*s, %s)\n",
|
||||
hostname_len, hostname, nsm->sm_addrbuf);
|
||||
|
||||
/* When reclaiming locks on this peer, make sure that
|
||||
* we set up a new notification */
|
||||
nsm->sm_monitored = 0;
|
||||
|
||||
/* Mark all hosts tied to this NSM state as having rebooted.
|
||||
* We run the loop repeatedly, because we drop the host table
|
||||
|
@ -520,8 +470,8 @@ again: mutex_lock(&nlm_host_mutex);
|
|||
for (chain = nlm_hosts; chain < nlm_hosts + NLM_HOST_NRHASH; ++chain) {
|
||||
hlist_for_each_entry(host, pos, chain, h_hash) {
|
||||
if (host->h_nsmhandle == nsm
|
||||
&& host->h_nsmstate != new_state) {
|
||||
host->h_nsmstate = new_state;
|
||||
&& host->h_nsmstate != info->state) {
|
||||
host->h_nsmstate = info->state;
|
||||
host->h_state++;
|
||||
|
||||
nlm_get_host(host);
|
||||
|
@ -629,89 +579,3 @@ nlm_gc_hosts(void)
|
|||
|
||||
next_gc = jiffies + NLM_HOST_COLLECT;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Manage NSM handles
|
||||
*/
|
||||
static LIST_HEAD(nsm_handles);
|
||||
static DEFINE_SPINLOCK(nsm_lock);
|
||||
|
||||
static struct nsm_handle *nsm_find(const struct sockaddr *sap,
|
||||
const size_t salen,
|
||||
const char *hostname,
|
||||
const size_t hostname_len,
|
||||
const int create)
|
||||
{
|
||||
struct nsm_handle *nsm = NULL;
|
||||
struct nsm_handle *pos;
|
||||
|
||||
if (!sap)
|
||||
return NULL;
|
||||
|
||||
if (hostname && memchr(hostname, '/', hostname_len) != NULL) {
|
||||
if (printk_ratelimit()) {
|
||||
printk(KERN_WARNING "Invalid hostname \"%.*s\" "
|
||||
"in NFS lock request\n",
|
||||
(int)hostname_len, hostname);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
retry:
|
||||
spin_lock(&nsm_lock);
|
||||
list_for_each_entry(pos, &nsm_handles, sm_link) {
|
||||
|
||||
if (hostname && nsm_use_hostnames) {
|
||||
if (strlen(pos->sm_name) != hostname_len
|
||||
|| memcmp(pos->sm_name, hostname, hostname_len))
|
||||
continue;
|
||||
} else if (!nlm_cmp_addr(nsm_addr(pos), sap))
|
||||
continue;
|
||||
atomic_inc(&pos->sm_count);
|
||||
kfree(nsm);
|
||||
nsm = pos;
|
||||
goto found;
|
||||
}
|
||||
if (nsm) {
|
||||
list_add(&nsm->sm_link, &nsm_handles);
|
||||
goto found;
|
||||
}
|
||||
spin_unlock(&nsm_lock);
|
||||
|
||||
if (!create)
|
||||
return NULL;
|
||||
|
||||
nsm = kzalloc(sizeof(*nsm) + hostname_len + 1, GFP_KERNEL);
|
||||
if (nsm == NULL)
|
||||
return NULL;
|
||||
|
||||
memcpy(nsm_addr(nsm), sap, salen);
|
||||
nsm->sm_addrlen = salen;
|
||||
nsm->sm_name = (char *) (nsm + 1);
|
||||
memcpy(nsm->sm_name, hostname, hostname_len);
|
||||
nsm->sm_name[hostname_len] = '\0';
|
||||
nlm_display_address((struct sockaddr *)&nsm->sm_addr,
|
||||
nsm->sm_addrbuf, sizeof(nsm->sm_addrbuf));
|
||||
atomic_set(&nsm->sm_count, 1);
|
||||
goto retry;
|
||||
|
||||
found:
|
||||
spin_unlock(&nsm_lock);
|
||||
return nsm;
|
||||
}
|
||||
|
||||
/*
|
||||
* Release an NSM handle
|
||||
*/
|
||||
void
|
||||
nsm_release(struct nsm_handle *nsm)
|
||||
{
|
||||
if (!nsm)
|
||||
return;
|
||||
if (atomic_dec_and_lock(&nsm->sm_count, &nsm_lock)) {
|
||||
list_del(&nsm->sm_link);
|
||||
spin_unlock(&nsm_lock);
|
||||
kfree(nsm);
|
||||
}
|
||||
}
|
||||
|
|
569
fs/lockd/mon.c
569
fs/lockd/mon.c
|
@ -9,35 +9,123 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/utsname.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/ktime.h>
|
||||
|
||||
#include <linux/sunrpc/clnt.h>
|
||||
#include <linux/sunrpc/xprtsock.h>
|
||||
#include <linux/sunrpc/svc.h>
|
||||
#include <linux/lockd/lockd.h>
|
||||
#include <linux/lockd/sm_inter.h>
|
||||
|
||||
|
||||
#define NLMDBG_FACILITY NLMDBG_MONITOR
|
||||
#define NSM_PROGRAM 100024
|
||||
#define NSM_VERSION 1
|
||||
|
||||
#define XDR_ADDRBUF_LEN (20)
|
||||
enum {
|
||||
NSMPROC_NULL,
|
||||
NSMPROC_STAT,
|
||||
NSMPROC_MON,
|
||||
NSMPROC_UNMON,
|
||||
NSMPROC_UNMON_ALL,
|
||||
NSMPROC_SIMU_CRASH,
|
||||
NSMPROC_NOTIFY,
|
||||
};
|
||||
|
||||
static struct rpc_clnt * nsm_create(void);
|
||||
struct nsm_args {
|
||||
struct nsm_private *priv;
|
||||
u32 prog; /* RPC callback info */
|
||||
u32 vers;
|
||||
u32 proc;
|
||||
|
||||
char *mon_name;
|
||||
};
|
||||
|
||||
struct nsm_res {
|
||||
u32 status;
|
||||
u32 state;
|
||||
};
|
||||
|
||||
static struct rpc_program nsm_program;
|
||||
static LIST_HEAD(nsm_handles);
|
||||
static DEFINE_SPINLOCK(nsm_lock);
|
||||
|
||||
/*
|
||||
* Local NSM state
|
||||
*/
|
||||
int nsm_local_state;
|
||||
int __read_mostly nsm_local_state;
|
||||
int __read_mostly nsm_use_hostnames;
|
||||
|
||||
/*
|
||||
* Common procedure for SM_MON/SM_UNMON calls
|
||||
*/
|
||||
static int
|
||||
nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res)
|
||||
static inline struct sockaddr *nsm_addr(const struct nsm_handle *nsm)
|
||||
{
|
||||
return (struct sockaddr *)&nsm->sm_addr;
|
||||
}
|
||||
|
||||
static void nsm_display_ipv4_address(const struct sockaddr *sap, char *buf,
|
||||
const size_t len)
|
||||
{
|
||||
const struct sockaddr_in *sin = (struct sockaddr_in *)sap;
|
||||
snprintf(buf, len, "%pI4", &sin->sin_addr.s_addr);
|
||||
}
|
||||
|
||||
static void nsm_display_ipv6_address(const struct sockaddr *sap, char *buf,
|
||||
const size_t len)
|
||||
{
|
||||
const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
|
||||
|
||||
if (ipv6_addr_v4mapped(&sin6->sin6_addr))
|
||||
snprintf(buf, len, "%pI4", &sin6->sin6_addr.s6_addr32[3]);
|
||||
else if (sin6->sin6_scope_id != 0)
|
||||
snprintf(buf, len, "%pI6%%%u", &sin6->sin6_addr,
|
||||
sin6->sin6_scope_id);
|
||||
else
|
||||
snprintf(buf, len, "%pI6", &sin6->sin6_addr);
|
||||
}
|
||||
|
||||
static void nsm_display_address(const struct sockaddr *sap,
|
||||
char *buf, const size_t len)
|
||||
{
|
||||
switch (sap->sa_family) {
|
||||
case AF_INET:
|
||||
nsm_display_ipv4_address(sap, buf, len);
|
||||
break;
|
||||
case AF_INET6:
|
||||
nsm_display_ipv6_address(sap, buf, len);
|
||||
break;
|
||||
default:
|
||||
snprintf(buf, len, "unsupported address family");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static struct rpc_clnt *nsm_create(void)
|
||||
{
|
||||
struct sockaddr_in sin = {
|
||||
.sin_family = AF_INET,
|
||||
.sin_addr.s_addr = htonl(INADDR_LOOPBACK),
|
||||
};
|
||||
struct rpc_create_args args = {
|
||||
.protocol = XPRT_TRANSPORT_UDP,
|
||||
.address = (struct sockaddr *)&sin,
|
||||
.addrsize = sizeof(sin),
|
||||
.servername = "rpc.statd",
|
||||
.program = &nsm_program,
|
||||
.version = NSM_VERSION,
|
||||
.authflavor = RPC_AUTH_NULL,
|
||||
};
|
||||
|
||||
return rpc_create(&args);
|
||||
}
|
||||
|
||||
static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res)
|
||||
{
|
||||
struct rpc_clnt *clnt;
|
||||
int status;
|
||||
struct nsm_args args;
|
||||
struct nsm_args args = {
|
||||
.priv = &nsm->sm_priv,
|
||||
.prog = NLM_PROGRAM,
|
||||
.vers = 3,
|
||||
.proc = NLMPROC_NSM_NOTIFY,
|
||||
.mon_name = nsm->sm_mon_name,
|
||||
};
|
||||
struct rpc_message msg = {
|
||||
.rpc_argp = &args,
|
||||
.rpc_resp = res,
|
||||
|
@ -46,22 +134,18 @@ nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res)
|
|||
clnt = nsm_create();
|
||||
if (IS_ERR(clnt)) {
|
||||
status = PTR_ERR(clnt);
|
||||
dprintk("lockd: failed to create NSM upcall transport, "
|
||||
"status=%d\n", status);
|
||||
goto out;
|
||||
}
|
||||
|
||||
memset(&args, 0, sizeof(args));
|
||||
args.mon_name = nsm->sm_name;
|
||||
args.addr = nsm_addr_in(nsm)->sin_addr.s_addr;
|
||||
args.prog = NLM_PROGRAM;
|
||||
args.vers = 3;
|
||||
args.proc = NLMPROC_NSM_NOTIFY;
|
||||
memset(res, 0, sizeof(*res));
|
||||
|
||||
msg.rpc_proc = &clnt->cl_procinfo[proc];
|
||||
status = rpc_call_sync(clnt, &msg, 0);
|
||||
if (status < 0)
|
||||
printk(KERN_DEBUG "nsm_mon_unmon: rpc failed, status=%d\n",
|
||||
status);
|
||||
dprintk("lockd: NSM upcall RPC failed, status=%d\n",
|
||||
status);
|
||||
else
|
||||
status = 0;
|
||||
rpc_shutdown_client(clnt);
|
||||
|
@ -69,82 +153,272 @@ nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res)
|
|||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set up monitoring of a remote host
|
||||
/**
|
||||
* nsm_monitor - Notify a peer in case we reboot
|
||||
* @host: pointer to nlm_host of peer to notify
|
||||
*
|
||||
* If this peer is not already monitored, this function sends an
|
||||
* upcall to the local rpc.statd to record the name/address of
|
||||
* the peer to notify in case we reboot.
|
||||
*
|
||||
* Returns zero if the peer is monitored by the local rpc.statd;
|
||||
* otherwise a negative errno value is returned.
|
||||
*/
|
||||
int
|
||||
nsm_monitor(struct nlm_host *host)
|
||||
int nsm_monitor(const struct nlm_host *host)
|
||||
{
|
||||
struct nsm_handle *nsm = host->h_nsmhandle;
|
||||
struct nsm_res res;
|
||||
int status;
|
||||
|
||||
dprintk("lockd: nsm_monitor(%s)\n", host->h_name);
|
||||
BUG_ON(nsm == NULL);
|
||||
dprintk("lockd: nsm_monitor(%s)\n", nsm->sm_name);
|
||||
|
||||
if (nsm->sm_monitored)
|
||||
return 0;
|
||||
|
||||
status = nsm_mon_unmon(nsm, SM_MON, &res);
|
||||
/*
|
||||
* Choose whether to record the caller_name or IP address of
|
||||
* this peer in the local rpc.statd's database.
|
||||
*/
|
||||
nsm->sm_mon_name = nsm_use_hostnames ? nsm->sm_name : nsm->sm_addrbuf;
|
||||
|
||||
if (status < 0 || res.status != 0)
|
||||
printk(KERN_NOTICE "lockd: cannot monitor %s\n", host->h_name);
|
||||
status = nsm_mon_unmon(nsm, NSMPROC_MON, &res);
|
||||
if (res.status != 0)
|
||||
status = -EIO;
|
||||
if (status < 0)
|
||||
printk(KERN_NOTICE "lockd: cannot monitor %s\n", nsm->sm_name);
|
||||
else
|
||||
nsm->sm_monitored = 1;
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Cease to monitor remote host
|
||||
/**
|
||||
* nsm_unmonitor - Unregister peer notification
|
||||
* @host: pointer to nlm_host of peer to stop monitoring
|
||||
*
|
||||
* If this peer is monitored, this function sends an upcall to
|
||||
* tell the local rpc.statd not to send this peer a notification
|
||||
* when we reboot.
|
||||
*/
|
||||
int
|
||||
nsm_unmonitor(struct nlm_host *host)
|
||||
void nsm_unmonitor(const struct nlm_host *host)
|
||||
{
|
||||
struct nsm_handle *nsm = host->h_nsmhandle;
|
||||
struct nsm_res res;
|
||||
int status = 0;
|
||||
|
||||
if (nsm == NULL)
|
||||
return 0;
|
||||
host->h_nsmhandle = NULL;
|
||||
int status;
|
||||
|
||||
if (atomic_read(&nsm->sm_count) == 1
|
||||
&& nsm->sm_monitored && !nsm->sm_sticky) {
|
||||
dprintk("lockd: nsm_unmonitor(%s)\n", host->h_name);
|
||||
dprintk("lockd: nsm_unmonitor(%s)\n", nsm->sm_name);
|
||||
|
||||
status = nsm_mon_unmon(nsm, SM_UNMON, &res);
|
||||
status = nsm_mon_unmon(nsm, NSMPROC_UNMON, &res);
|
||||
if (res.status != 0)
|
||||
status = -EIO;
|
||||
if (status < 0)
|
||||
printk(KERN_NOTICE "lockd: cannot unmonitor %s\n",
|
||||
host->h_name);
|
||||
nsm->sm_name);
|
||||
else
|
||||
nsm->sm_monitored = 0;
|
||||
}
|
||||
nsm_release(nsm);
|
||||
return status;
|
||||
}
|
||||
|
||||
static struct nsm_handle *nsm_lookup_hostname(const char *hostname,
|
||||
const size_t len)
|
||||
{
|
||||
struct nsm_handle *nsm;
|
||||
|
||||
list_for_each_entry(nsm, &nsm_handles, sm_link)
|
||||
if (strlen(nsm->sm_name) == len &&
|
||||
memcmp(nsm->sm_name, hostname, len) == 0)
|
||||
return nsm;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct nsm_handle *nsm_lookup_addr(const struct sockaddr *sap)
|
||||
{
|
||||
struct nsm_handle *nsm;
|
||||
|
||||
list_for_each_entry(nsm, &nsm_handles, sm_link)
|
||||
if (nlm_cmp_addr(nsm_addr(nsm), sap))
|
||||
return nsm;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct nsm_handle *nsm_lookup_priv(const struct nsm_private *priv)
|
||||
{
|
||||
struct nsm_handle *nsm;
|
||||
|
||||
list_for_each_entry(nsm, &nsm_handles, sm_link)
|
||||
if (memcmp(nsm->sm_priv.data, priv->data,
|
||||
sizeof(priv->data)) == 0)
|
||||
return nsm;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create NSM client for the local host
|
||||
* Construct a unique cookie to match this nsm_handle to this monitored
|
||||
* host. It is passed to the local rpc.statd via NSMPROC_MON, and
|
||||
* returned via NLMPROC_SM_NOTIFY, in the "priv" field of these
|
||||
* requests.
|
||||
*
|
||||
* The NSM protocol requires that these cookies be unique while the
|
||||
* system is running. We prefer a stronger requirement of making them
|
||||
* unique across reboots. If user space bugs cause a stale cookie to
|
||||
* be sent to the kernel, it could cause the wrong host to lose its
|
||||
* lock state if cookies were not unique across reboots.
|
||||
*
|
||||
* The cookies are exposed only to local user space via loopback. They
|
||||
* do not appear on the physical network. If we want greater security
|
||||
* for some reason, nsm_init_private() could perform a one-way hash to
|
||||
* obscure the contents of the cookie.
|
||||
*/
|
||||
static struct rpc_clnt *
|
||||
nsm_create(void)
|
||||
static void nsm_init_private(struct nsm_handle *nsm)
|
||||
{
|
||||
struct sockaddr_in sin = {
|
||||
.sin_family = AF_INET,
|
||||
.sin_addr.s_addr = htonl(INADDR_LOOPBACK),
|
||||
.sin_port = 0,
|
||||
};
|
||||
struct rpc_create_args args = {
|
||||
.protocol = XPRT_TRANSPORT_UDP,
|
||||
.address = (struct sockaddr *)&sin,
|
||||
.addrsize = sizeof(sin),
|
||||
.servername = "localhost",
|
||||
.program = &nsm_program,
|
||||
.version = SM_VERSION,
|
||||
.authflavor = RPC_AUTH_NULL,
|
||||
};
|
||||
u64 *p = (u64 *)&nsm->sm_priv.data;
|
||||
struct timespec ts;
|
||||
|
||||
return rpc_create(&args);
|
||||
ktime_get_ts(&ts);
|
||||
*p++ = timespec_to_ns(&ts);
|
||||
*p = (unsigned long)nsm;
|
||||
}
|
||||
|
||||
static struct nsm_handle *nsm_create_handle(const struct sockaddr *sap,
|
||||
const size_t salen,
|
||||
const char *hostname,
|
||||
const size_t hostname_len)
|
||||
{
|
||||
struct nsm_handle *new;
|
||||
|
||||
new = kzalloc(sizeof(*new) + hostname_len + 1, GFP_KERNEL);
|
||||
if (unlikely(new == NULL))
|
||||
return NULL;
|
||||
|
||||
atomic_set(&new->sm_count, 1);
|
||||
new->sm_name = (char *)(new + 1);
|
||||
memcpy(nsm_addr(new), sap, salen);
|
||||
new->sm_addrlen = salen;
|
||||
nsm_init_private(new);
|
||||
nsm_display_address((const struct sockaddr *)&new->sm_addr,
|
||||
new->sm_addrbuf, sizeof(new->sm_addrbuf));
|
||||
memcpy(new->sm_name, hostname, hostname_len);
|
||||
new->sm_name[hostname_len] = '\0';
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
/**
|
||||
* nsm_get_handle - Find or create a cached nsm_handle
|
||||
* @sap: pointer to socket address of handle to find
|
||||
* @salen: length of socket address
|
||||
* @hostname: pointer to C string containing hostname to find
|
||||
* @hostname_len: length of C string
|
||||
*
|
||||
* Behavior is modulated by the global nsm_use_hostnames variable.
|
||||
*
|
||||
* Returns a cached nsm_handle after bumping its ref count, or
|
||||
* returns a fresh nsm_handle if a handle that matches @sap and/or
|
||||
* @hostname cannot be found in the handle cache. Returns NULL if
|
||||
* an error occurs.
|
||||
*/
|
||||
struct nsm_handle *nsm_get_handle(const struct sockaddr *sap,
|
||||
const size_t salen, const char *hostname,
|
||||
const size_t hostname_len)
|
||||
{
|
||||
struct nsm_handle *cached, *new = NULL;
|
||||
|
||||
if (hostname && memchr(hostname, '/', hostname_len) != NULL) {
|
||||
if (printk_ratelimit()) {
|
||||
printk(KERN_WARNING "Invalid hostname \"%.*s\" "
|
||||
"in NFS lock request\n",
|
||||
(int)hostname_len, hostname);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
retry:
|
||||
spin_lock(&nsm_lock);
|
||||
|
||||
if (nsm_use_hostnames && hostname != NULL)
|
||||
cached = nsm_lookup_hostname(hostname, hostname_len);
|
||||
else
|
||||
cached = nsm_lookup_addr(sap);
|
||||
|
||||
if (cached != NULL) {
|
||||
atomic_inc(&cached->sm_count);
|
||||
spin_unlock(&nsm_lock);
|
||||
kfree(new);
|
||||
dprintk("lockd: found nsm_handle for %s (%s), "
|
||||
"cnt %d\n", cached->sm_name,
|
||||
cached->sm_addrbuf,
|
||||
atomic_read(&cached->sm_count));
|
||||
return cached;
|
||||
}
|
||||
|
||||
if (new != NULL) {
|
||||
list_add(&new->sm_link, &nsm_handles);
|
||||
spin_unlock(&nsm_lock);
|
||||
dprintk("lockd: created nsm_handle for %s (%s)\n",
|
||||
new->sm_name, new->sm_addrbuf);
|
||||
return new;
|
||||
}
|
||||
|
||||
spin_unlock(&nsm_lock);
|
||||
|
||||
new = nsm_create_handle(sap, salen, hostname, hostname_len);
|
||||
if (unlikely(new == NULL))
|
||||
return NULL;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
/**
|
||||
* nsm_reboot_lookup - match NLMPROC_SM_NOTIFY arguments to an nsm_handle
|
||||
* @info: pointer to NLMPROC_SM_NOTIFY arguments
|
||||
*
|
||||
* Returns a matching nsm_handle if found in the nsm cache; the returned
|
||||
* nsm_handle's reference count is bumped and sm_monitored is cleared.
|
||||
* Otherwise returns NULL if some error occurred.
|
||||
*/
|
||||
struct nsm_handle *nsm_reboot_lookup(const struct nlm_reboot *info)
|
||||
{
|
||||
struct nsm_handle *cached;
|
||||
|
||||
spin_lock(&nsm_lock);
|
||||
|
||||
cached = nsm_lookup_priv(&info->priv);
|
||||
if (unlikely(cached == NULL)) {
|
||||
spin_unlock(&nsm_lock);
|
||||
dprintk("lockd: never saw rebooted peer '%.*s' before\n",
|
||||
info->len, info->mon);
|
||||
return cached;
|
||||
}
|
||||
|
||||
atomic_inc(&cached->sm_count);
|
||||
spin_unlock(&nsm_lock);
|
||||
|
||||
/*
|
||||
* During subsequent lock activity, force a fresh
|
||||
* notification to be set up for this host.
|
||||
*/
|
||||
cached->sm_monitored = 0;
|
||||
|
||||
dprintk("lockd: host %s (%s) rebooted, cnt %d\n",
|
||||
cached->sm_name, cached->sm_addrbuf,
|
||||
atomic_read(&cached->sm_count));
|
||||
return cached;
|
||||
}
|
||||
|
||||
/**
|
||||
* nsm_release - Release an NSM handle
|
||||
* @nsm: pointer to handle to be released
|
||||
*
|
||||
*/
|
||||
void nsm_release(struct nsm_handle *nsm)
|
||||
{
|
||||
if (atomic_dec_and_lock(&nsm->sm_count, &nsm_lock)) {
|
||||
list_del(&nsm->sm_link);
|
||||
spin_unlock(&nsm_lock);
|
||||
dprintk("lockd: destroyed nsm_handle for %s (%s)\n",
|
||||
nsm->sm_name, nsm->sm_addrbuf);
|
||||
kfree(nsm);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -154,127 +428,132 @@ nsm_create(void)
|
|||
* Status Monitor wire protocol.
|
||||
*/
|
||||
|
||||
static __be32 *xdr_encode_nsm_string(__be32 *p, char *string)
|
||||
static int encode_nsm_string(struct xdr_stream *xdr, const char *string)
|
||||
{
|
||||
size_t len = strlen(string);
|
||||
const u32 len = strlen(string);
|
||||
__be32 *p;
|
||||
|
||||
if (len > SM_MAXSTRLEN)
|
||||
len = SM_MAXSTRLEN;
|
||||
return xdr_encode_opaque(p, string, len);
|
||||
if (unlikely(len > SM_MAXSTRLEN))
|
||||
return -EIO;
|
||||
p = xdr_reserve_space(xdr, sizeof(u32) + len);
|
||||
if (unlikely(p == NULL))
|
||||
return -EIO;
|
||||
xdr_encode_opaque(p, string, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* "mon_name" specifies the host to be monitored.
|
||||
*
|
||||
* Linux uses a text version of the IP address of the remote
|
||||
* host as the host identifier (the "mon_name" argument).
|
||||
*
|
||||
* Linux statd always looks up the canonical hostname first for
|
||||
* whatever remote hostname it receives, so this works alright.
|
||||
*/
|
||||
static __be32 *xdr_encode_mon_name(__be32 *p, struct nsm_args *argp)
|
||||
static int encode_mon_name(struct xdr_stream *xdr, const struct nsm_args *argp)
|
||||
{
|
||||
char buffer[XDR_ADDRBUF_LEN + 1];
|
||||
char *name = argp->mon_name;
|
||||
|
||||
if (!nsm_use_hostnames) {
|
||||
snprintf(buffer, XDR_ADDRBUF_LEN,
|
||||
"%pI4", &argp->addr);
|
||||
name = buffer;
|
||||
}
|
||||
|
||||
return xdr_encode_nsm_string(p, name);
|
||||
return encode_nsm_string(xdr, argp->mon_name);
|
||||
}
|
||||
|
||||
/*
|
||||
* The "my_id" argument specifies the hostname and RPC procedure
|
||||
* to be called when the status manager receives notification
|
||||
* (via the SM_NOTIFY call) that the state of host "mon_name"
|
||||
* (via the NLMPROC_SM_NOTIFY call) that the state of host "mon_name"
|
||||
* has changed.
|
||||
*/
|
||||
static __be32 *xdr_encode_my_id(__be32 *p, struct nsm_args *argp)
|
||||
static int encode_my_id(struct xdr_stream *xdr, const struct nsm_args *argp)
|
||||
{
|
||||
p = xdr_encode_nsm_string(p, utsname()->nodename);
|
||||
if (!p)
|
||||
return ERR_PTR(-EIO);
|
||||
int status;
|
||||
__be32 *p;
|
||||
|
||||
status = encode_nsm_string(xdr, utsname()->nodename);
|
||||
if (unlikely(status != 0))
|
||||
return status;
|
||||
p = xdr_reserve_space(xdr, 3 * sizeof(u32));
|
||||
if (unlikely(p == NULL))
|
||||
return -EIO;
|
||||
*p++ = htonl(argp->prog);
|
||||
*p++ = htonl(argp->vers);
|
||||
*p++ = htonl(argp->proc);
|
||||
|
||||
return p;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The "mon_id" argument specifies the non-private arguments
|
||||
* of an SM_MON or SM_UNMON call.
|
||||
* of an NSMPROC_MON or NSMPROC_UNMON call.
|
||||
*/
|
||||
static __be32 *xdr_encode_mon_id(__be32 *p, struct nsm_args *argp)
|
||||
static int encode_mon_id(struct xdr_stream *xdr, const struct nsm_args *argp)
|
||||
{
|
||||
p = xdr_encode_mon_name(p, argp);
|
||||
if (!p)
|
||||
return ERR_PTR(-EIO);
|
||||
int status;
|
||||
|
||||
return xdr_encode_my_id(p, argp);
|
||||
status = encode_mon_name(xdr, argp);
|
||||
if (unlikely(status != 0))
|
||||
return status;
|
||||
return encode_my_id(xdr, argp);
|
||||
}
|
||||
|
||||
/*
|
||||
* The "priv" argument may contain private information required
|
||||
* by the SM_MON call. This information will be supplied in the
|
||||
* SM_NOTIFY call.
|
||||
*
|
||||
* Linux provides the raw IP address of the monitored host,
|
||||
* left in network byte order.
|
||||
* by the NSMPROC_MON call. This information will be supplied in the
|
||||
* NLMPROC_SM_NOTIFY call.
|
||||
*/
|
||||
static __be32 *xdr_encode_priv(__be32 *p, struct nsm_args *argp)
|
||||
static int encode_priv(struct xdr_stream *xdr, const struct nsm_args *argp)
|
||||
{
|
||||
*p++ = argp->addr;
|
||||
*p++ = 0;
|
||||
*p++ = 0;
|
||||
*p++ = 0;
|
||||
__be32 *p;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
static int
|
||||
xdr_encode_mon(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp)
|
||||
{
|
||||
p = xdr_encode_mon_id(p, argp);
|
||||
if (IS_ERR(p))
|
||||
return PTR_ERR(p);
|
||||
|
||||
p = xdr_encode_priv(p, argp);
|
||||
if (IS_ERR(p))
|
||||
return PTR_ERR(p);
|
||||
|
||||
rqstp->rq_slen = xdr_adjust_iovec(rqstp->rq_svec, p);
|
||||
p = xdr_reserve_space(xdr, SM_PRIV_SIZE);
|
||||
if (unlikely(p == NULL))
|
||||
return -EIO;
|
||||
xdr_encode_opaque_fixed(p, argp->priv->data, SM_PRIV_SIZE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
xdr_encode_unmon(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp)
|
||||
static int xdr_enc_mon(struct rpc_rqst *req, __be32 *p,
|
||||
const struct nsm_args *argp)
|
||||
{
|
||||
p = xdr_encode_mon_id(p, argp);
|
||||
if (IS_ERR(p))
|
||||
return PTR_ERR(p);
|
||||
rqstp->rq_slen = xdr_adjust_iovec(rqstp->rq_svec, p);
|
||||
return 0;
|
||||
struct xdr_stream xdr;
|
||||
int status;
|
||||
|
||||
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
|
||||
status = encode_mon_id(&xdr, argp);
|
||||
if (unlikely(status))
|
||||
return status;
|
||||
return encode_priv(&xdr, argp);
|
||||
}
|
||||
|
||||
static int
|
||||
xdr_decode_stat_res(struct rpc_rqst *rqstp, __be32 *p, struct nsm_res *resp)
|
||||
static int xdr_enc_unmon(struct rpc_rqst *req, __be32 *p,
|
||||
const struct nsm_args *argp)
|
||||
{
|
||||
struct xdr_stream xdr;
|
||||
|
||||
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
|
||||
return encode_mon_id(&xdr, argp);
|
||||
}
|
||||
|
||||
static int xdr_dec_stat_res(struct rpc_rqst *rqstp, __be32 *p,
|
||||
struct nsm_res *resp)
|
||||
{
|
||||
struct xdr_stream xdr;
|
||||
|
||||
xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
|
||||
p = xdr_inline_decode(&xdr, 2 * sizeof(u32));
|
||||
if (unlikely(p == NULL))
|
||||
return -EIO;
|
||||
resp->status = ntohl(*p++);
|
||||
resp->state = ntohl(*p++);
|
||||
dprintk("nsm: xdr_decode_stat_res status %d state %d\n",
|
||||
resp->state = ntohl(*p);
|
||||
|
||||
dprintk("lockd: xdr_dec_stat_res status %d state %d\n",
|
||||
resp->status, resp->state);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
xdr_decode_stat(struct rpc_rqst *rqstp, __be32 *p, struct nsm_res *resp)
|
||||
static int xdr_dec_stat(struct rpc_rqst *rqstp, __be32 *p,
|
||||
struct nsm_res *resp)
|
||||
{
|
||||
resp->state = ntohl(*p++);
|
||||
struct xdr_stream xdr;
|
||||
|
||||
xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
|
||||
p = xdr_inline_decode(&xdr, sizeof(u32));
|
||||
if (unlikely(p == NULL))
|
||||
return -EIO;
|
||||
resp->state = ntohl(*p);
|
||||
|
||||
dprintk("lockd: xdr_dec_stat state %d\n", resp->state);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -288,22 +567,22 @@ xdr_decode_stat(struct rpc_rqst *rqstp, __be32 *p, struct nsm_res *resp)
|
|||
#define SM_unmonres_sz 1
|
||||
|
||||
static struct rpc_procinfo nsm_procedures[] = {
|
||||
[SM_MON] = {
|
||||
.p_proc = SM_MON,
|
||||
.p_encode = (kxdrproc_t) xdr_encode_mon,
|
||||
.p_decode = (kxdrproc_t) xdr_decode_stat_res,
|
||||
[NSMPROC_MON] = {
|
||||
.p_proc = NSMPROC_MON,
|
||||
.p_encode = (kxdrproc_t)xdr_enc_mon,
|
||||
.p_decode = (kxdrproc_t)xdr_dec_stat_res,
|
||||
.p_arglen = SM_mon_sz,
|
||||
.p_replen = SM_monres_sz,
|
||||
.p_statidx = SM_MON,
|
||||
.p_statidx = NSMPROC_MON,
|
||||
.p_name = "MONITOR",
|
||||
},
|
||||
[SM_UNMON] = {
|
||||
.p_proc = SM_UNMON,
|
||||
.p_encode = (kxdrproc_t) xdr_encode_unmon,
|
||||
.p_decode = (kxdrproc_t) xdr_decode_stat,
|
||||
[NSMPROC_UNMON] = {
|
||||
.p_proc = NSMPROC_UNMON,
|
||||
.p_encode = (kxdrproc_t)xdr_enc_unmon,
|
||||
.p_decode = (kxdrproc_t)xdr_dec_stat,
|
||||
.p_arglen = SM_mon_id_sz,
|
||||
.p_replen = SM_unmonres_sz,
|
||||
.p_statidx = SM_UNMON,
|
||||
.p_statidx = NSMPROC_UNMON,
|
||||
.p_name = "UNMONITOR",
|
||||
},
|
||||
};
|
||||
|
@ -322,7 +601,7 @@ static struct rpc_stat nsm_stats;
|
|||
|
||||
static struct rpc_program nsm_program = {
|
||||
.name = "statd",
|
||||
.number = SM_PROGRAM,
|
||||
.number = NSM_PROGRAM,
|
||||
.nrvers = ARRAY_SIZE(nsm_version),
|
||||
.version = nsm_version,
|
||||
.stats = &nsm_stats
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
#include <linux/sunrpc/svcsock.h>
|
||||
#include <net/ip.h>
|
||||
#include <linux/lockd/lockd.h>
|
||||
#include <linux/lockd/sm_inter.h>
|
||||
#include <linux/nfs.h>
|
||||
|
||||
#define NLMDBG_FACILITY NLMDBG_SVC
|
||||
|
@ -53,6 +52,17 @@ static struct task_struct *nlmsvc_task;
|
|||
static struct svc_rqst *nlmsvc_rqst;
|
||||
unsigned long nlmsvc_timeout;
|
||||
|
||||
/*
|
||||
* If the kernel has IPv6 support available, always listen for
|
||||
* both AF_INET and AF_INET6 requests.
|
||||
*/
|
||||
#if (defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)) && \
|
||||
defined(CONFIG_SUNRPC_REGISTER_V4)
|
||||
static const sa_family_t nlmsvc_family = AF_INET6;
|
||||
#else /* (CONFIG_IPV6 || CONFIG_IPV6_MODULE) && CONFIG_SUNRPC_REGISTER_V4 */
|
||||
static const sa_family_t nlmsvc_family = AF_INET;
|
||||
#endif /* (CONFIG_IPV6 || CONFIG_IPV6_MODULE) && CONFIG_SUNRPC_REGISTER_V4 */
|
||||
|
||||
/*
|
||||
* These can be set at insmod time (useful for NFS as root filesystem),
|
||||
* and also changed through the sysctl interface. -- Jamie Lokier, Aug 2003
|
||||
|
@ -60,7 +70,9 @@ unsigned long nlmsvc_timeout;
|
|||
static unsigned long nlm_grace_period;
|
||||
static unsigned long nlm_timeout = LOCKD_DFLT_TIMEO;
|
||||
static int nlm_udpport, nlm_tcpport;
|
||||
int nsm_use_hostnames = 0;
|
||||
|
||||
/* RLIM_NOFILE defaults to 1024. That seems like a reasonable default here. */
|
||||
static unsigned int nlm_max_connections = 1024;
|
||||
|
||||
/*
|
||||
* Constants needed for the sysctl interface.
|
||||
|
@ -143,6 +155,9 @@ lockd(void *vrqstp)
|
|||
long timeout = MAX_SCHEDULE_TIMEOUT;
|
||||
RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]);
|
||||
|
||||
/* update sv_maxconn if it has changed */
|
||||
rqstp->rq_server->sv_maxconn = nlm_max_connections;
|
||||
|
||||
if (signalled()) {
|
||||
flush_signals(current);
|
||||
if (nlmsvc_ops) {
|
||||
|
@ -189,6 +204,19 @@ lockd(void *vrqstp)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int create_lockd_listener(struct svc_serv *serv, char *name,
|
||||
unsigned short port)
|
||||
{
|
||||
struct svc_xprt *xprt;
|
||||
|
||||
xprt = svc_find_xprt(serv, name, 0, 0);
|
||||
if (xprt == NULL)
|
||||
return svc_create_xprt(serv, name, port, SVC_SOCK_DEFAULTS);
|
||||
|
||||
svc_xprt_put(xprt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure there are active UDP and TCP listeners for lockd.
|
||||
*
|
||||
|
@ -202,29 +230,23 @@ lockd(void *vrqstp)
|
|||
static int make_socks(struct svc_serv *serv)
|
||||
{
|
||||
static int warned;
|
||||
struct svc_xprt *xprt;
|
||||
int err = 0;
|
||||
int err;
|
||||
|
||||
xprt = svc_find_xprt(serv, "udp", 0, 0);
|
||||
if (!xprt)
|
||||
err = svc_create_xprt(serv, "udp", nlm_udpport,
|
||||
SVC_SOCK_DEFAULTS);
|
||||
else
|
||||
svc_xprt_put(xprt);
|
||||
if (err >= 0) {
|
||||
xprt = svc_find_xprt(serv, "tcp", 0, 0);
|
||||
if (!xprt)
|
||||
err = svc_create_xprt(serv, "tcp", nlm_tcpport,
|
||||
SVC_SOCK_DEFAULTS);
|
||||
else
|
||||
svc_xprt_put(xprt);
|
||||
}
|
||||
if (err >= 0) {
|
||||
warned = 0;
|
||||
err = 0;
|
||||
} else if (warned++ == 0)
|
||||
err = create_lockd_listener(serv, "udp", nlm_udpport);
|
||||
if (err < 0)
|
||||
goto out_err;
|
||||
|
||||
err = create_lockd_listener(serv, "tcp", nlm_tcpport);
|
||||
if (err < 0)
|
||||
goto out_err;
|
||||
|
||||
warned = 0;
|
||||
return 0;
|
||||
|
||||
out_err:
|
||||
if (warned++ == 0)
|
||||
printk(KERN_WARNING
|
||||
"lockd_up: makesock failed, error=%d\n", err);
|
||||
"lockd_up: makesock failed, error=%d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -252,7 +274,7 @@ int lockd_up(void)
|
|||
"lockd_up: no pid, %d users??\n", nlmsvc_users);
|
||||
|
||||
error = -ENOMEM;
|
||||
serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE, AF_INET, NULL);
|
||||
serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE, nlmsvc_family, NULL);
|
||||
if (!serv) {
|
||||
printk(KERN_WARNING "lockd_up: create service failed\n");
|
||||
goto out;
|
||||
|
@ -276,6 +298,7 @@ int lockd_up(void)
|
|||
}
|
||||
|
||||
svc_sock_update_bufs(serv);
|
||||
serv->sv_maxconn = nlm_max_connections;
|
||||
|
||||
nlmsvc_task = kthread_run(lockd, nlmsvc_rqst, serv->sv_name);
|
||||
if (IS_ERR(nlmsvc_task)) {
|
||||
|
@ -485,6 +508,7 @@ module_param_call(nlm_udpport, param_set_port, param_get_int,
|
|||
module_param_call(nlm_tcpport, param_set_port, param_get_int,
|
||||
&nlm_tcpport, 0644);
|
||||
module_param(nsm_use_hostnames, bool, 0644);
|
||||
module_param(nlm_max_connections, uint, 0644);
|
||||
|
||||
/*
|
||||
* Initialising and terminating the module.
|
||||
|
|
|
@ -16,8 +16,6 @@
|
|||
#include <linux/nfsd/nfsd.h>
|
||||
#include <linux/lockd/lockd.h>
|
||||
#include <linux/lockd/share.h>
|
||||
#include <linux/lockd/sm_inter.h>
|
||||
|
||||
|
||||
#define NLMDBG_FACILITY NLMDBG_CLIENT
|
||||
|
||||
|
@ -419,8 +417,6 @@ static __be32
|
|||
nlm4svc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
|
||||
void *resp)
|
||||
{
|
||||
struct sockaddr_in saddr;
|
||||
|
||||
dprintk("lockd: SM_NOTIFY called\n");
|
||||
|
||||
if (!nlm_privileged_requester(rqstp)) {
|
||||
|
@ -430,14 +426,7 @@ nlm4svc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
|
|||
return rpc_system_err;
|
||||
}
|
||||
|
||||
/* Obtain the host pointer for this NFS server and try to
|
||||
* reclaim all locks we hold on this server.
|
||||
*/
|
||||
memset(&saddr, 0, sizeof(saddr));
|
||||
saddr.sin_family = AF_INET;
|
||||
saddr.sin_addr.s_addr = argp->addr;
|
||||
nlm_host_rebooted(&saddr, argp->mon, argp->len, argp->state);
|
||||
|
||||
nlm_host_rebooted(argp);
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,8 +16,6 @@
|
|||
#include <linux/nfsd/nfsd.h>
|
||||
#include <linux/lockd/lockd.h>
|
||||
#include <linux/lockd/share.h>
|
||||
#include <linux/lockd/sm_inter.h>
|
||||
|
||||
|
||||
#define NLMDBG_FACILITY NLMDBG_CLIENT
|
||||
|
||||
|
@ -451,8 +449,6 @@ static __be32
|
|||
nlmsvc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
|
||||
void *resp)
|
||||
{
|
||||
struct sockaddr_in saddr;
|
||||
|
||||
dprintk("lockd: SM_NOTIFY called\n");
|
||||
|
||||
if (!nlm_privileged_requester(rqstp)) {
|
||||
|
@ -462,14 +458,7 @@ nlmsvc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
|
|||
return rpc_system_err;
|
||||
}
|
||||
|
||||
/* Obtain the host pointer for this NFS server and try to
|
||||
* reclaim all locks we hold on this server.
|
||||
*/
|
||||
memset(&saddr, 0, sizeof(saddr));
|
||||
saddr.sin_family = AF_INET;
|
||||
saddr.sin_addr.s_addr = argp->addr;
|
||||
nlm_host_rebooted(&saddr, argp->mon, argp->len, argp->state);
|
||||
|
||||
nlm_host_rebooted(argp);
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
#include <linux/nfsd/export.h>
|
||||
#include <linux/lockd/lockd.h>
|
||||
#include <linux/lockd/share.h>
|
||||
#include <linux/lockd/sm_inter.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mount.h>
|
||||
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
#include <linux/sunrpc/svc.h>
|
||||
#include <linux/sunrpc/stats.h>
|
||||
#include <linux/lockd/lockd.h>
|
||||
#include <linux/lockd/sm_inter.h>
|
||||
|
||||
#define NLMDBG_FACILITY NLMDBG_XDR
|
||||
|
||||
|
@ -349,8 +348,8 @@ nlmsvc_decode_reboot(struct svc_rqst *rqstp, __be32 *p, struct nlm_reboot *argp)
|
|||
if (!(p = xdr_decode_string_inplace(p, &argp->mon, &argp->len, SM_MAXSTRLEN)))
|
||||
return 0;
|
||||
argp->state = ntohl(*p++);
|
||||
/* Preserve the address in network byte order */
|
||||
argp->addr = *p++;
|
||||
memcpy(&argp->priv.data, p, sizeof(argp->priv.data));
|
||||
p += XDR_QUADLEN(SM_PRIV_SIZE);
|
||||
return xdr_argsize_check(rqstp, p);
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
#include <linux/sunrpc/svc.h>
|
||||
#include <linux/sunrpc/stats.h>
|
||||
#include <linux/lockd/lockd.h>
|
||||
#include <linux/lockd/sm_inter.h>
|
||||
|
||||
#define NLMDBG_FACILITY NLMDBG_XDR
|
||||
|
||||
|
@ -356,8 +355,8 @@ nlm4svc_decode_reboot(struct svc_rqst *rqstp, __be32 *p, struct nlm_reboot *argp
|
|||
if (!(p = xdr_decode_string_inplace(p, &argp->mon, &argp->len, SM_MAXSTRLEN)))
|
||||
return 0;
|
||||
argp->state = ntohl(*p++);
|
||||
/* Preserve the address in network byte order */
|
||||
argp->addr = *p++;
|
||||
memcpy(&argp->priv.data, p, sizeof(argp->priv.data));
|
||||
p += XDR_QUADLEN(SM_PRIV_SIZE);
|
||||
return xdr_argsize_check(rqstp, p);
|
||||
}
|
||||
|
||||
|
|
|
@ -76,10 +76,10 @@ int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp)
|
|||
|
||||
ret = set_groups(new, gi);
|
||||
put_group_info(gi);
|
||||
if (!ret)
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
if (new->uid)
|
||||
if (new->fsuid)
|
||||
new->cap_effective = cap_drop_nfsd_set(new->cap_effective);
|
||||
else
|
||||
new->cap_effective = cap_raise_nfsd_set(new->cap_effective,
|
||||
|
|
|
@ -53,9 +53,6 @@
|
|||
#define NFSPROC4_CB_NULL 0
|
||||
#define NFSPROC4_CB_COMPOUND 1
|
||||
|
||||
/* declarations */
|
||||
static const struct rpc_call_ops nfs4_cb_null_ops;
|
||||
|
||||
/* Index of predefined Linux callback client operations */
|
||||
|
||||
enum {
|
||||
|
|
|
@ -946,6 +946,11 @@ encode_op:
|
|||
nfsd4_encode_operation(resp, op);
|
||||
status = op->status;
|
||||
}
|
||||
|
||||
dprintk("nfsv4 compound op %p opcnt %d #%d: %d: status %d\n",
|
||||
args->ops, args->opcnt, resp->opcnt, op->opnum,
|
||||
be32_to_cpu(status));
|
||||
|
||||
if (cstate->replay_owner) {
|
||||
nfs4_put_stateowner(cstate->replay_owner);
|
||||
cstate->replay_owner = NULL;
|
||||
|
|
|
@ -116,9 +116,9 @@ nfs4_make_rec_clidname(char *dname, struct xdr_netobj *clname)
|
|||
|
||||
md5_to_hex(dname, cksum.data);
|
||||
|
||||
kfree(cksum.data);
|
||||
status = nfs_ok;
|
||||
out:
|
||||
kfree(cksum.data);
|
||||
crypto_free_hash(desc.tfm);
|
||||
out_no_tfm:
|
||||
return status;
|
||||
|
|
|
@ -2416,6 +2416,26 @@ out:
|
|||
#define LOCK_HASH_SIZE (1 << LOCK_HASH_BITS)
|
||||
#define LOCK_HASH_MASK (LOCK_HASH_SIZE - 1)
|
||||
|
||||
static inline u64
|
||||
end_offset(u64 start, u64 len)
|
||||
{
|
||||
u64 end;
|
||||
|
||||
end = start + len;
|
||||
return end >= start ? end: NFS4_MAX_UINT64;
|
||||
}
|
||||
|
||||
/* last octet in a range */
|
||||
static inline u64
|
||||
last_byte_offset(u64 start, u64 len)
|
||||
{
|
||||
u64 end;
|
||||
|
||||
BUG_ON(!len);
|
||||
end = start + len;
|
||||
return end > start ? end - 1: NFS4_MAX_UINT64;
|
||||
}
|
||||
|
||||
#define lockownerid_hashval(id) \
|
||||
((id) & LOCK_HASH_MASK)
|
||||
|
||||
|
@ -2435,13 +2455,13 @@ static struct list_head lockstateid_hashtbl[STATEID_HASH_SIZE];
|
|||
static struct nfs4_stateid *
|
||||
find_stateid(stateid_t *stid, int flags)
|
||||
{
|
||||
struct nfs4_stateid *local = NULL;
|
||||
struct nfs4_stateid *local;
|
||||
u32 st_id = stid->si_stateownerid;
|
||||
u32 f_id = stid->si_fileid;
|
||||
unsigned int hashval;
|
||||
|
||||
dprintk("NFSD: find_stateid flags 0x%x\n",flags);
|
||||
if ((flags & LOCK_STATE) || (flags & RD_STATE) || (flags & WR_STATE)) {
|
||||
if (flags & (LOCK_STATE | RD_STATE | WR_STATE)) {
|
||||
hashval = stateid_hashval(st_id, f_id);
|
||||
list_for_each_entry(local, &lockstateid_hashtbl[hashval], st_hash) {
|
||||
if ((local->st_stateid.si_stateownerid == st_id) &&
|
||||
|
@ -2449,7 +2469,8 @@ find_stateid(stateid_t *stid, int flags)
|
|||
return local;
|
||||
}
|
||||
}
|
||||
if ((flags & OPEN_STATE) || (flags & RD_STATE) || (flags & WR_STATE)) {
|
||||
|
||||
if (flags & (OPEN_STATE | RD_STATE | WR_STATE)) {
|
||||
hashval = stateid_hashval(st_id, f_id);
|
||||
list_for_each_entry(local, &stateid_hashtbl[hashval], st_hash) {
|
||||
if ((local->st_stateid.si_stateownerid == st_id) &&
|
||||
|
@ -2518,8 +2539,8 @@ nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny)
|
|||
deny->ld_clientid.cl_id = 0;
|
||||
}
|
||||
deny->ld_start = fl->fl_start;
|
||||
deny->ld_length = ~(u64)0;
|
||||
if (fl->fl_end != ~(u64)0)
|
||||
deny->ld_length = NFS4_MAX_UINT64;
|
||||
if (fl->fl_end != NFS4_MAX_UINT64)
|
||||
deny->ld_length = fl->fl_end - fl->fl_start + 1;
|
||||
deny->ld_type = NFS4_READ_LT;
|
||||
if (fl->fl_type != F_RDLCK)
|
||||
|
@ -2616,7 +2637,7 @@ out:
|
|||
static int
|
||||
check_lock_length(u64 offset, u64 length)
|
||||
{
|
||||
return ((length == 0) || ((length != ~(u64)0) &&
|
||||
return ((length == 0) || ((length != NFS4_MAX_UINT64) &&
|
||||
LOFF_OVERFLOW(offset, length)));
|
||||
}
|
||||
|
||||
|
@ -2736,11 +2757,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
|||
file_lock.fl_lmops = &nfsd_posix_mng_ops;
|
||||
|
||||
file_lock.fl_start = lock->lk_offset;
|
||||
if ((lock->lk_length == ~(u64)0) ||
|
||||
LOFF_OVERFLOW(lock->lk_offset, lock->lk_length))
|
||||
file_lock.fl_end = ~(u64)0;
|
||||
else
|
||||
file_lock.fl_end = lock->lk_offset + lock->lk_length - 1;
|
||||
file_lock.fl_end = last_byte_offset(lock->lk_offset, lock->lk_length);
|
||||
nfs4_transform_lock_offset(&file_lock);
|
||||
|
||||
/*
|
||||
|
@ -2780,6 +2797,25 @@ out:
|
|||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* The NFSv4 spec allows a client to do a LOCKT without holding an OPEN,
|
||||
* so we do a temporary open here just to get an open file to pass to
|
||||
* vfs_test_lock. (Arguably perhaps test_lock should be done with an
|
||||
* inode operation.)
|
||||
*/
|
||||
static int nfsd_test_lock(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file_lock *lock)
|
||||
{
|
||||
struct file *file;
|
||||
int err;
|
||||
|
||||
err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, &file);
|
||||
if (err)
|
||||
return err;
|
||||
err = vfs_test_lock(file, lock);
|
||||
nfsd_close(file);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* LOCKT operation
|
||||
*/
|
||||
|
@ -2788,7 +2824,6 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
|||
struct nfsd4_lockt *lockt)
|
||||
{
|
||||
struct inode *inode;
|
||||
struct file file;
|
||||
struct file_lock file_lock;
|
||||
int error;
|
||||
__be32 status;
|
||||
|
@ -2839,23 +2874,12 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
|||
file_lock.fl_lmops = &nfsd_posix_mng_ops;
|
||||
|
||||
file_lock.fl_start = lockt->lt_offset;
|
||||
if ((lockt->lt_length == ~(u64)0) || LOFF_OVERFLOW(lockt->lt_offset, lockt->lt_length))
|
||||
file_lock.fl_end = ~(u64)0;
|
||||
else
|
||||
file_lock.fl_end = lockt->lt_offset + lockt->lt_length - 1;
|
||||
file_lock.fl_end = last_byte_offset(lockt->lt_offset, lockt->lt_length);
|
||||
|
||||
nfs4_transform_lock_offset(&file_lock);
|
||||
|
||||
/* vfs_test_lock uses the struct file _only_ to resolve the inode.
|
||||
* since LOCKT doesn't require an OPEN, and therefore a struct
|
||||
* file may not exist, pass vfs_test_lock a struct file with
|
||||
* only the dentry:inode set.
|
||||
*/
|
||||
memset(&file, 0, sizeof (struct file));
|
||||
file.f_path.dentry = cstate->current_fh.fh_dentry;
|
||||
|
||||
status = nfs_ok;
|
||||
error = vfs_test_lock(&file, &file_lock);
|
||||
error = nfsd_test_lock(rqstp, &cstate->current_fh, &file_lock);
|
||||
if (error) {
|
||||
status = nfserrno(error);
|
||||
goto out;
|
||||
|
@ -2906,10 +2930,7 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
|||
file_lock.fl_lmops = &nfsd_posix_mng_ops;
|
||||
file_lock.fl_start = locku->lu_offset;
|
||||
|
||||
if ((locku->lu_length == ~(u64)0) || LOFF_OVERFLOW(locku->lu_offset, locku->lu_length))
|
||||
file_lock.fl_end = ~(u64)0;
|
||||
else
|
||||
file_lock.fl_end = locku->lu_offset + locku->lu_length - 1;
|
||||
file_lock.fl_end = last_byte_offset(locku->lu_offset, locku->lu_length);
|
||||
nfs4_transform_lock_offset(&file_lock);
|
||||
|
||||
/*
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
/*
|
||||
* fs/nfs/nfs4xdr.c
|
||||
*
|
||||
* Server-side XDR for NFSv4
|
||||
*
|
||||
* Copyright (c) 2002 The Regents of the University of Michigan.
|
||||
|
|
479
fs/nfsd/nfsctl.c
479
fs/nfsd/nfsctl.c
|
@ -84,6 +84,8 @@ static ssize_t write_unexport(struct file *file, char *buf, size_t size);
|
|||
static ssize_t write_getfd(struct file *file, char *buf, size_t size);
|
||||
static ssize_t write_getfs(struct file *file, char *buf, size_t size);
|
||||
static ssize_t write_filehandle(struct file *file, char *buf, size_t size);
|
||||
static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size);
|
||||
static ssize_t write_unlock_fs(struct file *file, char *buf, size_t size);
|
||||
static ssize_t write_threads(struct file *file, char *buf, size_t size);
|
||||
static ssize_t write_pool_threads(struct file *file, char *buf, size_t size);
|
||||
static ssize_t write_versions(struct file *file, char *buf, size_t size);
|
||||
|
@ -94,9 +96,6 @@ static ssize_t write_leasetime(struct file *file, char *buf, size_t size);
|
|||
static ssize_t write_recoverydir(struct file *file, char *buf, size_t size);
|
||||
#endif
|
||||
|
||||
static ssize_t failover_unlock_ip(struct file *file, char *buf, size_t size);
|
||||
static ssize_t failover_unlock_fs(struct file *file, char *buf, size_t size);
|
||||
|
||||
static ssize_t (*write_op[])(struct file *, char *, size_t) = {
|
||||
[NFSD_Svc] = write_svc,
|
||||
[NFSD_Add] = write_add,
|
||||
|
@ -106,8 +105,8 @@ static ssize_t (*write_op[])(struct file *, char *, size_t) = {
|
|||
[NFSD_Getfd] = write_getfd,
|
||||
[NFSD_Getfs] = write_getfs,
|
||||
[NFSD_Fh] = write_filehandle,
|
||||
[NFSD_FO_UnlockIP] = failover_unlock_ip,
|
||||
[NFSD_FO_UnlockFS] = failover_unlock_fs,
|
||||
[NFSD_FO_UnlockIP] = write_unlock_ip,
|
||||
[NFSD_FO_UnlockFS] = write_unlock_fs,
|
||||
[NFSD_Threads] = write_threads,
|
||||
[NFSD_Pool_Threads] = write_pool_threads,
|
||||
[NFSD_Versions] = write_versions,
|
||||
|
@ -176,10 +175,24 @@ static const struct file_operations exports_operations = {
|
|||
/*----------------------------------------------------------------------------*/
|
||||
/*
|
||||
* payload - write methods
|
||||
* If the method has a response, the response should be put in buf,
|
||||
* and the length returned. Otherwise return 0 or and -error.
|
||||
*/
|
||||
|
||||
/**
|
||||
* write_svc - Start kernel's NFSD server
|
||||
*
|
||||
* Deprecated. /proc/fs/nfsd/threads is preferred.
|
||||
* Function remains to support old versions of nfs-utils.
|
||||
*
|
||||
* Input:
|
||||
* buf: struct nfsctl_svc
|
||||
* svc_port: port number of this
|
||||
* server's listener
|
||||
* svc_nthreads: number of threads to start
|
||||
* size: size in bytes of passed in nfsctl_svc
|
||||
* Output:
|
||||
* On success: returns zero
|
||||
* On error: return code is negative errno value
|
||||
*/
|
||||
static ssize_t write_svc(struct file *file, char *buf, size_t size)
|
||||
{
|
||||
struct nfsctl_svc *data;
|
||||
|
@ -189,6 +202,30 @@ static ssize_t write_svc(struct file *file, char *buf, size_t size)
|
|||
return nfsd_svc(data->svc_port, data->svc_nthreads);
|
||||
}
|
||||
|
||||
/**
|
||||
* write_add - Add or modify client entry in auth unix cache
|
||||
*
|
||||
* Deprecated. /proc/net/rpc/auth.unix.ip is preferred.
|
||||
* Function remains to support old versions of nfs-utils.
|
||||
*
|
||||
* Input:
|
||||
* buf: struct nfsctl_client
|
||||
* cl_ident: '\0'-terminated C string
|
||||
* containing domain name
|
||||
* of client
|
||||
* cl_naddr: no. of items in cl_addrlist
|
||||
* cl_addrlist: array of client addresses
|
||||
* cl_fhkeytype: ignored
|
||||
* cl_fhkeylen: ignored
|
||||
* cl_fhkey: ignored
|
||||
* size: size in bytes of passed in nfsctl_client
|
||||
* Output:
|
||||
* On success: returns zero
|
||||
* On error: return code is negative errno value
|
||||
*
|
||||
* Note: Only AF_INET client addresses are passed in, since
|
||||
* nfsctl_client.cl_addrlist contains only in_addr fields for addresses.
|
||||
*/
|
||||
static ssize_t write_add(struct file *file, char *buf, size_t size)
|
||||
{
|
||||
struct nfsctl_client *data;
|
||||
|
@ -198,6 +235,30 @@ static ssize_t write_add(struct file *file, char *buf, size_t size)
|
|||
return exp_addclient(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* write_del - Remove client from auth unix cache
|
||||
*
|
||||
* Deprecated. /proc/net/rpc/auth.unix.ip is preferred.
|
||||
* Function remains to support old versions of nfs-utils.
|
||||
*
|
||||
* Input:
|
||||
* buf: struct nfsctl_client
|
||||
* cl_ident: '\0'-terminated C string
|
||||
* containing domain name
|
||||
* of client
|
||||
* cl_naddr: ignored
|
||||
* cl_addrlist: ignored
|
||||
* cl_fhkeytype: ignored
|
||||
* cl_fhkeylen: ignored
|
||||
* cl_fhkey: ignored
|
||||
* size: size in bytes of passed in nfsctl_client
|
||||
* Output:
|
||||
* On success: returns zero
|
||||
* On error: return code is negative errno value
|
||||
*
|
||||
* Note: Only AF_INET client addresses are passed in, since
|
||||
* nfsctl_client.cl_addrlist contains only in_addr fields for addresses.
|
||||
*/
|
||||
static ssize_t write_del(struct file *file, char *buf, size_t size)
|
||||
{
|
||||
struct nfsctl_client *data;
|
||||
|
@ -207,6 +268,33 @@ static ssize_t write_del(struct file *file, char *buf, size_t size)
|
|||
return exp_delclient(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* write_export - Export part or all of a local file system
|
||||
*
|
||||
* Deprecated. /proc/net/rpc/{nfsd.export,nfsd.fh} are preferred.
|
||||
* Function remains to support old versions of nfs-utils.
|
||||
*
|
||||
* Input:
|
||||
* buf: struct nfsctl_export
|
||||
* ex_client: '\0'-terminated C string
|
||||
* containing domain name
|
||||
* of client allowed to access
|
||||
* this export
|
||||
* ex_path: '\0'-terminated C string
|
||||
* containing pathname of
|
||||
* directory in local file system
|
||||
* ex_dev: fsid to use for this export
|
||||
* ex_ino: ignored
|
||||
* ex_flags: export flags for this export
|
||||
* ex_anon_uid: UID to use for anonymous
|
||||
* requests
|
||||
* ex_anon_gid: GID to use for anonymous
|
||||
* requests
|
||||
* size: size in bytes of passed in nfsctl_export
|
||||
* Output:
|
||||
* On success: returns zero
|
||||
* On error: return code is negative errno value
|
||||
*/
|
||||
static ssize_t write_export(struct file *file, char *buf, size_t size)
|
||||
{
|
||||
struct nfsctl_export *data;
|
||||
|
@ -216,6 +304,31 @@ static ssize_t write_export(struct file *file, char *buf, size_t size)
|
|||
return exp_export(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* write_unexport - Unexport a previously exported file system
|
||||
*
|
||||
* Deprecated. /proc/net/rpc/{nfsd.export,nfsd.fh} are preferred.
|
||||
* Function remains to support old versions of nfs-utils.
|
||||
*
|
||||
* Input:
|
||||
* buf: struct nfsctl_export
|
||||
* ex_client: '\0'-terminated C string
|
||||
* containing domain name
|
||||
* of client no longer allowed
|
||||
* to access this export
|
||||
* ex_path: '\0'-terminated C string
|
||||
* containing pathname of
|
||||
* directory in local file system
|
||||
* ex_dev: ignored
|
||||
* ex_ino: ignored
|
||||
* ex_flags: ignored
|
||||
* ex_anon_uid: ignored
|
||||
* ex_anon_gid: ignored
|
||||
* size: size in bytes of passed in nfsctl_export
|
||||
* Output:
|
||||
* On success: returns zero
|
||||
* On error: return code is negative errno value
|
||||
*/
|
||||
static ssize_t write_unexport(struct file *file, char *buf, size_t size)
|
||||
{
|
||||
struct nfsctl_export *data;
|
||||
|
@ -226,6 +339,30 @@ static ssize_t write_unexport(struct file *file, char *buf, size_t size)
|
|||
return exp_unexport(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* write_getfs - Get a variable-length NFS file handle by path
|
||||
*
|
||||
* Deprecated. /proc/fs/nfsd/filehandle is preferred.
|
||||
* Function remains to support old versions of nfs-utils.
|
||||
*
|
||||
* Input:
|
||||
* buf: struct nfsctl_fsparm
|
||||
* gd_addr: socket address of client
|
||||
* gd_path: '\0'-terminated C string
|
||||
* containing pathname of
|
||||
* directory in local file system
|
||||
* gd_maxlen: maximum size of returned file
|
||||
* handle
|
||||
* size: size in bytes of passed in nfsctl_fsparm
|
||||
* Output:
|
||||
* On success: passed-in buffer filled with a knfsd_fh structure
|
||||
* (a variable-length raw NFS file handle);
|
||||
* return code is the size in bytes of the file handle
|
||||
* On error: return code is negative errno value
|
||||
*
|
||||
* Note: Only AF_INET client addresses are passed in, since gd_addr
|
||||
* is the same size as a struct sockaddr_in.
|
||||
*/
|
||||
static ssize_t write_getfs(struct file *file, char *buf, size_t size)
|
||||
{
|
||||
struct nfsctl_fsparm *data;
|
||||
|
@ -265,6 +402,29 @@ static ssize_t write_getfs(struct file *file, char *buf, size_t size)
|
|||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* write_getfd - Get a fixed-length NFS file handle by path (used by mountd)
|
||||
*
|
||||
* Deprecated. /proc/fs/nfsd/filehandle is preferred.
|
||||
* Function remains to support old versions of nfs-utils.
|
||||
*
|
||||
* Input:
|
||||
* buf: struct nfsctl_fdparm
|
||||
* gd_addr: socket address of client
|
||||
* gd_path: '\0'-terminated C string
|
||||
* containing pathname of
|
||||
* directory in local file system
|
||||
* gd_version: fdparm structure version
|
||||
* size: size in bytes of passed in nfsctl_fdparm
|
||||
* Output:
|
||||
* On success: passed-in buffer filled with nfsctl_res
|
||||
* (a fixed-length raw NFS file handle);
|
||||
* return code is the size in bytes of the file handle
|
||||
* On error: return code is negative errno value
|
||||
*
|
||||
* Note: Only AF_INET client addresses are passed in, since gd_addr
|
||||
* is the same size as a struct sockaddr_in.
|
||||
*/
|
||||
static ssize_t write_getfd(struct file *file, char *buf, size_t size)
|
||||
{
|
||||
struct nfsctl_fdparm *data;
|
||||
|
@ -309,7 +469,23 @@ static ssize_t write_getfd(struct file *file, char *buf, size_t size)
|
|||
return err;
|
||||
}
|
||||
|
||||
static ssize_t failover_unlock_ip(struct file *file, char *buf, size_t size)
|
||||
/**
|
||||
* write_unlock_ip - Release all locks used by a client
|
||||
*
|
||||
* Experimental.
|
||||
*
|
||||
* Input:
|
||||
* buf: '\n'-terminated C string containing a
|
||||
* presentation format IPv4 address
|
||||
* size: length of C string in @buf
|
||||
* Output:
|
||||
* On success: returns zero if all specified locks were released;
|
||||
* returns one if one or more locks were not released
|
||||
* On error: return code is negative errno value
|
||||
*
|
||||
* Note: Only AF_INET client addresses are passed in
|
||||
*/
|
||||
static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size)
|
||||
{
|
||||
struct sockaddr_in sin = {
|
||||
.sin_family = AF_INET,
|
||||
|
@ -339,7 +515,21 @@ static ssize_t failover_unlock_ip(struct file *file, char *buf, size_t size)
|
|||
return nlmsvc_unlock_all_by_ip((struct sockaddr *)&sin);
|
||||
}
|
||||
|
||||
static ssize_t failover_unlock_fs(struct file *file, char *buf, size_t size)
|
||||
/**
|
||||
* write_unlock_fs - Release all locks on a local file system
|
||||
*
|
||||
* Experimental.
|
||||
*
|
||||
* Input:
|
||||
* buf: '\n'-terminated C string containing the
|
||||
* absolute pathname of a local file system
|
||||
* size: length of C string in @buf
|
||||
* Output:
|
||||
* On success: returns zero if all specified locks were released;
|
||||
* returns one if one or more locks were not released
|
||||
* On error: return code is negative errno value
|
||||
*/
|
||||
static ssize_t write_unlock_fs(struct file *file, char *buf, size_t size)
|
||||
{
|
||||
struct path path;
|
||||
char *fo_path;
|
||||
|
@ -360,21 +550,44 @@ static ssize_t failover_unlock_fs(struct file *file, char *buf, size_t size)
|
|||
if (error)
|
||||
return error;
|
||||
|
||||
/*
|
||||
* XXX: Needs better sanity checking. Otherwise we could end up
|
||||
* releasing locks on the wrong file system.
|
||||
*
|
||||
* For example:
|
||||
* 1. Does the path refer to a directory?
|
||||
* 2. Is that directory a mount point, or
|
||||
* 3. Is that directory the root of an exported file system?
|
||||
*/
|
||||
error = nlmsvc_unlock_all_by_sb(path.mnt->mnt_sb);
|
||||
|
||||
path_put(&path);
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* write_filehandle - Get a variable-length NFS file handle by path
|
||||
*
|
||||
* On input, the buffer contains a '\n'-terminated C string comprised of
|
||||
* three alphanumeric words separated by whitespace. The string may
|
||||
* contain escape sequences.
|
||||
*
|
||||
* Input:
|
||||
* buf:
|
||||
* domain: client domain name
|
||||
* path: export pathname
|
||||
* maxsize: numeric maximum size of
|
||||
* @buf
|
||||
* size: length of C string in @buf
|
||||
* Output:
|
||||
* On success: passed-in buffer filled with '\n'-terminated C
|
||||
* string containing a ASCII hex text version
|
||||
* of the NFS file handle;
|
||||
* return code is the size in bytes of the string
|
||||
* On error: return code is negative errno value
|
||||
*/
|
||||
static ssize_t write_filehandle(struct file *file, char *buf, size_t size)
|
||||
{
|
||||
/* request is:
|
||||
* domain path maxsize
|
||||
* response is
|
||||
* filehandle
|
||||
*
|
||||
* qword quoting is used, so filehandle will be \x....
|
||||
*/
|
||||
char *dname, *path;
|
||||
int uninitialized_var(maxsize);
|
||||
char *mesg = buf;
|
||||
|
@ -391,11 +604,13 @@ static ssize_t write_filehandle(struct file *file, char *buf, size_t size)
|
|||
|
||||
dname = mesg;
|
||||
len = qword_get(&mesg, dname, size);
|
||||
if (len <= 0) return -EINVAL;
|
||||
if (len <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
path = dname+len+1;
|
||||
len = qword_get(&mesg, path, size);
|
||||
if (len <= 0) return -EINVAL;
|
||||
if (len <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
len = get_int(&mesg, &maxsize);
|
||||
if (len)
|
||||
|
@ -419,17 +634,43 @@ static ssize_t write_filehandle(struct file *file, char *buf, size_t size)
|
|||
if (len)
|
||||
return len;
|
||||
|
||||
mesg = buf; len = SIMPLE_TRANSACTION_LIMIT;
|
||||
mesg = buf;
|
||||
len = SIMPLE_TRANSACTION_LIMIT;
|
||||
qword_addhex(&mesg, &len, (char*)&fh.fh_base, fh.fh_size);
|
||||
mesg[-1] = '\n';
|
||||
return mesg - buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* write_threads - Start NFSD, or report the current number of running threads
|
||||
*
|
||||
* Input:
|
||||
* buf: ignored
|
||||
* size: zero
|
||||
* Output:
|
||||
* On success: passed-in buffer filled with '\n'-terminated C
|
||||
* string numeric value representing the number of
|
||||
* running NFSD threads;
|
||||
* return code is the size in bytes of the string
|
||||
* On error: return code is zero
|
||||
*
|
||||
* OR
|
||||
*
|
||||
* Input:
|
||||
* buf: C string containing an unsigned
|
||||
* integer value representing the
|
||||
* number of NFSD threads to start
|
||||
* size: non-zero length of C string in @buf
|
||||
* Output:
|
||||
* On success: NFS service is started;
|
||||
* passed-in buffer filled with '\n'-terminated C
|
||||
* string numeric value representing the number of
|
||||
* running NFSD threads;
|
||||
* return code is the size in bytes of the string
|
||||
* On error: return code is zero or a negative errno value
|
||||
*/
|
||||
static ssize_t write_threads(struct file *file, char *buf, size_t size)
|
||||
{
|
||||
/* if size > 0, look for a number of threads and call nfsd_svc
|
||||
* then write out number of threads as reply
|
||||
*/
|
||||
char *mesg = buf;
|
||||
int rv;
|
||||
if (size > 0) {
|
||||
|
@ -437,9 +678,9 @@ static ssize_t write_threads(struct file *file, char *buf, size_t size)
|
|||
rv = get_int(&mesg, &newthreads);
|
||||
if (rv)
|
||||
return rv;
|
||||
if (newthreads <0)
|
||||
if (newthreads < 0)
|
||||
return -EINVAL;
|
||||
rv = nfsd_svc(2049, newthreads);
|
||||
rv = nfsd_svc(NFS_PORT, newthreads);
|
||||
if (rv)
|
||||
return rv;
|
||||
}
|
||||
|
@ -447,6 +688,28 @@ static ssize_t write_threads(struct file *file, char *buf, size_t size)
|
|||
return strlen(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* write_pool_threads - Set or report the current number of threads per pool
|
||||
*
|
||||
* Input:
|
||||
* buf: ignored
|
||||
* size: zero
|
||||
*
|
||||
* OR
|
||||
*
|
||||
* Input:
|
||||
* buf: C string containing whitespace-
|
||||
* separated unsigned integer values
|
||||
* representing the number of NFSD
|
||||
* threads to start in each pool
|
||||
* size: non-zero length of C string in @buf
|
||||
* Output:
|
||||
* On success: passed-in buffer filled with '\n'-terminated C
|
||||
* string containing integer values representing the
|
||||
* number of NFSD threads in each pool;
|
||||
* return code is the size in bytes of the string
|
||||
* On error: return code is zero or a negative errno value
|
||||
*/
|
||||
static ssize_t write_pool_threads(struct file *file, char *buf, size_t size)
|
||||
{
|
||||
/* if size > 0, look for an array of number of threads per node
|
||||
|
@ -517,10 +780,6 @@ out_free:
|
|||
|
||||
static ssize_t __write_versions(struct file *file, char *buf, size_t size)
|
||||
{
|
||||
/*
|
||||
* Format:
|
||||
* [-/+]vers [-/+]vers ...
|
||||
*/
|
||||
char *mesg = buf;
|
||||
char *vers, sign;
|
||||
int len, num;
|
||||
|
@ -578,6 +837,38 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size)
|
|||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* write_versions - Set or report the available NFS protocol versions
|
||||
*
|
||||
* Input:
|
||||
* buf: ignored
|
||||
* size: zero
|
||||
* Output:
|
||||
* On success: passed-in buffer filled with '\n'-terminated C
|
||||
* string containing positive or negative integer
|
||||
* values representing the current status of each
|
||||
* protocol version;
|
||||
* return code is the size in bytes of the string
|
||||
* On error: return code is zero or a negative errno value
|
||||
*
|
||||
* OR
|
||||
*
|
||||
* Input:
|
||||
* buf: C string containing whitespace-
|
||||
* separated positive or negative
|
||||
* integer values representing NFS
|
||||
* protocol versions to enable ("+n")
|
||||
* or disable ("-n")
|
||||
* size: non-zero length of C string in @buf
|
||||
* Output:
|
||||
* On success: status of zero or more protocol versions has
|
||||
* been updated; passed-in buffer filled with
|
||||
* '\n'-terminated C string containing positive
|
||||
* or negative integer values representing the
|
||||
* current status of each protocol version;
|
||||
* return code is the size in bytes of the string
|
||||
* On error: return code is zero or a negative errno value
|
||||
*/
|
||||
static ssize_t write_versions(struct file *file, char *buf, size_t size)
|
||||
{
|
||||
ssize_t rv;
|
||||
|
@ -687,6 +978,75 @@ static ssize_t __write_ports(struct file *file, char *buf, size_t size)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* write_ports - Pass a socket file descriptor or transport name to listen on
|
||||
*
|
||||
* Input:
|
||||
* buf: ignored
|
||||
* size: zero
|
||||
* Output:
|
||||
* On success: passed-in buffer filled with a '\n'-terminated C
|
||||
* string containing a whitespace-separated list of
|
||||
* named NFSD listeners;
|
||||
* return code is the size in bytes of the string
|
||||
* On error: return code is zero or a negative errno value
|
||||
*
|
||||
* OR
|
||||
*
|
||||
* Input:
|
||||
* buf: C string containing an unsigned
|
||||
* integer value representing a bound
|
||||
* but unconnected socket that is to be
|
||||
* used as an NFSD listener
|
||||
* size: non-zero length of C string in @buf
|
||||
* Output:
|
||||
* On success: NFS service is started;
|
||||
* passed-in buffer filled with a '\n'-terminated C
|
||||
* string containing a unique alphanumeric name of
|
||||
* the listener;
|
||||
* return code is the size in bytes of the string
|
||||
* On error: return code is a negative errno value
|
||||
*
|
||||
* OR
|
||||
*
|
||||
* Input:
|
||||
* buf: C string containing a "-" followed
|
||||
* by an integer value representing a
|
||||
* previously passed in socket file
|
||||
* descriptor
|
||||
* size: non-zero length of C string in @buf
|
||||
* Output:
|
||||
* On success: NFS service no longer listens on that socket;
|
||||
* passed-in buffer filled with a '\n'-terminated C
|
||||
* string containing a unique name of the listener;
|
||||
* return code is the size in bytes of the string
|
||||
* On error: return code is a negative errno value
|
||||
*
|
||||
* OR
|
||||
*
|
||||
* Input:
|
||||
* buf: C string containing a transport
|
||||
* name and an unsigned integer value
|
||||
* representing the port to listen on,
|
||||
* separated by whitespace
|
||||
* size: non-zero length of C string in @buf
|
||||
* Output:
|
||||
* On success: returns zero; NFS service is started
|
||||
* On error: return code is a negative errno value
|
||||
*
|
||||
* OR
|
||||
*
|
||||
* Input:
|
||||
* buf: C string containing a "-" followed
|
||||
* by a transport name and an unsigned
|
||||
* integer value representing the port
|
||||
* to listen on, separated by whitespace
|
||||
* size: non-zero length of C string in @buf
|
||||
* Output:
|
||||
* On success: returns zero; NFS service no longer listens
|
||||
* on that transport
|
||||
* On error: return code is a negative errno value
|
||||
*/
|
||||
static ssize_t write_ports(struct file *file, char *buf, size_t size)
|
||||
{
|
||||
ssize_t rv;
|
||||
|
@ -700,6 +1060,27 @@ static ssize_t write_ports(struct file *file, char *buf, size_t size)
|
|||
|
||||
int nfsd_max_blksize;
|
||||
|
||||
/**
|
||||
* write_maxblksize - Set or report the current NFS blksize
|
||||
*
|
||||
* Input:
|
||||
* buf: ignored
|
||||
* size: zero
|
||||
*
|
||||
* OR
|
||||
*
|
||||
* Input:
|
||||
* buf: C string containing an unsigned
|
||||
* integer value representing the new
|
||||
* NFS blksize
|
||||
* size: non-zero length of C string in @buf
|
||||
* Output:
|
||||
* On success: passed-in buffer filled with '\n'-terminated C string
|
||||
* containing numeric value of the current NFS blksize
|
||||
* setting;
|
||||
* return code is the size in bytes of the string
|
||||
* On error: return code is zero or a negative errno value
|
||||
*/
|
||||
static ssize_t write_maxblksize(struct file *file, char *buf, size_t size)
|
||||
{
|
||||
char *mesg = buf;
|
||||
|
@ -752,6 +1133,27 @@ static ssize_t __write_leasetime(struct file *file, char *buf, size_t size)
|
|||
return strlen(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* write_leasetime - Set or report the current NFSv4 lease time
|
||||
*
|
||||
* Input:
|
||||
* buf: ignored
|
||||
* size: zero
|
||||
*
|
||||
* OR
|
||||
*
|
||||
* Input:
|
||||
* buf: C string containing an unsigned
|
||||
* integer value representing the new
|
||||
* NFSv4 lease expiry time
|
||||
* size: non-zero length of C string in @buf
|
||||
* Output:
|
||||
* On success: passed-in buffer filled with '\n'-terminated C
|
||||
* string containing unsigned integer value of the
|
||||
* current lease expiry time;
|
||||
* return code is the size in bytes of the string
|
||||
* On error: return code is zero or a negative errno value
|
||||
*/
|
||||
static ssize_t write_leasetime(struct file *file, char *buf, size_t size)
|
||||
{
|
||||
ssize_t rv;
|
||||
|
@ -788,6 +1190,27 @@ static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size)
|
|||
return strlen(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* write_recoverydir - Set or report the pathname of the recovery directory
|
||||
*
|
||||
* Input:
|
||||
* buf: ignored
|
||||
* size: zero
|
||||
*
|
||||
* OR
|
||||
*
|
||||
* Input:
|
||||
* buf: C string containing the pathname
|
||||
* of the directory on a local file
|
||||
* system containing permanent NFSv4
|
||||
* recovery data
|
||||
* size: non-zero length of C string in @buf
|
||||
* Output:
|
||||
* On success: passed-in buffer filled with '\n'-terminated C string
|
||||
* containing the current recovery pathname setting;
|
||||
* return code is the size in bytes of the string
|
||||
* On error: return code is zero or a negative errno value
|
||||
*/
|
||||
static ssize_t write_recoverydir(struct file *file, char *buf, size_t size)
|
||||
{
|
||||
ssize_t rv;
|
||||
|
|
|
@ -258,14 +258,32 @@ out:
|
|||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform sanity checks on the dentry in a client's file handle.
|
||||
/**
|
||||
* fh_verify - filehandle lookup and access checking
|
||||
* @rqstp: pointer to current rpc request
|
||||
* @fhp: filehandle to be verified
|
||||
* @type: expected type of object pointed to by filehandle
|
||||
* @access: type of access needed to object
|
||||
*
|
||||
* Note that the file handle dentry may need to be freed even after
|
||||
* an error return.
|
||||
* Look up a dentry from the on-the-wire filehandle, check the client's
|
||||
* access to the export, and set the current task's credentials.
|
||||
*
|
||||
* This is only called at the start of an nfsproc call, so fhp points to
|
||||
* a svc_fh which is all 0 except for the over-the-wire file handle.
|
||||
* Regardless of success or failure of fh_verify(), fh_put() should be
|
||||
* called on @fhp when the caller is finished with the filehandle.
|
||||
*
|
||||
* fh_verify() may be called multiple times on a given filehandle, for
|
||||
* example, when processing an NFSv4 compound. The first call will look
|
||||
* up a dentry using the on-the-wire filehandle. Subsequent calls will
|
||||
* skip the lookup and just perform the other checks and possibly change
|
||||
* the current task's credentials.
|
||||
*
|
||||
* @type specifies the type of object expected using one of the S_IF*
|
||||
* constants defined in include/linux/stat.h. The caller may use zero
|
||||
* to indicate that it doesn't care, or a negative integer to indicate
|
||||
* that it expects something not of the given type.
|
||||
*
|
||||
* @access is formed from the NFSD_MAY_* constants defined in
|
||||
* include/linux/nfsd/nfsd.h.
|
||||
*/
|
||||
__be32
|
||||
fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
|
||||
|
@ -466,6 +484,8 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry,
|
|||
goto retry;
|
||||
break;
|
||||
}
|
||||
} else if (exp->ex_flags & NFSEXP_FSID) {
|
||||
fsid_type = FSID_NUM;
|
||||
} else if (exp->ex_uuid) {
|
||||
if (fhp->fh_maxsize >= 64) {
|
||||
if (root_export)
|
||||
|
@ -478,9 +498,7 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry,
|
|||
else
|
||||
fsid_type = FSID_UUID4_INUM;
|
||||
}
|
||||
} else if (exp->ex_flags & NFSEXP_FSID)
|
||||
fsid_type = FSID_NUM;
|
||||
else if (!old_valid_dev(ex_dev))
|
||||
} else if (!old_valid_dev(ex_dev))
|
||||
/* for newer device numbers, we must use a newer fsid format */
|
||||
fsid_type = FSID_ENCODE_DEV;
|
||||
else
|
||||
|
|
|
@ -622,6 +622,7 @@ nfserrno (int errno)
|
|||
{ nfserr_badname, -ESRCH },
|
||||
{ nfserr_io, -ETXTBSY },
|
||||
{ nfserr_notsupp, -EOPNOTSUPP },
|
||||
{ nfserr_toosmall, -ETOOSMALL },
|
||||
};
|
||||
int i;
|
||||
|
||||
|
|
|
@ -744,16 +744,44 @@ nfsd_close(struct file *filp)
|
|||
fput(filp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Sync a file
|
||||
* As this calls fsync (not fdatasync) there is no need for a write_inode
|
||||
* after it.
|
||||
*/
|
||||
static inline int nfsd_dosync(struct file *filp, struct dentry *dp,
|
||||
const struct file_operations *fop)
|
||||
{
|
||||
struct inode *inode = dp->d_inode;
|
||||
int (*fsync) (struct file *, struct dentry *, int);
|
||||
int err;
|
||||
|
||||
err = filemap_fdatawrite(inode->i_mapping);
|
||||
if (err == 0 && fop && (fsync = fop->fsync))
|
||||
err = fsync(filp, dp, 0);
|
||||
if (err == 0)
|
||||
err = filemap_fdatawait(inode->i_mapping);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
nfsd_sync(struct file *filp)
|
||||
{
|
||||
return vfs_fsync(filp, filp->f_path.dentry, 0);
|
||||
int err;
|
||||
struct inode *inode = filp->f_path.dentry->d_inode;
|
||||
dprintk("nfsd: sync file %s\n", filp->f_path.dentry->d_name.name);
|
||||
mutex_lock(&inode->i_mutex);
|
||||
err=nfsd_dosync(filp, filp->f_path.dentry, filp->f_op);
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int
|
||||
nfsd_sync_dir(struct dentry *dentry)
|
||||
nfsd_sync_dir(struct dentry *dp)
|
||||
{
|
||||
return vfs_fsync(NULL, dentry, 0);
|
||||
return nfsd_dosync(NULL, dp, dp->d_inode->i_fop);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -43,8 +43,8 @@ struct nlm_host {
|
|||
struct sockaddr_storage h_addr; /* peer address */
|
||||
size_t h_addrlen;
|
||||
struct sockaddr_storage h_srcaddr; /* our address (optional) */
|
||||
struct rpc_clnt * h_rpcclnt; /* RPC client to talk to peer */
|
||||
char * h_name; /* remote hostname */
|
||||
struct rpc_clnt *h_rpcclnt; /* RPC client to talk to peer */
|
||||
char *h_name; /* remote hostname */
|
||||
u32 h_version; /* interface version */
|
||||
unsigned short h_proto; /* transport proto */
|
||||
unsigned short h_reclaiming : 1,
|
||||
|
@ -64,21 +64,29 @@ struct nlm_host {
|
|||
spinlock_t h_lock;
|
||||
struct list_head h_granted; /* Locks in GRANTED state */
|
||||
struct list_head h_reclaim; /* Locks in RECLAIM state */
|
||||
struct nsm_handle * h_nsmhandle; /* NSM status handle */
|
||||
|
||||
char h_addrbuf[48], /* address eyecatchers */
|
||||
h_srcaddrbuf[48];
|
||||
struct nsm_handle *h_nsmhandle; /* NSM status handle */
|
||||
char *h_addrbuf; /* address eyecatcher */
|
||||
};
|
||||
|
||||
/*
|
||||
* The largest string sm_addrbuf should hold is a full-size IPv6 address
|
||||
* (no "::" anywhere) with a scope ID. The buffer size is computed to
|
||||
* hold eight groups of colon-separated four-hex-digit numbers, a
|
||||
* percent sign, a scope id (at most 32 bits, in decimal), and NUL.
|
||||
*/
|
||||
#define NSM_ADDRBUF ((8 * 4 + 7) + (1 + 10) + 1)
|
||||
|
||||
struct nsm_handle {
|
||||
struct list_head sm_link;
|
||||
atomic_t sm_count;
|
||||
char * sm_name;
|
||||
char *sm_mon_name;
|
||||
char *sm_name;
|
||||
struct sockaddr_storage sm_addr;
|
||||
size_t sm_addrlen;
|
||||
unsigned int sm_monitored : 1,
|
||||
sm_sticky : 1; /* don't unmonitor */
|
||||
char sm_addrbuf[48]; /* address eyecatcher */
|
||||
struct nsm_private sm_priv;
|
||||
char sm_addrbuf[NSM_ADDRBUF];
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -104,16 +112,6 @@ static inline struct sockaddr *nlm_srcaddr(const struct nlm_host *host)
|
|||
return (struct sockaddr *)&host->h_srcaddr;
|
||||
}
|
||||
|
||||
static inline struct sockaddr_in *nsm_addr_in(const struct nsm_handle *handle)
|
||||
{
|
||||
return (struct sockaddr_in *)&handle->sm_addr;
|
||||
}
|
||||
|
||||
static inline struct sockaddr *nsm_addr(const struct nsm_handle *handle)
|
||||
{
|
||||
return (struct sockaddr *)&handle->sm_addr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Map an fl_owner_t into a unique 32-bit "pid"
|
||||
*/
|
||||
|
@ -197,6 +195,7 @@ extern struct svc_procedure nlmsvc_procedures4[];
|
|||
extern int nlmsvc_grace_period;
|
||||
extern unsigned long nlmsvc_timeout;
|
||||
extern int nsm_use_hostnames;
|
||||
extern int nsm_local_state;
|
||||
|
||||
/*
|
||||
* Lockd client functions
|
||||
|
@ -231,10 +230,20 @@ void nlm_rebind_host(struct nlm_host *);
|
|||
struct nlm_host * nlm_get_host(struct nlm_host *);
|
||||
void nlm_release_host(struct nlm_host *);
|
||||
void nlm_shutdown_hosts(void);
|
||||
extern void nlm_host_rebooted(const struct sockaddr_in *, const char *,
|
||||
unsigned int, u32);
|
||||
void nsm_release(struct nsm_handle *);
|
||||
void nlm_host_rebooted(const struct nlm_reboot *);
|
||||
|
||||
/*
|
||||
* Host monitoring
|
||||
*/
|
||||
int nsm_monitor(const struct nlm_host *host);
|
||||
void nsm_unmonitor(const struct nlm_host *host);
|
||||
|
||||
struct nsm_handle *nsm_get_handle(const struct sockaddr *sap,
|
||||
const size_t salen,
|
||||
const char *hostname,
|
||||
const size_t hostname_len);
|
||||
struct nsm_handle *nsm_reboot_lookup(const struct nlm_reboot *info);
|
||||
void nsm_release(struct nsm_handle *nsm);
|
||||
|
||||
/*
|
||||
* This is used in garbage collection and resource reclaim
|
||||
|
@ -282,16 +291,25 @@ static inline struct inode *nlmsvc_file_inode(struct nlm_file *file)
|
|||
static inline int __nlm_privileged_request4(const struct sockaddr *sap)
|
||||
{
|
||||
const struct sockaddr_in *sin = (struct sockaddr_in *)sap;
|
||||
return (sin->sin_addr.s_addr == htonl(INADDR_LOOPBACK)) &&
|
||||
(ntohs(sin->sin_port) < 1024);
|
||||
|
||||
if (ntohs(sin->sin_port) > 1023)
|
||||
return 0;
|
||||
|
||||
return ipv4_is_loopback(sin->sin_addr.s_addr);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
|
||||
static inline int __nlm_privileged_request6(const struct sockaddr *sap)
|
||||
{
|
||||
const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
|
||||
return (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LOOPBACK) &&
|
||||
(ntohs(sin6->sin6_port) < 1024);
|
||||
|
||||
if (ntohs(sin6->sin6_port) > 1023)
|
||||
return 0;
|
||||
|
||||
if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_MAPPED)
|
||||
return ipv4_is_loopback(sin6->sin6_addr.s6_addr32[3]);
|
||||
|
||||
return ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LOOPBACK;
|
||||
}
|
||||
#else /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
|
||||
static inline int __nlm_privileged_request6(const struct sockaddr *sap)
|
||||
|
|
|
@ -1,48 +0,0 @@
|
|||
/*
|
||||
* linux/include/linux/lockd/sm_inter.h
|
||||
*
|
||||
* Declarations for the kernel statd client.
|
||||
*
|
||||
* Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
|
||||
*/
|
||||
|
||||
#ifndef LINUX_LOCKD_SM_INTER_H
|
||||
#define LINUX_LOCKD_SM_INTER_H
|
||||
|
||||
#define SM_PROGRAM 100024
|
||||
#define SM_VERSION 1
|
||||
#define SM_STAT 1
|
||||
#define SM_MON 2
|
||||
#define SM_UNMON 3
|
||||
#define SM_UNMON_ALL 4
|
||||
#define SM_SIMU_CRASH 5
|
||||
#define SM_NOTIFY 6
|
||||
|
||||
#define SM_MAXSTRLEN 1024
|
||||
#define SM_PRIV_SIZE 16
|
||||
|
||||
/*
|
||||
* Arguments for all calls to statd
|
||||
*/
|
||||
struct nsm_args {
|
||||
__be32 addr; /* remote address */
|
||||
u32 prog; /* RPC callback info */
|
||||
u32 vers;
|
||||
u32 proc;
|
||||
|
||||
char * mon_name;
|
||||
};
|
||||
|
||||
/*
|
||||
* Result returned by statd
|
||||
*/
|
||||
struct nsm_res {
|
||||
u32 status;
|
||||
u32 state;
|
||||
};
|
||||
|
||||
int nsm_monitor(struct nlm_host *);
|
||||
int nsm_unmonitor(struct nlm_host *);
|
||||
extern int nsm_local_state;
|
||||
|
||||
#endif /* LINUX_LOCKD_SM_INTER_H */
|
|
@ -13,6 +13,13 @@
|
|||
#include <linux/nfs.h>
|
||||
#include <linux/sunrpc/xdr.h>
|
||||
|
||||
#define SM_MAXSTRLEN 1024
|
||||
#define SM_PRIV_SIZE 16
|
||||
|
||||
struct nsm_private {
|
||||
unsigned char data[SM_PRIV_SIZE];
|
||||
};
|
||||
|
||||
struct svc_rqst;
|
||||
|
||||
#define NLM_MAXCOOKIELEN 32
|
||||
|
@ -77,10 +84,10 @@ struct nlm_res {
|
|||
* statd callback when client has rebooted
|
||||
*/
|
||||
struct nlm_reboot {
|
||||
char * mon;
|
||||
unsigned int len;
|
||||
u32 state;
|
||||
__be32 addr;
|
||||
char *mon;
|
||||
unsigned int len;
|
||||
u32 state;
|
||||
struct nsm_private priv;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -88,6 +88,8 @@
|
|||
#define NFS4_ACE_GENERIC_EXECUTE 0x001200A0
|
||||
#define NFS4_ACE_MASK_ALL 0x001F01FF
|
||||
|
||||
#define NFS4_MAX_UINT64 (~(u64)0)
|
||||
|
||||
enum nfs4_acl_whotype {
|
||||
NFS4_ACL_WHO_NAMED = 0,
|
||||
NFS4_ACL_WHO_OWNER,
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
/*
|
||||
* nfsd version
|
||||
*/
|
||||
#define NFSD_VERSION "0.5"
|
||||
#define NFSD_SUPPORTED_MINOR_VERSION 0
|
||||
|
||||
/*
|
||||
|
|
|
@ -68,6 +68,10 @@ struct nfs_fhbase_old {
|
|||
* 1 - 4 byte user specified identifier
|
||||
* 2 - 4 byte major, 4 byte minor, 4 byte inode number - DEPRECATED
|
||||
* 3 - 4 byte device id, encoded for user-space, 4 byte inode number
|
||||
* 4 - 4 byte inode number and 4 byte uuid
|
||||
* 5 - 8 byte uuid
|
||||
* 6 - 16 byte uuid
|
||||
* 7 - 8 byte inode number and 16 byte uuid
|
||||
*
|
||||
* The fileid_type identified how the file within the filesystem is encoded.
|
||||
* This is (will be) passed to, and set by, the underlying filesystem if it supports
|
||||
|
|
|
@ -58,10 +58,13 @@ struct svc_serv {
|
|||
struct svc_stat * sv_stats; /* RPC statistics */
|
||||
spinlock_t sv_lock;
|
||||
unsigned int sv_nrthreads; /* # of server threads */
|
||||
unsigned int sv_maxconn; /* max connections allowed or
|
||||
* '0' causing max to be based
|
||||
* on number of threads. */
|
||||
|
||||
unsigned int sv_max_payload; /* datagram payload size */
|
||||
unsigned int sv_max_mesg; /* max_payload + 1 page for overheads */
|
||||
unsigned int sv_xdrsize; /* XDR buffer size */
|
||||
|
||||
struct list_head sv_permsocks; /* all permanent sockets */
|
||||
struct list_head sv_tempsocks; /* all temporary sockets */
|
||||
int sv_tmpcnt; /* count of temporary sockets */
|
||||
|
|
|
@ -98,7 +98,7 @@ struct cache_head *sunrpc_cache_lookup(struct cache_detail *detail,
|
|||
|
||||
return new;
|
||||
}
|
||||
EXPORT_SYMBOL(sunrpc_cache_lookup);
|
||||
EXPORT_SYMBOL_GPL(sunrpc_cache_lookup);
|
||||
|
||||
|
||||
static void queue_loose(struct cache_detail *detail, struct cache_head *ch);
|
||||
|
@ -173,7 +173,7 @@ struct cache_head *sunrpc_cache_update(struct cache_detail *detail,
|
|||
cache_put(old, detail);
|
||||
return tmp;
|
||||
}
|
||||
EXPORT_SYMBOL(sunrpc_cache_update);
|
||||
EXPORT_SYMBOL_GPL(sunrpc_cache_update);
|
||||
|
||||
static int cache_make_upcall(struct cache_detail *detail, struct cache_head *h);
|
||||
/*
|
||||
|
@ -245,7 +245,7 @@ int cache_check(struct cache_detail *detail,
|
|||
cache_put(h, detail);
|
||||
return rv;
|
||||
}
|
||||
EXPORT_SYMBOL(cache_check);
|
||||
EXPORT_SYMBOL_GPL(cache_check);
|
||||
|
||||
/*
|
||||
* caches need to be periodically cleaned.
|
||||
|
@ -373,7 +373,7 @@ int cache_register(struct cache_detail *cd)
|
|||
schedule_delayed_work(&cache_cleaner, 0);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(cache_register);
|
||||
EXPORT_SYMBOL_GPL(cache_register);
|
||||
|
||||
void cache_unregister(struct cache_detail *cd)
|
||||
{
|
||||
|
@ -399,7 +399,7 @@ void cache_unregister(struct cache_detail *cd)
|
|||
out:
|
||||
printk(KERN_ERR "nfsd: failed to unregister %s cache\n", cd->name);
|
||||
}
|
||||
EXPORT_SYMBOL(cache_unregister);
|
||||
EXPORT_SYMBOL_GPL(cache_unregister);
|
||||
|
||||
/* clean cache tries to find something to clean
|
||||
* and cleans it.
|
||||
|
@ -514,7 +514,7 @@ void cache_flush(void)
|
|||
while (cache_clean() != -1)
|
||||
cond_resched();
|
||||
}
|
||||
EXPORT_SYMBOL(cache_flush);
|
||||
EXPORT_SYMBOL_GPL(cache_flush);
|
||||
|
||||
void cache_purge(struct cache_detail *detail)
|
||||
{
|
||||
|
@ -523,7 +523,7 @@ void cache_purge(struct cache_detail *detail)
|
|||
cache_flush();
|
||||
detail->flush_time = 1;
|
||||
}
|
||||
EXPORT_SYMBOL(cache_purge);
|
||||
EXPORT_SYMBOL_GPL(cache_purge);
|
||||
|
||||
|
||||
/*
|
||||
|
@ -988,7 +988,7 @@ void qword_add(char **bpp, int *lp, char *str)
|
|||
*bpp = bp;
|
||||
*lp = len;
|
||||
}
|
||||
EXPORT_SYMBOL(qword_add);
|
||||
EXPORT_SYMBOL_GPL(qword_add);
|
||||
|
||||
void qword_addhex(char **bpp, int *lp, char *buf, int blen)
|
||||
{
|
||||
|
@ -1017,7 +1017,7 @@ void qword_addhex(char **bpp, int *lp, char *buf, int blen)
|
|||
*bpp = bp;
|
||||
*lp = len;
|
||||
}
|
||||
EXPORT_SYMBOL(qword_addhex);
|
||||
EXPORT_SYMBOL_GPL(qword_addhex);
|
||||
|
||||
static void warn_no_listener(struct cache_detail *detail)
|
||||
{
|
||||
|
@ -1140,7 +1140,7 @@ int qword_get(char **bpp, char *dest, int bufsize)
|
|||
*dest = '\0';
|
||||
return len;
|
||||
}
|
||||
EXPORT_SYMBOL(qword_get);
|
||||
EXPORT_SYMBOL_GPL(qword_get);
|
||||
|
||||
|
||||
/*
|
||||
|
|
|
@ -106,7 +106,7 @@ void svc_seq_show(struct seq_file *seq, const struct svc_stat *statp) {
|
|||
seq_putc(seq, '\n');
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(svc_seq_show);
|
||||
EXPORT_SYMBOL_GPL(svc_seq_show);
|
||||
|
||||
/**
|
||||
* rpc_alloc_iostats - allocate an rpc_iostats structure
|
||||
|
@ -249,14 +249,14 @@ svc_proc_register(struct svc_stat *statp, const struct file_operations *fops)
|
|||
{
|
||||
return do_register(statp->program->pg_name, statp, fops);
|
||||
}
|
||||
EXPORT_SYMBOL(svc_proc_register);
|
||||
EXPORT_SYMBOL_GPL(svc_proc_register);
|
||||
|
||||
void
|
||||
svc_proc_unregister(const char *name)
|
||||
{
|
||||
remove_proc_entry(name, proc_net_rpc);
|
||||
}
|
||||
EXPORT_SYMBOL(svc_proc_unregister);
|
||||
EXPORT_SYMBOL_GPL(svc_proc_unregister);
|
||||
|
||||
void
|
||||
rpc_proc_init(void)
|
||||
|
|
|
@ -431,7 +431,7 @@ svc_create(struct svc_program *prog, unsigned int bufsize,
|
|||
{
|
||||
return __svc_create(prog, bufsize, /*npools*/1, family, shutdown);
|
||||
}
|
||||
EXPORT_SYMBOL(svc_create);
|
||||
EXPORT_SYMBOL_GPL(svc_create);
|
||||
|
||||
struct svc_serv *
|
||||
svc_create_pooled(struct svc_program *prog, unsigned int bufsize,
|
||||
|
@ -450,7 +450,7 @@ svc_create_pooled(struct svc_program *prog, unsigned int bufsize,
|
|||
|
||||
return serv;
|
||||
}
|
||||
EXPORT_SYMBOL(svc_create_pooled);
|
||||
EXPORT_SYMBOL_GPL(svc_create_pooled);
|
||||
|
||||
/*
|
||||
* Destroy an RPC service. Should be called with appropriate locking to
|
||||
|
@ -492,7 +492,7 @@ svc_destroy(struct svc_serv *serv)
|
|||
kfree(serv->sv_pools);
|
||||
kfree(serv);
|
||||
}
|
||||
EXPORT_SYMBOL(svc_destroy);
|
||||
EXPORT_SYMBOL_GPL(svc_destroy);
|
||||
|
||||
/*
|
||||
* Allocate an RPC server's buffer space.
|
||||
|
@ -567,7 +567,7 @@ out_thread:
|
|||
out_enomem:
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
EXPORT_SYMBOL(svc_prepare_thread);
|
||||
EXPORT_SYMBOL_GPL(svc_prepare_thread);
|
||||
|
||||
/*
|
||||
* Choose a pool in which to create a new thread, for svc_set_num_threads
|
||||
|
@ -689,7 +689,7 @@ svc_set_num_threads(struct svc_serv *serv, struct svc_pool *pool, int nrservs)
|
|||
|
||||
return error;
|
||||
}
|
||||
EXPORT_SYMBOL(svc_set_num_threads);
|
||||
EXPORT_SYMBOL_GPL(svc_set_num_threads);
|
||||
|
||||
/*
|
||||
* Called from a server thread as it's exiting. Caller must hold the BKL or
|
||||
|
@ -717,7 +717,7 @@ svc_exit_thread(struct svc_rqst *rqstp)
|
|||
if (serv)
|
||||
svc_destroy(serv);
|
||||
}
|
||||
EXPORT_SYMBOL(svc_exit_thread);
|
||||
EXPORT_SYMBOL_GPL(svc_exit_thread);
|
||||
|
||||
#ifdef CONFIG_SUNRPC_REGISTER_V4
|
||||
|
||||
|
@ -1231,7 +1231,7 @@ err_bad:
|
|||
svc_putnl(resv, ntohl(rpc_stat));
|
||||
goto sendit;
|
||||
}
|
||||
EXPORT_SYMBOL(svc_process);
|
||||
EXPORT_SYMBOL_GPL(svc_process);
|
||||
|
||||
/*
|
||||
* Return (transport-specific) limit on the rpc payload.
|
||||
|
|
|
@ -440,7 +440,7 @@ void svc_reserve(struct svc_rqst *rqstp, int space)
|
|||
svc_xprt_enqueue(xprt);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(svc_reserve);
|
||||
EXPORT_SYMBOL_GPL(svc_reserve);
|
||||
|
||||
static void svc_xprt_release(struct svc_rqst *rqstp)
|
||||
{
|
||||
|
@ -448,6 +448,9 @@ static void svc_xprt_release(struct svc_rqst *rqstp)
|
|||
|
||||
rqstp->rq_xprt->xpt_ops->xpo_release_rqst(rqstp);
|
||||
|
||||
kfree(rqstp->rq_deferred);
|
||||
rqstp->rq_deferred = NULL;
|
||||
|
||||
svc_free_res_pages(rqstp);
|
||||
rqstp->rq_res.page_len = 0;
|
||||
rqstp->rq_res.page_base = 0;
|
||||
|
@ -498,7 +501,7 @@ void svc_wake_up(struct svc_serv *serv)
|
|||
spin_unlock_bh(&pool->sp_lock);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(svc_wake_up);
|
||||
EXPORT_SYMBOL_GPL(svc_wake_up);
|
||||
|
||||
int svc_port_is_privileged(struct sockaddr *sin)
|
||||
{
|
||||
|
@ -515,8 +518,10 @@ int svc_port_is_privileged(struct sockaddr *sin)
|
|||
}
|
||||
|
||||
/*
|
||||
* Make sure that we don't have too many active connections. If we
|
||||
* have, something must be dropped.
|
||||
* Make sure that we don't have too many active connections. If we have,
|
||||
* something must be dropped. It's not clear what will happen if we allow
|
||||
* "too many" connections, but when dealing with network-facing software,
|
||||
* we have to code defensively. Here we do that by imposing hard limits.
|
||||
*
|
||||
* There's no point in trying to do random drop here for DoS
|
||||
* prevention. The NFS clients does 1 reconnect in 15 seconds. An
|
||||
|
@ -525,19 +530,27 @@ int svc_port_is_privileged(struct sockaddr *sin)
|
|||
* The only somewhat efficient mechanism would be if drop old
|
||||
* connections from the same IP first. But right now we don't even
|
||||
* record the client IP in svc_sock.
|
||||
*
|
||||
* single-threaded services that expect a lot of clients will probably
|
||||
* need to set sv_maxconn to override the default value which is based
|
||||
* on the number of threads
|
||||
*/
|
||||
static void svc_check_conn_limits(struct svc_serv *serv)
|
||||
{
|
||||
if (serv->sv_tmpcnt > (serv->sv_nrthreads+3)*20) {
|
||||
unsigned int limit = serv->sv_maxconn ? serv->sv_maxconn :
|
||||
(serv->sv_nrthreads+3) * 20;
|
||||
|
||||
if (serv->sv_tmpcnt > limit) {
|
||||
struct svc_xprt *xprt = NULL;
|
||||
spin_lock_bh(&serv->sv_lock);
|
||||
if (!list_empty(&serv->sv_tempsocks)) {
|
||||
if (net_ratelimit()) {
|
||||
/* Try to help the admin */
|
||||
printk(KERN_NOTICE "%s: too many open "
|
||||
"connections, consider increasing the "
|
||||
"number of nfsd threads\n",
|
||||
serv->sv_name);
|
||||
"connections, consider increasing %s\n",
|
||||
serv->sv_name, serv->sv_maxconn ?
|
||||
"the max number of connections." :
|
||||
"the number of threads.");
|
||||
}
|
||||
/*
|
||||
* Always select the oldest connection. It's not fair,
|
||||
|
@ -730,7 +743,7 @@ int svc_recv(struct svc_rqst *rqstp, long timeout)
|
|||
serv->sv_stats->netcnt++;
|
||||
return len;
|
||||
}
|
||||
EXPORT_SYMBOL(svc_recv);
|
||||
EXPORT_SYMBOL_GPL(svc_recv);
|
||||
|
||||
/*
|
||||
* Drop request
|
||||
|
@ -740,7 +753,7 @@ void svc_drop(struct svc_rqst *rqstp)
|
|||
dprintk("svc: xprt %p dropped request\n", rqstp->rq_xprt);
|
||||
svc_xprt_release(rqstp);
|
||||
}
|
||||
EXPORT_SYMBOL(svc_drop);
|
||||
EXPORT_SYMBOL_GPL(svc_drop);
|
||||
|
||||
/*
|
||||
* Return reply to client.
|
||||
|
@ -837,6 +850,11 @@ static void svc_age_temp_xprts(unsigned long closure)
|
|||
void svc_delete_xprt(struct svc_xprt *xprt)
|
||||
{
|
||||
struct svc_serv *serv = xprt->xpt_server;
|
||||
struct svc_deferred_req *dr;
|
||||
|
||||
/* Only do this once */
|
||||
if (test_and_set_bit(XPT_DEAD, &xprt->xpt_flags))
|
||||
return;
|
||||
|
||||
dprintk("svc: svc_delete_xprt(%p)\n", xprt);
|
||||
xprt->xpt_ops->xpo_detach(xprt);
|
||||
|
@ -851,12 +869,16 @@ void svc_delete_xprt(struct svc_xprt *xprt)
|
|||
* while still attached to a queue, the queue itself
|
||||
* is about to be destroyed (in svc_destroy).
|
||||
*/
|
||||
if (!test_and_set_bit(XPT_DEAD, &xprt->xpt_flags)) {
|
||||
BUG_ON(atomic_read(&xprt->xpt_ref.refcount) < 2);
|
||||
if (test_bit(XPT_TEMP, &xprt->xpt_flags))
|
||||
serv->sv_tmpcnt--;
|
||||
if (test_bit(XPT_TEMP, &xprt->xpt_flags))
|
||||
serv->sv_tmpcnt--;
|
||||
|
||||
for (dr = svc_deferred_dequeue(xprt); dr;
|
||||
dr = svc_deferred_dequeue(xprt)) {
|
||||
svc_xprt_put(xprt);
|
||||
kfree(dr);
|
||||
}
|
||||
|
||||
svc_xprt_put(xprt);
|
||||
spin_unlock_bh(&serv->sv_lock);
|
||||
}
|
||||
|
||||
|
@ -902,17 +924,19 @@ static void svc_revisit(struct cache_deferred_req *dreq, int too_many)
|
|||
container_of(dreq, struct svc_deferred_req, handle);
|
||||
struct svc_xprt *xprt = dr->xprt;
|
||||
|
||||
if (too_many) {
|
||||
spin_lock(&xprt->xpt_lock);
|
||||
set_bit(XPT_DEFERRED, &xprt->xpt_flags);
|
||||
if (too_many || test_bit(XPT_DEAD, &xprt->xpt_flags)) {
|
||||
spin_unlock(&xprt->xpt_lock);
|
||||
dprintk("revisit canceled\n");
|
||||
svc_xprt_put(xprt);
|
||||
kfree(dr);
|
||||
return;
|
||||
}
|
||||
dprintk("revisit queued\n");
|
||||
dr->xprt = NULL;
|
||||
spin_lock(&xprt->xpt_lock);
|
||||
list_add(&dr->handle.recent, &xprt->xpt_deferred);
|
||||
spin_unlock(&xprt->xpt_lock);
|
||||
set_bit(XPT_DEFERRED, &xprt->xpt_flags);
|
||||
svc_xprt_enqueue(xprt);
|
||||
svc_xprt_put(xprt);
|
||||
}
|
||||
|
|
|
@ -57,13 +57,13 @@ svc_authenticate(struct svc_rqst *rqstp, __be32 *authp)
|
|||
rqstp->rq_authop = aops;
|
||||
return aops->accept(rqstp, authp);
|
||||
}
|
||||
EXPORT_SYMBOL(svc_authenticate);
|
||||
EXPORT_SYMBOL_GPL(svc_authenticate);
|
||||
|
||||
int svc_set_client(struct svc_rqst *rqstp)
|
||||
{
|
||||
return rqstp->rq_authop->set_client(rqstp);
|
||||
}
|
||||
EXPORT_SYMBOL(svc_set_client);
|
||||
EXPORT_SYMBOL_GPL(svc_set_client);
|
||||
|
||||
/* A request, which was authenticated, has now executed.
|
||||
* Time to finalise the credentials and verifier
|
||||
|
@ -95,7 +95,7 @@ svc_auth_register(rpc_authflavor_t flavor, struct auth_ops *aops)
|
|||
spin_unlock(&authtab_lock);
|
||||
return rv;
|
||||
}
|
||||
EXPORT_SYMBOL(svc_auth_register);
|
||||
EXPORT_SYMBOL_GPL(svc_auth_register);
|
||||
|
||||
void
|
||||
svc_auth_unregister(rpc_authflavor_t flavor)
|
||||
|
@ -105,7 +105,7 @@ svc_auth_unregister(rpc_authflavor_t flavor)
|
|||
authtab[flavor] = NULL;
|
||||
spin_unlock(&authtab_lock);
|
||||
}
|
||||
EXPORT_SYMBOL(svc_auth_unregister);
|
||||
EXPORT_SYMBOL_GPL(svc_auth_unregister);
|
||||
|
||||
/**************************************************
|
||||
* 'auth_domains' are stored in a hash table indexed by name.
|
||||
|
@ -132,7 +132,7 @@ void auth_domain_put(struct auth_domain *dom)
|
|||
spin_unlock(&auth_domain_lock);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(auth_domain_put);
|
||||
EXPORT_SYMBOL_GPL(auth_domain_put);
|
||||
|
||||
struct auth_domain *
|
||||
auth_domain_lookup(char *name, struct auth_domain *new)
|
||||
|
@ -157,10 +157,10 @@ auth_domain_lookup(char *name, struct auth_domain *new)
|
|||
spin_unlock(&auth_domain_lock);
|
||||
return new;
|
||||
}
|
||||
EXPORT_SYMBOL(auth_domain_lookup);
|
||||
EXPORT_SYMBOL_GPL(auth_domain_lookup);
|
||||
|
||||
struct auth_domain *auth_domain_find(char *name)
|
||||
{
|
||||
return auth_domain_lookup(name, NULL);
|
||||
}
|
||||
EXPORT_SYMBOL(auth_domain_find);
|
||||
EXPORT_SYMBOL_GPL(auth_domain_find);
|
||||
|
|
|
@ -64,7 +64,7 @@ struct auth_domain *unix_domain_find(char *name)
|
|||
rv = auth_domain_lookup(name, &new->h);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(unix_domain_find);
|
||||
EXPORT_SYMBOL_GPL(unix_domain_find);
|
||||
|
||||
static void svcauth_unix_domain_release(struct auth_domain *dom)
|
||||
{
|
||||
|
@ -358,7 +358,7 @@ int auth_unix_add_addr(struct in6_addr *addr, struct auth_domain *dom)
|
|||
else
|
||||
return -ENOMEM;
|
||||
}
|
||||
EXPORT_SYMBOL(auth_unix_add_addr);
|
||||
EXPORT_SYMBOL_GPL(auth_unix_add_addr);
|
||||
|
||||
int auth_unix_forget_old(struct auth_domain *dom)
|
||||
{
|
||||
|
@ -370,7 +370,7 @@ int auth_unix_forget_old(struct auth_domain *dom)
|
|||
udom->addr_changes++;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(auth_unix_forget_old);
|
||||
EXPORT_SYMBOL_GPL(auth_unix_forget_old);
|
||||
|
||||
struct auth_domain *auth_unix_lookup(struct in6_addr *addr)
|
||||
{
|
||||
|
@ -395,13 +395,13 @@ struct auth_domain *auth_unix_lookup(struct in6_addr *addr)
|
|||
cache_put(&ipm->h, &ip_map_cache);
|
||||
return rv;
|
||||
}
|
||||
EXPORT_SYMBOL(auth_unix_lookup);
|
||||
EXPORT_SYMBOL_GPL(auth_unix_lookup);
|
||||
|
||||
void svcauth_unix_purge(void)
|
||||
{
|
||||
cache_purge(&ip_map_cache);
|
||||
}
|
||||
EXPORT_SYMBOL(svcauth_unix_purge);
|
||||
EXPORT_SYMBOL_GPL(svcauth_unix_purge);
|
||||
|
||||
static inline struct ip_map *
|
||||
ip_map_cached_get(struct svc_rqst *rqstp)
|
||||
|
@ -714,7 +714,7 @@ svcauth_unix_set_client(struct svc_rqst *rqstp)
|
|||
return SVC_OK;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(svcauth_unix_set_client);
|
||||
EXPORT_SYMBOL_GPL(svcauth_unix_set_client);
|
||||
|
||||
static int
|
||||
svcauth_null_accept(struct svc_rqst *rqstp, __be32 *authp)
|
||||
|
|
|
@ -59,6 +59,7 @@ static void svc_udp_data_ready(struct sock *, int);
|
|||
static int svc_udp_recvfrom(struct svc_rqst *);
|
||||
static int svc_udp_sendto(struct svc_rqst *);
|
||||
static void svc_sock_detach(struct svc_xprt *);
|
||||
static void svc_tcp_sock_detach(struct svc_xprt *);
|
||||
static void svc_sock_free(struct svc_xprt *);
|
||||
|
||||
static struct svc_xprt *svc_create_socket(struct svc_serv *, int,
|
||||
|
@ -102,7 +103,6 @@ static void svc_reclassify_socket(struct socket *sock)
|
|||
static void svc_release_skb(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct sk_buff *skb = rqstp->rq_xprt_ctxt;
|
||||
struct svc_deferred_req *dr = rqstp->rq_deferred;
|
||||
|
||||
if (skb) {
|
||||
struct svc_sock *svsk =
|
||||
|
@ -112,10 +112,6 @@ static void svc_release_skb(struct svc_rqst *rqstp)
|
|||
dprintk("svc: service %p, releasing skb %p\n", rqstp, skb);
|
||||
skb_free_datagram(svsk->sk_sk, skb);
|
||||
}
|
||||
if (dr) {
|
||||
rqstp->rq_deferred = NULL;
|
||||
kfree(dr);
|
||||
}
|
||||
}
|
||||
|
||||
union svc_pktinfo_u {
|
||||
|
@ -289,7 +285,7 @@ svc_sock_names(char *buf, struct svc_serv *serv, char *toclose)
|
|||
return -ENOENT;
|
||||
return len;
|
||||
}
|
||||
EXPORT_SYMBOL(svc_sock_names);
|
||||
EXPORT_SYMBOL_GPL(svc_sock_names);
|
||||
|
||||
/*
|
||||
* Check input queue length
|
||||
|
@ -1017,7 +1013,7 @@ static struct svc_xprt_ops svc_tcp_ops = {
|
|||
.xpo_recvfrom = svc_tcp_recvfrom,
|
||||
.xpo_sendto = svc_tcp_sendto,
|
||||
.xpo_release_rqst = svc_release_skb,
|
||||
.xpo_detach = svc_sock_detach,
|
||||
.xpo_detach = svc_tcp_sock_detach,
|
||||
.xpo_free = svc_sock_free,
|
||||
.xpo_prep_reply_hdr = svc_tcp_prep_reply_hdr,
|
||||
.xpo_has_wspace = svc_tcp_has_wspace,
|
||||
|
@ -1101,7 +1097,7 @@ void svc_sock_update_bufs(struct svc_serv *serv)
|
|||
}
|
||||
spin_unlock_bh(&serv->sv_lock);
|
||||
}
|
||||
EXPORT_SYMBOL(svc_sock_update_bufs);
|
||||
EXPORT_SYMBOL_GPL(svc_sock_update_bufs);
|
||||
|
||||
/*
|
||||
* Initialize socket for RPC use and create svc_sock struct
|
||||
|
@ -1287,6 +1283,24 @@ static void svc_sock_detach(struct svc_xprt *xprt)
|
|||
sk->sk_state_change = svsk->sk_ostate;
|
||||
sk->sk_data_ready = svsk->sk_odata;
|
||||
sk->sk_write_space = svsk->sk_owspace;
|
||||
|
||||
if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
|
||||
wake_up_interruptible(sk->sk_sleep);
|
||||
}
|
||||
|
||||
/*
|
||||
* Disconnect the socket, and reset the callbacks
|
||||
*/
|
||||
static void svc_tcp_sock_detach(struct svc_xprt *xprt)
|
||||
{
|
||||
struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt);
|
||||
|
||||
dprintk("svc: svc_tcp_sock_detach(%p)\n", svsk);
|
||||
|
||||
svc_sock_detach(xprt);
|
||||
|
||||
if (!test_bit(XPT_LISTENER, &xprt->xpt_flags))
|
||||
kernel_sock_shutdown(svsk->sk_sock, SHUT_RDWR);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in a new issue