Commit 713404d6 authored by Linus Torvalds's avatar Linus Torvalds

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
  ...
parents d599edca db43910c
......@@ -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;
......
......@@ -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);
}
}
......@@ -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
enum {
NSMPROC_NULL,
NSMPROC_STAT,
NSMPROC_MON,
NSMPROC_UNMON,
NSMPROC_UNMON_ALL,
NSMPROC_SIMU_CRASH,
NSMPROC_NOTIFY,
};
#define XDR_ADDRBUF_LEN (20)
struct nsm_args {
struct nsm_private *priv;
u32 prog; /* RPC callback info */
u32 vers;
u32 proc;
static struct rpc_clnt * nsm_create(void);
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,21 +134,17 @@ 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",
dprintk("lockd: NSM upcall RPC failed, status=%d\n",
status);
else
status = 0;
......@@ -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);
if (len > SM_MAXSTRLEN)
len = SM_MAXSTRLEN;
return xdr_encode_opaque(p, string, len);
const u32 len = strlen(string);
__be32 *p;
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;
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_mon(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);
p = xdr_encode_priv(p, argp);
if (IS_ERR(p))
return PTR_ERR(p);
struct xdr_stream xdr;
int status;
rqstp->rq_slen = xdr_adjust_iovec(rqstp->rq_svec, p);
return 0;
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_encode_unmon(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp)
static int xdr_enc_unmon(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;
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
return encode_mon_id(&xdr, argp);
}
static int
xdr_decode_stat_res(struct rpc_rqst *rqstp, __be32 *p, struct nsm_res *resp)
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,27 +230,21 @@ lockd(void *vrqstp)
static int make_socks(struct svc_serv *serv)
{
static int warned;
struct svc_xprt *xprt;
int err = 0;
int err;
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;
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)
return 0;
out_err:
if (warned++ == 0)
printk(KERN_WARNING
"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 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
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 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
#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 @@ alloc_init_lock_stateid(struct nfs4_stateowner *sop, struct nfs4_file *fp, struc
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 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
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);
/*
......
/*
* fs/nfs/nfs4xdr.c
*
* Server-side XDR for NFSv4
*
* Copyright (c) 2002 The Regents of the University of Michigan.
......
......@@ -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;
}
static ssize_t write_filehandle(struct file *file, char *buf, size_t size)
{
/* request is:
* domain path maxsize
* response is
* filehandle
/**
* write_filehandle - Get a variable-length NFS file handle by path
*
* qword quoting is used, so filehandle will be \x....
* 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)
{
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 @@ 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)
{
/*
* 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 @@ static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp)
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
*
* 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.
*
* Regardless of success or failure of fh_verify(), fh_put() should be
* called on @fhp when the caller is finished with the filehandle.
*
* Note that the file handle dentry may need to be freed even after
* an error return.
* 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.
*
* 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.
* @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)
......
/*
* 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;
char *mon;
unsigned int len;
u32 state;
__be32 addr;
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 @@ svc_prepare_thread(struct svc_serv *serv, struct svc_pool *pool)
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 @@ svc_process(struct svc_rqst *rqstp)
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--;
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);
}
/*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment