Merge branch 'for-2.6.28' of git://linux-nfs.org/~bfields/linux
* 'for-2.6.28' of git://linux-nfs.org/~bfields/linux: (59 commits) svcrdma: Fix IRD/ORD polarity svcrdma: Update svc_rdma_send_error to use DMA LKEY svcrdma: Modify the RPC reply path to use FRMR when available svcrdma: Modify the RPC recv path to use FRMR when available svcrdma: Add support to svc_rdma_send to handle chained WR svcrdma: Modify post recv path to use local dma key svcrdma: Add a service to register a Fast Reg MR with the device svcrdma: Query device for Fast Reg support during connection setup svcrdma: Add FRMR get/put services NLM: Remove unused argument from svc_addsock() function NLM: Remove "proto" argument from lockd_up() NLM: Always start both UDP and TCP listeners lockd: Remove unused fields in the nlm_reboot structure lockd: Add helper to sanity check incoming NOTIFY requests lockd: change nlmclnt_grant() to take a "struct sockaddr *" lockd: Adjust nlmsvc_lookup_host() to accomodate AF_INET6 addresses lockd: Adjust nlmclnt_lookup_host() signature to accomodate non-AF_INET lockd: Support non-AF_INET addresses in nlm_lookup_host() NLM: Convert nlm_lookup_host() to use a single argument svcrdma: Add Fast Reg MR Data Types ...
This commit is contained in:
commit
8acd3a60bc
30
fs/Kconfig
30
fs/Kconfig
|
@ -433,6 +433,14 @@ config FS_POSIX_ACL
|
||||||
bool
|
bool
|
||||||
default n
|
default n
|
||||||
|
|
||||||
|
config FILE_LOCKING
|
||||||
|
bool "Enable POSIX file locking API" if EMBEDDED
|
||||||
|
default y
|
||||||
|
help
|
||||||
|
This option enables standard file locking support, required
|
||||||
|
for filesystems like NFS and for the flock() system
|
||||||
|
call. Disabling this option saves about 11k.
|
||||||
|
|
||||||
source "fs/xfs/Kconfig"
|
source "fs/xfs/Kconfig"
|
||||||
source "fs/gfs2/Kconfig"
|
source "fs/gfs2/Kconfig"
|
||||||
|
|
||||||
|
@ -1779,6 +1787,28 @@ config SUNRPC_XPRT_RDMA
|
||||||
|
|
||||||
If unsure, say N.
|
If unsure, say N.
|
||||||
|
|
||||||
|
config SUNRPC_REGISTER_V4
|
||||||
|
bool "Register local RPC services via rpcbind v4 (EXPERIMENTAL)"
|
||||||
|
depends on SUNRPC && EXPERIMENTAL
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
Sun added support for registering RPC services at an IPv6
|
||||||
|
address by creating two new versions of the rpcbind protocol
|
||||||
|
(RFC 1833).
|
||||||
|
|
||||||
|
This option enables support in the kernel RPC server for
|
||||||
|
registering kernel RPC services via version 4 of the rpcbind
|
||||||
|
protocol. If you enable this option, you must run a portmapper
|
||||||
|
daemon that supports rpcbind protocol version 4.
|
||||||
|
|
||||||
|
Serving NFS over IPv6 from knfsd (the kernel's NFS server)
|
||||||
|
requires that you enable this option and use a portmapper that
|
||||||
|
supports rpcbind version 4.
|
||||||
|
|
||||||
|
If unsure, say N to get traditional behavior (register kernel
|
||||||
|
RPC services using only rpcbind version 2). Distributions
|
||||||
|
using the legacy Linux portmapper daemon must say N here.
|
||||||
|
|
||||||
config RPCSEC_GSS_KRB5
|
config RPCSEC_GSS_KRB5
|
||||||
tristate "Secure RPC: Kerberos V mechanism (EXPERIMENTAL)"
|
tristate "Secure RPC: Kerberos V mechanism (EXPERIMENTAL)"
|
||||||
depends on SUNRPC && EXPERIMENTAL
|
depends on SUNRPC && EXPERIMENTAL
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
obj-y := open.o read_write.o file_table.o super.o \
|
obj-y := open.o read_write.o file_table.o super.o \
|
||||||
char_dev.o stat.o exec.o pipe.o namei.o fcntl.o \
|
char_dev.o stat.o exec.o pipe.o namei.o fcntl.o \
|
||||||
ioctl.o readdir.o select.o fifo.o locks.o dcache.o inode.o \
|
ioctl.o readdir.o select.o fifo.o dcache.o inode.o \
|
||||||
attr.o bad_inode.o file.o filesystems.o namespace.o aio.o \
|
attr.o bad_inode.o file.o filesystems.o namespace.o aio.o \
|
||||||
seq_file.o xattr.o libfs.o fs-writeback.o \
|
seq_file.o xattr.o libfs.o fs-writeback.o \
|
||||||
pnode.o drop_caches.o splice.o sync.o utimes.o \
|
pnode.o drop_caches.o splice.o sync.o utimes.o \
|
||||||
|
@ -27,6 +27,7 @@ obj-$(CONFIG_ANON_INODES) += anon_inodes.o
|
||||||
obj-$(CONFIG_SIGNALFD) += signalfd.o
|
obj-$(CONFIG_SIGNALFD) += signalfd.o
|
||||||
obj-$(CONFIG_TIMERFD) += timerfd.o
|
obj-$(CONFIG_TIMERFD) += timerfd.o
|
||||||
obj-$(CONFIG_EVENTFD) += eventfd.o
|
obj-$(CONFIG_EVENTFD) += eventfd.o
|
||||||
|
obj-$(CONFIG_FILE_LOCKING) += locks.o
|
||||||
obj-$(CONFIG_COMPAT) += compat.o compat_ioctl.o
|
obj-$(CONFIG_COMPAT) += compat.o compat_ioctl.o
|
||||||
|
|
||||||
nfsd-$(CONFIG_NFSD) := nfsctl.o
|
nfsd-$(CONFIG_NFSD) := nfsctl.o
|
||||||
|
|
|
@ -5,6 +5,6 @@
|
||||||
obj-$(CONFIG_LOCKD) += lockd.o
|
obj-$(CONFIG_LOCKD) += lockd.o
|
||||||
|
|
||||||
lockd-objs-y := clntlock.o clntproc.o host.o svc.o svclock.o svcshare.o \
|
lockd-objs-y := clntlock.o clntproc.o host.o svc.o svclock.o svcshare.o \
|
||||||
svcproc.o svcsubs.o mon.o xdr.o
|
svcproc.o svcsubs.o mon.o xdr.o grace.o
|
||||||
lockd-objs-$(CONFIG_LOCKD_V4) += xdr4.o svc4proc.o
|
lockd-objs-$(CONFIG_LOCKD_V4) += xdr4.o svc4proc.o
|
||||||
lockd-objs := $(lockd-objs-y)
|
lockd-objs := $(lockd-objs-y)
|
||||||
|
|
|
@ -54,14 +54,13 @@ struct nlm_host *nlmclnt_init(const struct nlmclnt_initdata *nlm_init)
|
||||||
u32 nlm_version = (nlm_init->nfs_version == 2) ? 1 : 4;
|
u32 nlm_version = (nlm_init->nfs_version == 2) ? 1 : 4;
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
status = lockd_up(nlm_init->protocol);
|
status = lockd_up();
|
||||||
if (status < 0)
|
if (status < 0)
|
||||||
return ERR_PTR(status);
|
return ERR_PTR(status);
|
||||||
|
|
||||||
host = nlmclnt_lookup_host((struct sockaddr_in *)nlm_init->address,
|
host = nlmclnt_lookup_host(nlm_init->address, nlm_init->addrlen,
|
||||||
nlm_init->protocol, nlm_version,
|
nlm_init->protocol, nlm_version,
|
||||||
nlm_init->hostname,
|
nlm_init->hostname);
|
||||||
strlen(nlm_init->hostname));
|
|
||||||
if (host == NULL) {
|
if (host == NULL) {
|
||||||
lockd_down();
|
lockd_down();
|
||||||
return ERR_PTR(-ENOLCK);
|
return ERR_PTR(-ENOLCK);
|
||||||
|
@ -142,7 +141,7 @@ int nlmclnt_block(struct nlm_wait *block, struct nlm_rqst *req, long timeout)
|
||||||
/*
|
/*
|
||||||
* The server lockd has called us back to tell us the lock was granted
|
* The server lockd has called us back to tell us the lock was granted
|
||||||
*/
|
*/
|
||||||
__be32 nlmclnt_grant(const struct sockaddr_in *addr, const struct nlm_lock *lock)
|
__be32 nlmclnt_grant(const struct sockaddr *addr, const struct nlm_lock *lock)
|
||||||
{
|
{
|
||||||
const struct file_lock *fl = &lock->fl;
|
const struct file_lock *fl = &lock->fl;
|
||||||
const struct nfs_fh *fh = &lock->fh;
|
const struct nfs_fh *fh = &lock->fh;
|
||||||
|
@ -166,7 +165,7 @@ __be32 nlmclnt_grant(const struct sockaddr_in *addr, const struct nlm_lock *lock
|
||||||
*/
|
*/
|
||||||
if (fl_blocked->fl_u.nfs_fl.owner->pid != lock->svid)
|
if (fl_blocked->fl_u.nfs_fl.owner->pid != lock->svid)
|
||||||
continue;
|
continue;
|
||||||
if (!nlm_cmp_addr(&block->b_host->h_addr, addr))
|
if (!nlm_cmp_addr(nlm_addr(block->b_host), addr))
|
||||||
continue;
|
continue;
|
||||||
if (nfs_compare_fh(NFS_FH(fl_blocked->fl_file->f_path.dentry->d_inode) ,fh) != 0)
|
if (nfs_compare_fh(NFS_FH(fl_blocked->fl_file->f_path.dentry->d_inode) ,fh) != 0)
|
||||||
continue;
|
continue;
|
||||||
|
@ -216,7 +215,7 @@ reclaimer(void *ptr)
|
||||||
/* This one ensures that our parent doesn't terminate while the
|
/* This one ensures that our parent doesn't terminate while the
|
||||||
* reclaim is in progress */
|
* reclaim is in progress */
|
||||||
lock_kernel();
|
lock_kernel();
|
||||||
lockd_up(0); /* note: this cannot fail as lockd is already running */
|
lockd_up(); /* note: this cannot fail as lockd is already running */
|
||||||
|
|
||||||
dprintk("lockd: reclaiming locks for host %s\n", host->h_name);
|
dprintk("lockd: reclaiming locks for host %s\n", host->h_name);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
* Common code for control of lockd and nfsv4 grace periods.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/lockd/bind.h>
|
||||||
|
|
||||||
|
static LIST_HEAD(grace_list);
|
||||||
|
static DEFINE_SPINLOCK(grace_lock);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* locks_start_grace
|
||||||
|
* @lm: who this grace period is for
|
||||||
|
*
|
||||||
|
* A grace period is a period during which locks should not be given
|
||||||
|
* out. Currently grace periods are only enforced by the two lock
|
||||||
|
* managers (lockd and nfsd), using the locks_in_grace() function to
|
||||||
|
* check when they are in a grace period.
|
||||||
|
*
|
||||||
|
* This function is called to start a grace period.
|
||||||
|
*/
|
||||||
|
void locks_start_grace(struct lock_manager *lm)
|
||||||
|
{
|
||||||
|
spin_lock(&grace_lock);
|
||||||
|
list_add(&lm->list, &grace_list);
|
||||||
|
spin_unlock(&grace_lock);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(locks_start_grace);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* locks_end_grace
|
||||||
|
* @lm: who this grace period is for
|
||||||
|
*
|
||||||
|
* Call this function to state that the given lock manager is ready to
|
||||||
|
* resume regular locking. The grace period will not end until all lock
|
||||||
|
* managers that called locks_start_grace() also call locks_end_grace().
|
||||||
|
* Note that callers count on it being safe to call this more than once,
|
||||||
|
* and the second call should be a no-op.
|
||||||
|
*/
|
||||||
|
void locks_end_grace(struct lock_manager *lm)
|
||||||
|
{
|
||||||
|
spin_lock(&grace_lock);
|
||||||
|
list_del_init(&lm->list);
|
||||||
|
spin_unlock(&grace_lock);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(locks_end_grace);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* locks_in_grace
|
||||||
|
*
|
||||||
|
* Lock managers call this function to determine when it is OK for them
|
||||||
|
* to answer ordinary lock requests, and when they should accept only
|
||||||
|
* lock reclaims.
|
||||||
|
*/
|
||||||
|
int locks_in_grace(void)
|
||||||
|
{
|
||||||
|
return !list_empty(&grace_list);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(locks_in_grace);
|
342
fs/lockd/host.c
342
fs/lockd/host.c
|
@ -11,16 +11,17 @@
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/in.h>
|
#include <linux/in.h>
|
||||||
|
#include <linux/in6.h>
|
||||||
#include <linux/sunrpc/clnt.h>
|
#include <linux/sunrpc/clnt.h>
|
||||||
#include <linux/sunrpc/svc.h>
|
#include <linux/sunrpc/svc.h>
|
||||||
#include <linux/lockd/lockd.h>
|
#include <linux/lockd/lockd.h>
|
||||||
#include <linux/lockd/sm_inter.h>
|
#include <linux/lockd/sm_inter.h>
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
|
|
||||||
|
#include <net/ipv6.h>
|
||||||
|
|
||||||
#define NLMDBG_FACILITY NLMDBG_HOSTCACHE
|
#define NLMDBG_FACILITY NLMDBG_HOSTCACHE
|
||||||
#define NLM_HOST_NRHASH 32
|
#define NLM_HOST_NRHASH 32
|
||||||
#define NLM_ADDRHASH(addr) (ntohl(addr) & (NLM_HOST_NRHASH-1))
|
|
||||||
#define NLM_HOST_REBIND (60 * HZ)
|
#define NLM_HOST_REBIND (60 * HZ)
|
||||||
#define NLM_HOST_EXPIRE (300 * HZ)
|
#define NLM_HOST_EXPIRE (300 * HZ)
|
||||||
#define NLM_HOST_COLLECT (120 * HZ)
|
#define NLM_HOST_COLLECT (120 * HZ)
|
||||||
|
@ -30,42 +31,115 @@ static unsigned long next_gc;
|
||||||
static int nrhosts;
|
static int nrhosts;
|
||||||
static DEFINE_MUTEX(nlm_host_mutex);
|
static DEFINE_MUTEX(nlm_host_mutex);
|
||||||
|
|
||||||
|
|
||||||
static void nlm_gc_hosts(void);
|
static void nlm_gc_hosts(void);
|
||||||
static struct nsm_handle * __nsm_find(const struct sockaddr_in *,
|
static struct nsm_handle *nsm_find(const struct sockaddr *sap,
|
||||||
const char *, unsigned int, int);
|
const size_t salen,
|
||||||
static struct nsm_handle * nsm_find(const struct sockaddr_in *sin,
|
|
||||||
const char *hostname,
|
const char *hostname,
|
||||||
unsigned int hostname_len);
|
const size_t hostname_len,
|
||||||
|
const int create);
|
||||||
|
|
||||||
|
struct nlm_lookup_host_info {
|
||||||
|
const int server; /* search for server|client */
|
||||||
|
const struct sockaddr *sap; /* address to search for */
|
||||||
|
const size_t salen; /* it's length */
|
||||||
|
const unsigned short protocol; /* transport to search for*/
|
||||||
|
const u32 version; /* NLM version to search for */
|
||||||
|
const char *hostname; /* remote's hostname */
|
||||||
|
const size_t hostname_len; /* it's length */
|
||||||
|
const struct sockaddr *src_sap; /* our address (optional) */
|
||||||
|
const size_t src_len; /* it's length */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hash function must work well on big- and little-endian platforms
|
||||||
|
*/
|
||||||
|
static unsigned int __nlm_hash32(const __be32 n)
|
||||||
|
{
|
||||||
|
unsigned int hash = (__force u32)n ^ ((__force u32)n >> 16);
|
||||||
|
return hash ^ (hash >> 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int __nlm_hash_addr4(const struct sockaddr *sap)
|
||||||
|
{
|
||||||
|
const struct sockaddr_in *sin = (struct sockaddr_in *)sap;
|
||||||
|
return __nlm_hash32(sin->sin_addr.s_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int __nlm_hash_addr6(const struct sockaddr *sap)
|
||||||
|
{
|
||||||
|
const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
|
||||||
|
const struct in6_addr addr = sin6->sin6_addr;
|
||||||
|
return __nlm_hash32(addr.s6_addr32[0]) ^
|
||||||
|
__nlm_hash32(addr.s6_addr32[1]) ^
|
||||||
|
__nlm_hash32(addr.s6_addr32[2]) ^
|
||||||
|
__nlm_hash32(addr.s6_addr32[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int nlm_hash_address(const struct sockaddr *sap)
|
||||||
|
{
|
||||||
|
unsigned int hash;
|
||||||
|
|
||||||
|
switch (sap->sa_family) {
|
||||||
|
case AF_INET:
|
||||||
|
hash = __nlm_hash_addr4(sap);
|
||||||
|
break;
|
||||||
|
case AF_INET6:
|
||||||
|
hash = __nlm_hash_addr6(sap);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
hash = 0;
|
||||||
|
}
|
||||||
|
return hash & (NLM_HOST_NRHASH - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nlm_clear_port(struct sockaddr *sap)
|
||||||
|
{
|
||||||
|
switch (sap->sa_family) {
|
||||||
|
case AF_INET:
|
||||||
|
((struct sockaddr_in *)sap)->sin_port = 0;
|
||||||
|
break;
|
||||||
|
case AF_INET6:
|
||||||
|
((struct sockaddr_in6 *)sap)->sin6_port = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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, NIPQUAD_FMT, NIPQUAD(sin->sin_addr.s_addr));
|
||||||
|
break;
|
||||||
|
case AF_INET6:
|
||||||
|
if (ipv6_addr_v4mapped(&sin6->sin6_addr))
|
||||||
|
snprintf(buf, len, NIPQUAD_FMT,
|
||||||
|
NIPQUAD(sin6->sin6_addr.s6_addr32[3]));
|
||||||
|
else
|
||||||
|
snprintf(buf, len, NIP6_FMT, NIP6(sin6->sin6_addr));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
snprintf(buf, len, "unsupported address family");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Common host lookup routine for server & client
|
* Common host lookup routine for server & client
|
||||||
*/
|
*/
|
||||||
static struct nlm_host *nlm_lookup_host(int server,
|
static struct nlm_host *nlm_lookup_host(struct nlm_lookup_host_info *ni)
|
||||||
const struct sockaddr_in *sin,
|
|
||||||
int proto, u32 version,
|
|
||||||
const char *hostname,
|
|
||||||
unsigned int hostname_len,
|
|
||||||
const struct sockaddr_in *ssin)
|
|
||||||
{
|
{
|
||||||
struct hlist_head *chain;
|
struct hlist_head *chain;
|
||||||
struct hlist_node *pos;
|
struct hlist_node *pos;
|
||||||
struct nlm_host *host;
|
struct nlm_host *host;
|
||||||
struct nsm_handle *nsm = NULL;
|
struct nsm_handle *nsm = NULL;
|
||||||
int hash;
|
|
||||||
|
|
||||||
dprintk("lockd: nlm_lookup_host("NIPQUAD_FMT"->"NIPQUAD_FMT
|
|
||||||
", p=%d, v=%u, my role=%s, name=%.*s)\n",
|
|
||||||
NIPQUAD(ssin->sin_addr.s_addr),
|
|
||||||
NIPQUAD(sin->sin_addr.s_addr), proto, version,
|
|
||||||
server? "server" : "client",
|
|
||||||
hostname_len,
|
|
||||||
hostname? hostname : "<none>");
|
|
||||||
|
|
||||||
|
|
||||||
hash = NLM_ADDRHASH(sin->sin_addr.s_addr);
|
|
||||||
|
|
||||||
/* Lock hash table */
|
|
||||||
mutex_lock(&nlm_host_mutex);
|
mutex_lock(&nlm_host_mutex);
|
||||||
|
|
||||||
if (time_after_eq(jiffies, next_gc))
|
if (time_after_eq(jiffies, next_gc))
|
||||||
|
@ -78,22 +152,22 @@ static struct nlm_host *nlm_lookup_host(int server,
|
||||||
* different NLM rpc_clients into one single nlm_host object.
|
* different NLM rpc_clients into one single nlm_host object.
|
||||||
* This would allow us to have one nlm_host per address.
|
* This would allow us to have one nlm_host per address.
|
||||||
*/
|
*/
|
||||||
chain = &nlm_hosts[hash];
|
chain = &nlm_hosts[nlm_hash_address(ni->sap)];
|
||||||
hlist_for_each_entry(host, pos, chain, h_hash) {
|
hlist_for_each_entry(host, pos, chain, h_hash) {
|
||||||
if (!nlm_cmp_addr(&host->h_addr, sin))
|
if (!nlm_cmp_addr(nlm_addr(host), ni->sap))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* See if we have an NSM handle for this client */
|
/* See if we have an NSM handle for this client */
|
||||||
if (!nsm)
|
if (!nsm)
|
||||||
nsm = host->h_nsmhandle;
|
nsm = host->h_nsmhandle;
|
||||||
|
|
||||||
if (host->h_proto != proto)
|
if (host->h_proto != ni->protocol)
|
||||||
continue;
|
continue;
|
||||||
if (host->h_version != version)
|
if (host->h_version != ni->version)
|
||||||
continue;
|
continue;
|
||||||
if (host->h_server != server)
|
if (host->h_server != ni->server)
|
||||||
continue;
|
continue;
|
||||||
if (!nlm_cmp_addr(&host->h_saddr, ssin))
|
if (!nlm_cmp_addr(nlm_srcaddr(host), ni->src_sap))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Move to head of hash chain. */
|
/* Move to head of hash chain. */
|
||||||
|
@ -101,30 +175,41 @@ static struct nlm_host *nlm_lookup_host(int server,
|
||||||
hlist_add_head(&host->h_hash, chain);
|
hlist_add_head(&host->h_hash, chain);
|
||||||
|
|
||||||
nlm_get_host(host);
|
nlm_get_host(host);
|
||||||
|
dprintk("lockd: nlm_lookup_host found host %s (%s)\n",
|
||||||
|
host->h_name, host->h_addrbuf);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The host wasn't in our hash table. If we don't
|
||||||
|
* have an NSM handle for it yet, create one.
|
||||||
|
*/
|
||||||
if (nsm)
|
if (nsm)
|
||||||
atomic_inc(&nsm->sm_count);
|
atomic_inc(&nsm->sm_count);
|
||||||
|
else {
|
||||||
host = NULL;
|
host = NULL;
|
||||||
|
nsm = nsm_find(ni->sap, ni->salen,
|
||||||
/* Sadly, the host isn't in our hash table yet. See if
|
ni->hostname, ni->hostname_len, 1);
|
||||||
* we have an NSM handle for it. If not, create one.
|
if (!nsm) {
|
||||||
*/
|
dprintk("lockd: nlm_lookup_host failed; "
|
||||||
if (!nsm && !(nsm = nsm_find(sin, hostname, hostname_len)))
|
"no nsm handle\n");
|
||||||
goto out;
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
host = kzalloc(sizeof(*host), GFP_KERNEL);
|
host = kzalloc(sizeof(*host), GFP_KERNEL);
|
||||||
if (!host) {
|
if (!host) {
|
||||||
nsm_release(nsm);
|
nsm_release(nsm);
|
||||||
|
dprintk("lockd: nlm_lookup_host failed; no memory\n");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
host->h_name = nsm->sm_name;
|
host->h_name = nsm->sm_name;
|
||||||
host->h_addr = *sin;
|
memcpy(nlm_addr(host), ni->sap, ni->salen);
|
||||||
host->h_addr.sin_port = 0; /* ouch! */
|
host->h_addrlen = ni->salen;
|
||||||
host->h_saddr = *ssin;
|
nlm_clear_port(nlm_addr(host));
|
||||||
host->h_version = version;
|
memcpy(nlm_srcaddr(host), ni->src_sap, ni->src_len);
|
||||||
host->h_proto = proto;
|
host->h_version = ni->version;
|
||||||
|
host->h_proto = ni->protocol;
|
||||||
host->h_rpcclnt = NULL;
|
host->h_rpcclnt = NULL;
|
||||||
mutex_init(&host->h_mutex);
|
mutex_init(&host->h_mutex);
|
||||||
host->h_nextrebind = jiffies + NLM_HOST_REBIND;
|
host->h_nextrebind = jiffies + NLM_HOST_REBIND;
|
||||||
|
@ -135,7 +220,7 @@ static struct nlm_host *nlm_lookup_host(int server,
|
||||||
host->h_state = 0; /* pseudo NSM state */
|
host->h_state = 0; /* pseudo NSM state */
|
||||||
host->h_nsmstate = 0; /* real NSM state */
|
host->h_nsmstate = 0; /* real NSM state */
|
||||||
host->h_nsmhandle = nsm;
|
host->h_nsmhandle = nsm;
|
||||||
host->h_server = server;
|
host->h_server = ni->server;
|
||||||
hlist_add_head(&host->h_hash, chain);
|
hlist_add_head(&host->h_hash, chain);
|
||||||
INIT_LIST_HEAD(&host->h_lockowners);
|
INIT_LIST_HEAD(&host->h_lockowners);
|
||||||
spin_lock_init(&host->h_lock);
|
spin_lock_init(&host->h_lock);
|
||||||
|
@ -143,6 +228,15 @@ static struct nlm_host *nlm_lookup_host(int server,
|
||||||
INIT_LIST_HEAD(&host->h_reclaim);
|
INIT_LIST_HEAD(&host->h_reclaim);
|
||||||
|
|
||||||
nrhosts++;
|
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);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
mutex_unlock(&nlm_host_mutex);
|
mutex_unlock(&nlm_host_mutex);
|
||||||
return host;
|
return host;
|
||||||
|
@ -170,33 +264,103 @@ nlm_destroy_host(struct nlm_host *host)
|
||||||
kfree(host);
|
kfree(host);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Find an NLM server handle in the cache. If there is none, create it.
|
* nlmclnt_lookup_host - Find an NLM host handle matching a remote server
|
||||||
|
* @sap: network address of server
|
||||||
|
* @salen: length of server address
|
||||||
|
* @protocol: transport protocol to use
|
||||||
|
* @version: NLM protocol version
|
||||||
|
* @hostname: '\0'-terminated hostname of server
|
||||||
|
*
|
||||||
|
* Returns an nlm_host structure that matches the passed-in
|
||||||
|
* [server address, transport protocol, NLM version, server hostname].
|
||||||
|
* If one doesn't already exist in the host cache, a new handle is
|
||||||
|
* created and returned.
|
||||||
*/
|
*/
|
||||||
struct nlm_host *nlmclnt_lookup_host(const struct sockaddr_in *sin,
|
struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap,
|
||||||
int proto, u32 version,
|
const size_t salen,
|
||||||
const char *hostname,
|
const unsigned short protocol,
|
||||||
unsigned int hostname_len)
|
const u32 version, const char *hostname)
|
||||||
{
|
{
|
||||||
struct sockaddr_in ssin = {0};
|
const struct sockaddr source = {
|
||||||
|
.sa_family = AF_UNSPEC,
|
||||||
|
};
|
||||||
|
struct nlm_lookup_host_info ni = {
|
||||||
|
.server = 0,
|
||||||
|
.sap = sap,
|
||||||
|
.salen = salen,
|
||||||
|
.protocol = protocol,
|
||||||
|
.version = version,
|
||||||
|
.hostname = hostname,
|
||||||
|
.hostname_len = strlen(hostname),
|
||||||
|
.src_sap = &source,
|
||||||
|
.src_len = sizeof(source),
|
||||||
|
};
|
||||||
|
|
||||||
return nlm_lookup_host(0, sin, proto, version,
|
dprintk("lockd: %s(host='%s', vers=%u, proto=%s)\n", __func__,
|
||||||
hostname, hostname_len, &ssin);
|
(hostname ? hostname : "<none>"), version,
|
||||||
|
(protocol == IPPROTO_UDP ? "udp" : "tcp"));
|
||||||
|
|
||||||
|
return nlm_lookup_host(&ni);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Find an NLM client handle in the cache. If there is none, create it.
|
* nlmsvc_lookup_host - Find an NLM host handle matching a remote client
|
||||||
|
* @rqstp: incoming NLM request
|
||||||
|
* @hostname: name of client host
|
||||||
|
* @hostname_len: length of client hostname
|
||||||
|
*
|
||||||
|
* Returns an nlm_host structure that matches the [client address,
|
||||||
|
* transport protocol, NLM version, client hostname] of the passed-in
|
||||||
|
* NLM request. If one doesn't already exist in the host cache, a
|
||||||
|
* new handle is created and returned.
|
||||||
|
*
|
||||||
|
* Before possibly creating a new nlm_host, construct a sockaddr
|
||||||
|
* for a specific source address in case the local system has
|
||||||
|
* multiple network addresses. The family of the address in
|
||||||
|
* rq_daddr is guaranteed to be the same as the family of the
|
||||||
|
* address in rq_addr, so it's safe to use the same family for
|
||||||
|
* the source address.
|
||||||
*/
|
*/
|
||||||
struct nlm_host *
|
struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp,
|
||||||
nlmsvc_lookup_host(struct svc_rqst *rqstp,
|
const char *hostname,
|
||||||
const char *hostname, unsigned int hostname_len)
|
const size_t hostname_len)
|
||||||
{
|
{
|
||||||
struct sockaddr_in ssin = {0};
|
struct sockaddr_in sin = {
|
||||||
|
.sin_family = AF_INET,
|
||||||
|
};
|
||||||
|
struct sockaddr_in6 sin6 = {
|
||||||
|
.sin6_family = AF_INET6,
|
||||||
|
};
|
||||||
|
struct nlm_lookup_host_info ni = {
|
||||||
|
.server = 1,
|
||||||
|
.sap = svc_addr(rqstp),
|
||||||
|
.salen = rqstp->rq_addrlen,
|
||||||
|
.protocol = rqstp->rq_prot,
|
||||||
|
.version = rqstp->rq_vers,
|
||||||
|
.hostname = hostname,
|
||||||
|
.hostname_len = hostname_len,
|
||||||
|
.src_len = rqstp->rq_addrlen,
|
||||||
|
};
|
||||||
|
|
||||||
ssin.sin_addr = rqstp->rq_daddr.addr;
|
dprintk("lockd: %s(host='%*s', vers=%u, proto=%s)\n", __func__,
|
||||||
return nlm_lookup_host(1, svc_addr_in(rqstp),
|
(int)hostname_len, hostname, rqstp->rq_vers,
|
||||||
rqstp->rq_prot, rqstp->rq_vers,
|
(rqstp->rq_prot == IPPROTO_UDP ? "udp" : "tcp"));
|
||||||
hostname, hostname_len, &ssin);
|
|
||||||
|
switch (ni.sap->sa_family) {
|
||||||
|
case AF_INET:
|
||||||
|
sin.sin_addr.s_addr = rqstp->rq_daddr.addr.s_addr;
|
||||||
|
ni.src_sap = (struct sockaddr *)&sin;
|
||||||
|
break;
|
||||||
|
case AF_INET6:
|
||||||
|
ipv6_addr_copy(&sin6.sin6_addr, &rqstp->rq_daddr.addr6);
|
||||||
|
ni.src_sap = (struct sockaddr *)&sin6;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nlm_lookup_host(&ni);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -207,9 +371,8 @@ nlm_bind_host(struct nlm_host *host)
|
||||||
{
|
{
|
||||||
struct rpc_clnt *clnt;
|
struct rpc_clnt *clnt;
|
||||||
|
|
||||||
dprintk("lockd: nlm_bind_host("NIPQUAD_FMT"->"NIPQUAD_FMT")\n",
|
dprintk("lockd: nlm_bind_host %s (%s), my addr=%s\n",
|
||||||
NIPQUAD(host->h_saddr.sin_addr),
|
host->h_name, host->h_addrbuf, host->h_srcaddrbuf);
|
||||||
NIPQUAD(host->h_addr.sin_addr));
|
|
||||||
|
|
||||||
/* Lock host handle */
|
/* Lock host handle */
|
||||||
mutex_lock(&host->h_mutex);
|
mutex_lock(&host->h_mutex);
|
||||||
|
@ -221,7 +384,7 @@ nlm_bind_host(struct nlm_host *host)
|
||||||
if (time_after_eq(jiffies, host->h_nextrebind)) {
|
if (time_after_eq(jiffies, host->h_nextrebind)) {
|
||||||
rpc_force_rebind(clnt);
|
rpc_force_rebind(clnt);
|
||||||
host->h_nextrebind = jiffies + NLM_HOST_REBIND;
|
host->h_nextrebind = jiffies + NLM_HOST_REBIND;
|
||||||
dprintk("lockd: next rebind in %ld jiffies\n",
|
dprintk("lockd: next rebind in %lu jiffies\n",
|
||||||
host->h_nextrebind - jiffies);
|
host->h_nextrebind - jiffies);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -234,9 +397,9 @@ nlm_bind_host(struct nlm_host *host)
|
||||||
};
|
};
|
||||||
struct rpc_create_args args = {
|
struct rpc_create_args args = {
|
||||||
.protocol = host->h_proto,
|
.protocol = host->h_proto,
|
||||||
.address = (struct sockaddr *)&host->h_addr,
|
.address = nlm_addr(host),
|
||||||
.addrsize = sizeof(host->h_addr),
|
.addrsize = host->h_addrlen,
|
||||||
.saddress = (struct sockaddr *)&host->h_saddr,
|
.saddress = nlm_srcaddr(host),
|
||||||
.timeout = &timeparms,
|
.timeout = &timeparms,
|
||||||
.servername = host->h_name,
|
.servername = host->h_name,
|
||||||
.program = &nlm_program,
|
.program = &nlm_program,
|
||||||
|
@ -324,12 +487,16 @@ void nlm_host_rebooted(const struct sockaddr_in *sin,
|
||||||
struct nsm_handle *nsm;
|
struct nsm_handle *nsm;
|
||||||
struct nlm_host *host;
|
struct nlm_host *host;
|
||||||
|
|
||||||
dprintk("lockd: nlm_host_rebooted(%s, %u.%u.%u.%u)\n",
|
nsm = nsm_find((struct sockaddr *)sin, sizeof(*sin),
|
||||||
hostname, NIPQUAD(sin->sin_addr));
|
hostname, hostname_len, 0);
|
||||||
|
if (nsm == NULL) {
|
||||||
/* Find the NSM handle for this peer */
|
dprintk("lockd: never saw rebooted peer '%.*s' before\n",
|
||||||
if (!(nsm = __nsm_find(sin, hostname, hostname_len, 0)))
|
hostname_len, hostname);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dprintk("lockd: nlm_host_rebooted(%.*s, %s)\n",
|
||||||
|
hostname_len, hostname, nsm->sm_addrbuf);
|
||||||
|
|
||||||
/* When reclaiming locks on this peer, make sure that
|
/* When reclaiming locks on this peer, make sure that
|
||||||
* we set up a new notification */
|
* we set up a new notification */
|
||||||
|
@ -461,22 +628,23 @@ nlm_gc_hosts(void)
|
||||||
static LIST_HEAD(nsm_handles);
|
static LIST_HEAD(nsm_handles);
|
||||||
static DEFINE_SPINLOCK(nsm_lock);
|
static DEFINE_SPINLOCK(nsm_lock);
|
||||||
|
|
||||||
static struct nsm_handle *
|
static struct nsm_handle *nsm_find(const struct sockaddr *sap,
|
||||||
__nsm_find(const struct sockaddr_in *sin,
|
const size_t salen,
|
||||||
const char *hostname, unsigned int hostname_len,
|
const char *hostname,
|
||||||
int create)
|
const size_t hostname_len,
|
||||||
|
const int create)
|
||||||
{
|
{
|
||||||
struct nsm_handle *nsm = NULL;
|
struct nsm_handle *nsm = NULL;
|
||||||
struct nsm_handle *pos;
|
struct nsm_handle *pos;
|
||||||
|
|
||||||
if (!sin)
|
if (!sap)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (hostname && memchr(hostname, '/', hostname_len) != NULL) {
|
if (hostname && memchr(hostname, '/', hostname_len) != NULL) {
|
||||||
if (printk_ratelimit()) {
|
if (printk_ratelimit()) {
|
||||||
printk(KERN_WARNING "Invalid hostname \"%.*s\" "
|
printk(KERN_WARNING "Invalid hostname \"%.*s\" "
|
||||||
"in NFS lock request\n",
|
"in NFS lock request\n",
|
||||||
hostname_len, hostname);
|
(int)hostname_len, hostname);
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -489,7 +657,7 @@ retry:
|
||||||
if (strlen(pos->sm_name) != hostname_len
|
if (strlen(pos->sm_name) != hostname_len
|
||||||
|| memcmp(pos->sm_name, hostname, hostname_len))
|
|| memcmp(pos->sm_name, hostname, hostname_len))
|
||||||
continue;
|
continue;
|
||||||
} else if (!nlm_cmp_addr(&pos->sm_addr, sin))
|
} else if (!nlm_cmp_addr(nsm_addr(pos), sap))
|
||||||
continue;
|
continue;
|
||||||
atomic_inc(&pos->sm_count);
|
atomic_inc(&pos->sm_count);
|
||||||
kfree(nsm);
|
kfree(nsm);
|
||||||
|
@ -509,10 +677,13 @@ retry:
|
||||||
if (nsm == NULL)
|
if (nsm == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
nsm->sm_addr = *sin;
|
memcpy(nsm_addr(nsm), sap, salen);
|
||||||
|
nsm->sm_addrlen = salen;
|
||||||
nsm->sm_name = (char *) (nsm + 1);
|
nsm->sm_name = (char *) (nsm + 1);
|
||||||
memcpy(nsm->sm_name, hostname, hostname_len);
|
memcpy(nsm->sm_name, hostname, hostname_len);
|
||||||
nsm->sm_name[hostname_len] = '\0';
|
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);
|
atomic_set(&nsm->sm_count, 1);
|
||||||
goto retry;
|
goto retry;
|
||||||
|
|
||||||
|
@ -521,13 +692,6 @@ found:
|
||||||
return nsm;
|
return nsm;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct nsm_handle *
|
|
||||||
nsm_find(const struct sockaddr_in *sin, const char *hostname,
|
|
||||||
unsigned int hostname_len)
|
|
||||||
{
|
|
||||||
return __nsm_find(sin, hostname, hostname_len, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Release an NSM handle
|
* Release an NSM handle
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -51,7 +51,7 @@ nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res)
|
||||||
|
|
||||||
memset(&args, 0, sizeof(args));
|
memset(&args, 0, sizeof(args));
|
||||||
args.mon_name = nsm->sm_name;
|
args.mon_name = nsm->sm_name;
|
||||||
args.addr = nsm->sm_addr.sin_addr.s_addr;
|
args.addr = nsm_addr_in(nsm)->sin_addr.s_addr;
|
||||||
args.prog = NLM_PROGRAM;
|
args.prog = NLM_PROGRAM;
|
||||||
args.vers = 3;
|
args.vers = 3;
|
||||||
args.proc = NLMPROC_NSM_NOTIFY;
|
args.proc = NLMPROC_NSM_NOTIFY;
|
||||||
|
|
|
@ -51,7 +51,6 @@ static DEFINE_MUTEX(nlmsvc_mutex);
|
||||||
static unsigned int nlmsvc_users;
|
static unsigned int nlmsvc_users;
|
||||||
static struct task_struct *nlmsvc_task;
|
static struct task_struct *nlmsvc_task;
|
||||||
static struct svc_rqst *nlmsvc_rqst;
|
static struct svc_rqst *nlmsvc_rqst;
|
||||||
int nlmsvc_grace_period;
|
|
||||||
unsigned long nlmsvc_timeout;
|
unsigned long nlmsvc_timeout;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -85,27 +84,23 @@ static unsigned long get_lockd_grace_period(void)
|
||||||
return nlm_timeout * 5 * HZ;
|
return nlm_timeout * 5 * HZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long get_nfs_grace_period(void)
|
static struct lock_manager lockd_manager = {
|
||||||
|
};
|
||||||
|
|
||||||
|
static void grace_ender(struct work_struct *not_used)
|
||||||
{
|
{
|
||||||
unsigned long lockdgrace = get_lockd_grace_period();
|
locks_end_grace(&lockd_manager);
|
||||||
unsigned long nfsdgrace = 0;
|
|
||||||
|
|
||||||
if (nlmsvc_ops)
|
|
||||||
nfsdgrace = nlmsvc_ops->get_grace_period();
|
|
||||||
|
|
||||||
return max(lockdgrace, nfsdgrace);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(get_nfs_grace_period);
|
|
||||||
|
|
||||||
static unsigned long set_grace_period(void)
|
|
||||||
{
|
|
||||||
nlmsvc_grace_period = 1;
|
|
||||||
return get_nfs_grace_period() + jiffies;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void clear_grace_period(void)
|
static DECLARE_DELAYED_WORK(grace_period_end, grace_ender);
|
||||||
|
|
||||||
|
static void set_grace_period(void)
|
||||||
{
|
{
|
||||||
nlmsvc_grace_period = 0;
|
unsigned long grace_period = get_lockd_grace_period();
|
||||||
|
|
||||||
|
locks_start_grace(&lockd_manager);
|
||||||
|
cancel_delayed_work_sync(&grace_period_end);
|
||||||
|
schedule_delayed_work(&grace_period_end, grace_period);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -116,7 +111,6 @@ lockd(void *vrqstp)
|
||||||
{
|
{
|
||||||
int err = 0, preverr = 0;
|
int err = 0, preverr = 0;
|
||||||
struct svc_rqst *rqstp = vrqstp;
|
struct svc_rqst *rqstp = vrqstp;
|
||||||
unsigned long grace_period_expire;
|
|
||||||
|
|
||||||
/* try_to_freeze() is called from svc_recv() */
|
/* try_to_freeze() is called from svc_recv() */
|
||||||
set_freezable();
|
set_freezable();
|
||||||
|
@ -139,7 +133,7 @@ lockd(void *vrqstp)
|
||||||
nlm_timeout = LOCKD_DFLT_TIMEO;
|
nlm_timeout = LOCKD_DFLT_TIMEO;
|
||||||
nlmsvc_timeout = nlm_timeout * HZ;
|
nlmsvc_timeout = nlm_timeout * HZ;
|
||||||
|
|
||||||
grace_period_expire = set_grace_period();
|
set_grace_period();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The main request loop. We don't terminate until the last
|
* The main request loop. We don't terminate until the last
|
||||||
|
@ -153,21 +147,12 @@ lockd(void *vrqstp)
|
||||||
flush_signals(current);
|
flush_signals(current);
|
||||||
if (nlmsvc_ops) {
|
if (nlmsvc_ops) {
|
||||||
nlmsvc_invalidate_all();
|
nlmsvc_invalidate_all();
|
||||||
grace_period_expire = set_grace_period();
|
set_grace_period();
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Retry any blocked locks that have been notified by
|
|
||||||
* the VFS. Don't do this during grace period.
|
|
||||||
* (Theoretically, there shouldn't even be blocked locks
|
|
||||||
* during grace period).
|
|
||||||
*/
|
|
||||||
if (!nlmsvc_grace_period) {
|
|
||||||
timeout = nlmsvc_retry_blocked();
|
timeout = nlmsvc_retry_blocked();
|
||||||
} else if (time_before(grace_period_expire, jiffies))
|
|
||||||
clear_grace_period();
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find a socket with data available and call its
|
* Find a socket with data available and call its
|
||||||
|
@ -195,6 +180,7 @@ lockd(void *vrqstp)
|
||||||
svc_process(rqstp);
|
svc_process(rqstp);
|
||||||
}
|
}
|
||||||
flush_signals(current);
|
flush_signals(current);
|
||||||
|
cancel_delayed_work_sync(&grace_period_end);
|
||||||
if (nlmsvc_ops)
|
if (nlmsvc_ops)
|
||||||
nlmsvc_invalidate_all();
|
nlmsvc_invalidate_all();
|
||||||
nlm_shutdown_hosts();
|
nlm_shutdown_hosts();
|
||||||
|
@ -203,25 +189,28 @@ lockd(void *vrqstp)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make any sockets that are needed but not present.
|
* Ensure there are active UDP and TCP listeners for lockd.
|
||||||
* If nlm_udpport or nlm_tcpport were set as module
|
*
|
||||||
* options, make those sockets unconditionally
|
* Even if we have only TCP NFS mounts and/or TCP NFSDs, some
|
||||||
|
* local services (such as rpc.statd) still require UDP, and
|
||||||
|
* some NFS servers do not yet support NLM over TCP.
|
||||||
|
*
|
||||||
|
* Returns zero if all listeners are available; otherwise a
|
||||||
|
* negative errno value is returned.
|
||||||
*/
|
*/
|
||||||
static int make_socks(struct svc_serv *serv, int proto)
|
static int make_socks(struct svc_serv *serv)
|
||||||
{
|
{
|
||||||
static int warned;
|
static int warned;
|
||||||
struct svc_xprt *xprt;
|
struct svc_xprt *xprt;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
if (proto == IPPROTO_UDP || nlm_udpport) {
|
|
||||||
xprt = svc_find_xprt(serv, "udp", 0, 0);
|
xprt = svc_find_xprt(serv, "udp", 0, 0);
|
||||||
if (!xprt)
|
if (!xprt)
|
||||||
err = svc_create_xprt(serv, "udp", nlm_udpport,
|
err = svc_create_xprt(serv, "udp", nlm_udpport,
|
||||||
SVC_SOCK_DEFAULTS);
|
SVC_SOCK_DEFAULTS);
|
||||||
else
|
else
|
||||||
svc_xprt_put(xprt);
|
svc_xprt_put(xprt);
|
||||||
}
|
if (err >= 0) {
|
||||||
if (err >= 0 && (proto == IPPROTO_TCP || nlm_tcpport)) {
|
|
||||||
xprt = svc_find_xprt(serv, "tcp", 0, 0);
|
xprt = svc_find_xprt(serv, "tcp", 0, 0);
|
||||||
if (!xprt)
|
if (!xprt)
|
||||||
err = svc_create_xprt(serv, "tcp", nlm_tcpport,
|
err = svc_create_xprt(serv, "tcp", nlm_tcpport,
|
||||||
|
@ -241,8 +230,7 @@ static int make_socks(struct svc_serv *serv, int proto)
|
||||||
/*
|
/*
|
||||||
* Bring up the lockd process if it's not already up.
|
* Bring up the lockd process if it's not already up.
|
||||||
*/
|
*/
|
||||||
int
|
int lockd_up(void)
|
||||||
lockd_up(int proto) /* Maybe add a 'family' option when IPv6 is supported ?? */
|
|
||||||
{
|
{
|
||||||
struct svc_serv *serv;
|
struct svc_serv *serv;
|
||||||
int error = 0;
|
int error = 0;
|
||||||
|
@ -251,11 +239,8 @@ lockd_up(int proto) /* Maybe add a 'family' option when IPv6 is supported ?? */
|
||||||
/*
|
/*
|
||||||
* Check whether we're already up and running.
|
* Check whether we're already up and running.
|
||||||
*/
|
*/
|
||||||
if (nlmsvc_rqst) {
|
if (nlmsvc_rqst)
|
||||||
if (proto)
|
|
||||||
error = make_socks(nlmsvc_rqst->rq_server, proto);
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Sanity check: if there's no pid,
|
* Sanity check: if there's no pid,
|
||||||
|
@ -266,13 +251,14 @@ lockd_up(int proto) /* Maybe add a 'family' option when IPv6 is supported ?? */
|
||||||
"lockd_up: no pid, %d users??\n", nlmsvc_users);
|
"lockd_up: no pid, %d users??\n", nlmsvc_users);
|
||||||
|
|
||||||
error = -ENOMEM;
|
error = -ENOMEM;
|
||||||
serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE, NULL);
|
serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE, AF_INET, NULL);
|
||||||
if (!serv) {
|
if (!serv) {
|
||||||
printk(KERN_WARNING "lockd_up: create service failed\n");
|
printk(KERN_WARNING "lockd_up: create service failed\n");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((error = make_socks(serv, proto)) < 0)
|
error = make_socks(serv);
|
||||||
|
if (error < 0)
|
||||||
goto destroy_and_out;
|
goto destroy_and_out;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -88,12 +88,6 @@ nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
|
||||||
dprintk("lockd: TEST4 called\n");
|
dprintk("lockd: TEST4 called\n");
|
||||||
resp->cookie = argp->cookie;
|
resp->cookie = argp->cookie;
|
||||||
|
|
||||||
/* Don't accept test requests during grace period */
|
|
||||||
if (nlmsvc_grace_period) {
|
|
||||||
resp->status = nlm_lck_denied_grace_period;
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Obtain client and file */
|
/* Obtain client and file */
|
||||||
if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
|
if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
|
||||||
return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
|
return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
|
||||||
|
@ -122,12 +116,6 @@ nlm4svc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
|
||||||
|
|
||||||
resp->cookie = argp->cookie;
|
resp->cookie = argp->cookie;
|
||||||
|
|
||||||
/* Don't accept new lock requests during grace period */
|
|
||||||
if (nlmsvc_grace_period && !argp->reclaim) {
|
|
||||||
resp->status = nlm_lck_denied_grace_period;
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Obtain client and file */
|
/* Obtain client and file */
|
||||||
if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
|
if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
|
||||||
return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
|
return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
|
||||||
|
@ -146,7 +134,8 @@ nlm4svc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
|
||||||
|
|
||||||
/* Now try to lock the file */
|
/* Now try to lock the file */
|
||||||
resp->status = nlmsvc_lock(rqstp, file, host, &argp->lock,
|
resp->status = nlmsvc_lock(rqstp, file, host, &argp->lock,
|
||||||
argp->block, &argp->cookie);
|
argp->block, &argp->cookie,
|
||||||
|
argp->reclaim);
|
||||||
if (resp->status == nlm_drop_reply)
|
if (resp->status == nlm_drop_reply)
|
||||||
rc = rpc_drop_reply;
|
rc = rpc_drop_reply;
|
||||||
else
|
else
|
||||||
|
@ -169,7 +158,7 @@ nlm4svc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp,
|
||||||
resp->cookie = argp->cookie;
|
resp->cookie = argp->cookie;
|
||||||
|
|
||||||
/* Don't accept requests during grace period */
|
/* Don't accept requests during grace period */
|
||||||
if (nlmsvc_grace_period) {
|
if (locks_in_grace()) {
|
||||||
resp->status = nlm_lck_denied_grace_period;
|
resp->status = nlm_lck_denied_grace_period;
|
||||||
return rpc_success;
|
return rpc_success;
|
||||||
}
|
}
|
||||||
|
@ -202,7 +191,7 @@ nlm4svc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp,
|
||||||
resp->cookie = argp->cookie;
|
resp->cookie = argp->cookie;
|
||||||
|
|
||||||
/* Don't accept new lock requests during grace period */
|
/* Don't accept new lock requests during grace period */
|
||||||
if (nlmsvc_grace_period) {
|
if (locks_in_grace()) {
|
||||||
resp->status = nlm_lck_denied_grace_period;
|
resp->status = nlm_lck_denied_grace_period;
|
||||||
return rpc_success;
|
return rpc_success;
|
||||||
}
|
}
|
||||||
|
@ -231,7 +220,7 @@ nlm4svc_proc_granted(struct svc_rqst *rqstp, struct nlm_args *argp,
|
||||||
resp->cookie = argp->cookie;
|
resp->cookie = argp->cookie;
|
||||||
|
|
||||||
dprintk("lockd: GRANTED called\n");
|
dprintk("lockd: GRANTED called\n");
|
||||||
resp->status = nlmclnt_grant(svc_addr_in(rqstp), &argp->lock);
|
resp->status = nlmclnt_grant(svc_addr(rqstp), &argp->lock);
|
||||||
dprintk("lockd: GRANTED status %d\n", ntohl(resp->status));
|
dprintk("lockd: GRANTED status %d\n", ntohl(resp->status));
|
||||||
return rpc_success;
|
return rpc_success;
|
||||||
}
|
}
|
||||||
|
@ -341,7 +330,7 @@ nlm4svc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp,
|
||||||
resp->cookie = argp->cookie;
|
resp->cookie = argp->cookie;
|
||||||
|
|
||||||
/* Don't accept new lock requests during grace period */
|
/* Don't accept new lock requests during grace period */
|
||||||
if (nlmsvc_grace_period && !argp->reclaim) {
|
if (locks_in_grace() && !argp->reclaim) {
|
||||||
resp->status = nlm_lck_denied_grace_period;
|
resp->status = nlm_lck_denied_grace_period;
|
||||||
return rpc_success;
|
return rpc_success;
|
||||||
}
|
}
|
||||||
|
@ -374,7 +363,7 @@ nlm4svc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp,
|
||||||
resp->cookie = argp->cookie;
|
resp->cookie = argp->cookie;
|
||||||
|
|
||||||
/* Don't accept requests during grace period */
|
/* Don't accept requests during grace period */
|
||||||
if (nlmsvc_grace_period) {
|
if (locks_in_grace()) {
|
||||||
resp->status = nlm_lck_denied_grace_period;
|
resp->status = nlm_lck_denied_grace_period;
|
||||||
return rpc_success;
|
return rpc_success;
|
||||||
}
|
}
|
||||||
|
@ -432,11 +421,9 @@ nlm4svc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
|
||||||
{
|
{
|
||||||
struct sockaddr_in saddr;
|
struct sockaddr_in saddr;
|
||||||
|
|
||||||
memcpy(&saddr, svc_addr_in(rqstp), sizeof(saddr));
|
|
||||||
|
|
||||||
dprintk("lockd: SM_NOTIFY called\n");
|
dprintk("lockd: SM_NOTIFY called\n");
|
||||||
if (saddr.sin_addr.s_addr != htonl(INADDR_LOOPBACK)
|
|
||||||
|| ntohs(saddr.sin_port) >= 1024) {
|
if (!nlm_privileged_requester(rqstp)) {
|
||||||
char buf[RPC_MAX_ADDRBUFLEN];
|
char buf[RPC_MAX_ADDRBUFLEN];
|
||||||
printk(KERN_WARNING "lockd: rejected NSM callback from %s\n",
|
printk(KERN_WARNING "lockd: rejected NSM callback from %s\n",
|
||||||
svc_print_addr(rqstp, buf, sizeof(buf)));
|
svc_print_addr(rqstp, buf, sizeof(buf)));
|
||||||
|
|
|
@ -360,7 +360,7 @@ nlmsvc_defer_lock_rqst(struct svc_rqst *rqstp, struct nlm_block *block)
|
||||||
__be32
|
__be32
|
||||||
nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
|
nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
|
||||||
struct nlm_host *host, struct nlm_lock *lock, int wait,
|
struct nlm_host *host, struct nlm_lock *lock, int wait,
|
||||||
struct nlm_cookie *cookie)
|
struct nlm_cookie *cookie, int reclaim)
|
||||||
{
|
{
|
||||||
struct nlm_block *block = NULL;
|
struct nlm_block *block = NULL;
|
||||||
int error;
|
int error;
|
||||||
|
@ -406,6 +406,15 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (locks_in_grace() && !reclaim) {
|
||||||
|
ret = nlm_lck_denied_grace_period;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (reclaim && !locks_in_grace()) {
|
||||||
|
ret = nlm_lck_denied_grace_period;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
if (!wait)
|
if (!wait)
|
||||||
lock->fl.fl_flags &= ~FL_SLEEP;
|
lock->fl.fl_flags &= ~FL_SLEEP;
|
||||||
error = vfs_lock_file(file->f_file, F_SETLK, &lock->fl, NULL);
|
error = vfs_lock_file(file->f_file, F_SETLK, &lock->fl, NULL);
|
||||||
|
@ -502,6 +511,10 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (locks_in_grace()) {
|
||||||
|
ret = nlm_lck_denied_grace_period;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
error = vfs_test_lock(file->f_file, &lock->fl);
|
error = vfs_test_lock(file->f_file, &lock->fl);
|
||||||
if (error == FILE_LOCK_DEFERRED) {
|
if (error == FILE_LOCK_DEFERRED) {
|
||||||
ret = nlmsvc_defer_lock_rqst(rqstp, block);
|
ret = nlmsvc_defer_lock_rqst(rqstp, block);
|
||||||
|
@ -582,6 +595,9 @@ nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock)
|
||||||
(long long)lock->fl.fl_start,
|
(long long)lock->fl.fl_start,
|
||||||
(long long)lock->fl.fl_end);
|
(long long)lock->fl.fl_end);
|
||||||
|
|
||||||
|
if (locks_in_grace())
|
||||||
|
return nlm_lck_denied_grace_period;
|
||||||
|
|
||||||
mutex_lock(&file->f_mutex);
|
mutex_lock(&file->f_mutex);
|
||||||
block = nlmsvc_lookup_block(file, lock);
|
block = nlmsvc_lookup_block(file, lock);
|
||||||
mutex_unlock(&file->f_mutex);
|
mutex_unlock(&file->f_mutex);
|
||||||
|
|
|
@ -117,12 +117,6 @@ nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
|
||||||
dprintk("lockd: TEST called\n");
|
dprintk("lockd: TEST called\n");
|
||||||
resp->cookie = argp->cookie;
|
resp->cookie = argp->cookie;
|
||||||
|
|
||||||
/* Don't accept test requests during grace period */
|
|
||||||
if (nlmsvc_grace_period) {
|
|
||||||
resp->status = nlm_lck_denied_grace_period;
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Obtain client and file */
|
/* Obtain client and file */
|
||||||
if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
|
if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
|
||||||
return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
|
return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
|
||||||
|
@ -152,12 +146,6 @@ nlmsvc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
|
||||||
|
|
||||||
resp->cookie = argp->cookie;
|
resp->cookie = argp->cookie;
|
||||||
|
|
||||||
/* Don't accept new lock requests during grace period */
|
|
||||||
if (nlmsvc_grace_period && !argp->reclaim) {
|
|
||||||
resp->status = nlm_lck_denied_grace_period;
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Obtain client and file */
|
/* Obtain client and file */
|
||||||
if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
|
if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
|
||||||
return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
|
return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
|
||||||
|
@ -176,7 +164,8 @@ nlmsvc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
|
||||||
|
|
||||||
/* Now try to lock the file */
|
/* Now try to lock the file */
|
||||||
resp->status = cast_status(nlmsvc_lock(rqstp, file, host, &argp->lock,
|
resp->status = cast_status(nlmsvc_lock(rqstp, file, host, &argp->lock,
|
||||||
argp->block, &argp->cookie));
|
argp->block, &argp->cookie,
|
||||||
|
argp->reclaim));
|
||||||
if (resp->status == nlm_drop_reply)
|
if (resp->status == nlm_drop_reply)
|
||||||
rc = rpc_drop_reply;
|
rc = rpc_drop_reply;
|
||||||
else
|
else
|
||||||
|
@ -199,7 +188,7 @@ nlmsvc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp,
|
||||||
resp->cookie = argp->cookie;
|
resp->cookie = argp->cookie;
|
||||||
|
|
||||||
/* Don't accept requests during grace period */
|
/* Don't accept requests during grace period */
|
||||||
if (nlmsvc_grace_period) {
|
if (locks_in_grace()) {
|
||||||
resp->status = nlm_lck_denied_grace_period;
|
resp->status = nlm_lck_denied_grace_period;
|
||||||
return rpc_success;
|
return rpc_success;
|
||||||
}
|
}
|
||||||
|
@ -232,7 +221,7 @@ nlmsvc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp,
|
||||||
resp->cookie = argp->cookie;
|
resp->cookie = argp->cookie;
|
||||||
|
|
||||||
/* Don't accept new lock requests during grace period */
|
/* Don't accept new lock requests during grace period */
|
||||||
if (nlmsvc_grace_period) {
|
if (locks_in_grace()) {
|
||||||
resp->status = nlm_lck_denied_grace_period;
|
resp->status = nlm_lck_denied_grace_period;
|
||||||
return rpc_success;
|
return rpc_success;
|
||||||
}
|
}
|
||||||
|
@ -261,7 +250,7 @@ nlmsvc_proc_granted(struct svc_rqst *rqstp, struct nlm_args *argp,
|
||||||
resp->cookie = argp->cookie;
|
resp->cookie = argp->cookie;
|
||||||
|
|
||||||
dprintk("lockd: GRANTED called\n");
|
dprintk("lockd: GRANTED called\n");
|
||||||
resp->status = nlmclnt_grant(svc_addr_in(rqstp), &argp->lock);
|
resp->status = nlmclnt_grant(svc_addr(rqstp), &argp->lock);
|
||||||
dprintk("lockd: GRANTED status %d\n", ntohl(resp->status));
|
dprintk("lockd: GRANTED status %d\n", ntohl(resp->status));
|
||||||
return rpc_success;
|
return rpc_success;
|
||||||
}
|
}
|
||||||
|
@ -373,7 +362,7 @@ nlmsvc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp,
|
||||||
resp->cookie = argp->cookie;
|
resp->cookie = argp->cookie;
|
||||||
|
|
||||||
/* Don't accept new lock requests during grace period */
|
/* Don't accept new lock requests during grace period */
|
||||||
if (nlmsvc_grace_period && !argp->reclaim) {
|
if (locks_in_grace() && !argp->reclaim) {
|
||||||
resp->status = nlm_lck_denied_grace_period;
|
resp->status = nlm_lck_denied_grace_period;
|
||||||
return rpc_success;
|
return rpc_success;
|
||||||
}
|
}
|
||||||
|
@ -406,7 +395,7 @@ nlmsvc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp,
|
||||||
resp->cookie = argp->cookie;
|
resp->cookie = argp->cookie;
|
||||||
|
|
||||||
/* Don't accept requests during grace period */
|
/* Don't accept requests during grace period */
|
||||||
if (nlmsvc_grace_period) {
|
if (locks_in_grace()) {
|
||||||
resp->status = nlm_lck_denied_grace_period;
|
resp->status = nlm_lck_denied_grace_period;
|
||||||
return rpc_success;
|
return rpc_success;
|
||||||
}
|
}
|
||||||
|
@ -464,11 +453,9 @@ nlmsvc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
|
||||||
{
|
{
|
||||||
struct sockaddr_in saddr;
|
struct sockaddr_in saddr;
|
||||||
|
|
||||||
memcpy(&saddr, svc_addr_in(rqstp), sizeof(saddr));
|
|
||||||
|
|
||||||
dprintk("lockd: SM_NOTIFY called\n");
|
dprintk("lockd: SM_NOTIFY called\n");
|
||||||
if (saddr.sin_addr.s_addr != htonl(INADDR_LOOPBACK)
|
|
||||||
|| ntohs(saddr.sin_port) >= 1024) {
|
if (!nlm_privileged_requester(rqstp)) {
|
||||||
char buf[RPC_MAX_ADDRBUFLEN];
|
char buf[RPC_MAX_ADDRBUFLEN];
|
||||||
printk(KERN_WARNING "lockd: rejected NSM callback from %s\n",
|
printk(KERN_WARNING "lockd: rejected NSM callback from %s\n",
|
||||||
svc_print_addr(rqstp, buf, sizeof(buf)));
|
svc_print_addr(rqstp, buf, sizeof(buf)));
|
||||||
|
|
|
@ -418,7 +418,7 @@ EXPORT_SYMBOL_GPL(nlmsvc_unlock_all_by_sb);
|
||||||
static int
|
static int
|
||||||
nlmsvc_match_ip(void *datap, struct nlm_host *host)
|
nlmsvc_match_ip(void *datap, struct nlm_host *host)
|
||||||
{
|
{
|
||||||
return nlm_cmp_addr(&host->h_saddr, datap);
|
return nlm_cmp_addr(nlm_srcaddr(host), datap);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -351,8 +351,6 @@ nlmsvc_decode_reboot(struct svc_rqst *rqstp, __be32 *p, struct nlm_reboot *argp)
|
||||||
argp->state = ntohl(*p++);
|
argp->state = ntohl(*p++);
|
||||||
/* Preserve the address in network byte order */
|
/* Preserve the address in network byte order */
|
||||||
argp->addr = *p++;
|
argp->addr = *p++;
|
||||||
argp->vers = *p++;
|
|
||||||
argp->proto = *p++;
|
|
||||||
return xdr_argsize_check(rqstp, p);
|
return xdr_argsize_check(rqstp, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -358,8 +358,6 @@ nlm4svc_decode_reboot(struct svc_rqst *rqstp, __be32 *p, struct nlm_reboot *argp
|
||||||
argp->state = ntohl(*p++);
|
argp->state = ntohl(*p++);
|
||||||
/* Preserve the address in network byte order */
|
/* Preserve the address in network byte order */
|
||||||
argp->addr = *p++;
|
argp->addr = *p++;
|
||||||
argp->vers = *p++;
|
|
||||||
argp->proto = *p++;
|
|
||||||
return xdr_argsize_check(rqstp, p);
|
return xdr_argsize_check(rqstp, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -105,7 +105,8 @@ int nfs_callback_up(void)
|
||||||
mutex_lock(&nfs_callback_mutex);
|
mutex_lock(&nfs_callback_mutex);
|
||||||
if (nfs_callback_info.users++ || nfs_callback_info.task != NULL)
|
if (nfs_callback_info.users++ || nfs_callback_info.task != NULL)
|
||||||
goto out;
|
goto out;
|
||||||
serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, NULL);
|
serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE,
|
||||||
|
AF_INET, NULL);
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
if (!serv)
|
if (!serv)
|
||||||
goto out_err;
|
goto out_err;
|
||||||
|
|
|
@ -70,7 +70,6 @@ nlm_fclose(struct file *filp)
|
||||||
static struct nlmsvc_binding nfsd_nlm_ops = {
|
static struct nlmsvc_binding nfsd_nlm_ops = {
|
||||||
.fopen = nlm_fopen, /* open file for locking */
|
.fopen = nlm_fopen, /* open file for locking */
|
||||||
.fclose = nlm_fclose, /* close file */
|
.fclose = nlm_fclose, /* close file */
|
||||||
.get_grace_period = get_nfs4_grace_period,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -63,7 +63,8 @@ nfsd3_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle *argp,
|
||||||
SVCFH_fmt(&argp->fh));
|
SVCFH_fmt(&argp->fh));
|
||||||
|
|
||||||
fh_copy(&resp->fh, &argp->fh);
|
fh_copy(&resp->fh, &argp->fh);
|
||||||
nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP);
|
nfserr = fh_verify(rqstp, &resp->fh, 0,
|
||||||
|
NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT);
|
||||||
if (nfserr)
|
if (nfserr)
|
||||||
RETURN_STATUS(nfserr);
|
RETURN_STATUS(nfserr);
|
||||||
|
|
||||||
|
@ -530,7 +531,7 @@ nfsd3_proc_fsstat(struct svc_rqst * rqstp, struct nfsd_fhandle *argp,
|
||||||
dprintk("nfsd: FSSTAT(3) %s\n",
|
dprintk("nfsd: FSSTAT(3) %s\n",
|
||||||
SVCFH_fmt(&argp->fh));
|
SVCFH_fmt(&argp->fh));
|
||||||
|
|
||||||
nfserr = nfsd_statfs(rqstp, &argp->fh, &resp->stats);
|
nfserr = nfsd_statfs(rqstp, &argp->fh, &resp->stats, 0);
|
||||||
fh_put(&argp->fh);
|
fh_put(&argp->fh);
|
||||||
RETURN_STATUS(nfserr);
|
RETURN_STATUS(nfserr);
|
||||||
}
|
}
|
||||||
|
@ -558,7 +559,8 @@ nfsd3_proc_fsinfo(struct svc_rqst * rqstp, struct nfsd_fhandle *argp,
|
||||||
resp->f_maxfilesize = ~(u32) 0;
|
resp->f_maxfilesize = ~(u32) 0;
|
||||||
resp->f_properties = NFS3_FSF_DEFAULT;
|
resp->f_properties = NFS3_FSF_DEFAULT;
|
||||||
|
|
||||||
nfserr = fh_verify(rqstp, &argp->fh, 0, NFSD_MAY_NOP);
|
nfserr = fh_verify(rqstp, &argp->fh, 0,
|
||||||
|
NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT);
|
||||||
|
|
||||||
/* Check special features of the file system. May request
|
/* Check special features of the file system. May request
|
||||||
* different read/write sizes for file systems known to have
|
* different read/write sizes for file systems known to have
|
||||||
|
|
|
@ -225,7 +225,8 @@ encode_cb_recall(struct xdr_stream *xdr, struct nfs4_cb_recall *cb_rec)
|
||||||
|
|
||||||
RESERVE_SPACE(12+sizeof(cb_rec->cbr_stateid) + len);
|
RESERVE_SPACE(12+sizeof(cb_rec->cbr_stateid) + len);
|
||||||
WRITE32(OP_CB_RECALL);
|
WRITE32(OP_CB_RECALL);
|
||||||
WRITEMEM(&cb_rec->cbr_stateid, sizeof(stateid_t));
|
WRITE32(cb_rec->cbr_stateid.si_generation);
|
||||||
|
WRITEMEM(&cb_rec->cbr_stateid.si_opaque, sizeof(stateid_opaque_t));
|
||||||
WRITE32(cb_rec->cbr_trunc);
|
WRITE32(cb_rec->cbr_trunc);
|
||||||
WRITE32(len);
|
WRITE32(len);
|
||||||
WRITEMEM(cb_rec->cbr_fhval, len);
|
WRITEMEM(cb_rec->cbr_fhval, len);
|
||||||
|
@ -379,6 +380,7 @@ static int do_probe_callback(void *data)
|
||||||
.addrsize = sizeof(addr),
|
.addrsize = sizeof(addr),
|
||||||
.timeout = &timeparms,
|
.timeout = &timeparms,
|
||||||
.program = &cb_program,
|
.program = &cb_program,
|
||||||
|
.prognumber = cb->cb_prog,
|
||||||
.version = nfs_cb_version[1]->number,
|
.version = nfs_cb_version[1]->number,
|
||||||
.authflavor = RPC_AUTH_UNIX, /* XXX: need AUTH_GSS... */
|
.authflavor = RPC_AUTH_UNIX, /* XXX: need AUTH_GSS... */
|
||||||
.flags = (RPC_CLNT_CREATE_NOPING | RPC_CLNT_CREATE_QUIET),
|
.flags = (RPC_CLNT_CREATE_NOPING | RPC_CLNT_CREATE_QUIET),
|
||||||
|
@ -396,9 +398,6 @@ static int do_probe_callback(void *data)
|
||||||
addr.sin_port = htons(cb->cb_port);
|
addr.sin_port = htons(cb->cb_port);
|
||||||
addr.sin_addr.s_addr = htonl(cb->cb_addr);
|
addr.sin_addr.s_addr = htonl(cb->cb_addr);
|
||||||
|
|
||||||
/* Initialize rpc_stat */
|
|
||||||
memset(args.program->stats, 0, sizeof(struct rpc_stat));
|
|
||||||
|
|
||||||
/* Create RPC client */
|
/* Create RPC client */
|
||||||
client = rpc_create(&args);
|
client = rpc_create(&args);
|
||||||
if (IS_ERR(client)) {
|
if (IS_ERR(client)) {
|
||||||
|
|
|
@ -201,10 +201,10 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||||
/* Openowner is now set, so sequence id will get bumped. Now we need
|
/* Openowner is now set, so sequence id will get bumped. Now we need
|
||||||
* these checks before we do any creates: */
|
* these checks before we do any creates: */
|
||||||
status = nfserr_grace;
|
status = nfserr_grace;
|
||||||
if (nfs4_in_grace() && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS)
|
if (locks_in_grace() && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS)
|
||||||
goto out;
|
goto out;
|
||||||
status = nfserr_no_grace;
|
status = nfserr_no_grace;
|
||||||
if (!nfs4_in_grace() && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
|
if (!locks_in_grace() && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
switch (open->op_claim_type) {
|
switch (open->op_claim_type) {
|
||||||
|
@ -575,7 +575,7 @@ nfsd4_remove(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||||
{
|
{
|
||||||
__be32 status;
|
__be32 status;
|
||||||
|
|
||||||
if (nfs4_in_grace())
|
if (locks_in_grace())
|
||||||
return nfserr_grace;
|
return nfserr_grace;
|
||||||
status = nfsd_unlink(rqstp, &cstate->current_fh, 0,
|
status = nfsd_unlink(rqstp, &cstate->current_fh, 0,
|
||||||
remove->rm_name, remove->rm_namelen);
|
remove->rm_name, remove->rm_namelen);
|
||||||
|
@ -596,7 +596,7 @@ nfsd4_rename(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||||
|
|
||||||
if (!cstate->save_fh.fh_dentry)
|
if (!cstate->save_fh.fh_dentry)
|
||||||
return status;
|
return status;
|
||||||
if (nfs4_in_grace() && !(cstate->save_fh.fh_export->ex_flags
|
if (locks_in_grace() && !(cstate->save_fh.fh_export->ex_flags
|
||||||
& NFSEXP_NOSUBTREECHECK))
|
& NFSEXP_NOSUBTREECHECK))
|
||||||
return nfserr_grace;
|
return nfserr_grace;
|
||||||
status = nfsd_rename(rqstp, &cstate->save_fh, rename->rn_sname,
|
status = nfsd_rename(rqstp, &cstate->save_fh, rename->rn_sname,
|
||||||
|
|
|
@ -61,7 +61,6 @@
|
||||||
static time_t lease_time = 90; /* default lease time */
|
static time_t lease_time = 90; /* default lease time */
|
||||||
static time_t user_lease_time = 90;
|
static time_t user_lease_time = 90;
|
||||||
static time_t boot_time;
|
static time_t boot_time;
|
||||||
static int in_grace = 1;
|
|
||||||
static u32 current_ownerid = 1;
|
static u32 current_ownerid = 1;
|
||||||
static u32 current_fileid = 1;
|
static u32 current_fileid = 1;
|
||||||
static u32 current_delegid = 1;
|
static u32 current_delegid = 1;
|
||||||
|
@ -1640,7 +1639,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta
|
||||||
case NFS4_OPEN_CLAIM_NULL:
|
case NFS4_OPEN_CLAIM_NULL:
|
||||||
/* Let's not give out any delegations till everyone's
|
/* Let's not give out any delegations till everyone's
|
||||||
* had the chance to reclaim theirs.... */
|
* had the chance to reclaim theirs.... */
|
||||||
if (nfs4_in_grace())
|
if (locks_in_grace())
|
||||||
goto out;
|
goto out;
|
||||||
if (!atomic_read(&cb->cb_set) || !sop->so_confirmed)
|
if (!atomic_read(&cb->cb_set) || !sop->so_confirmed)
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -1816,12 +1815,15 @@ out:
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct lock_manager nfsd4_manager = {
|
||||||
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
end_grace(void)
|
nfsd4_end_grace(void)
|
||||||
{
|
{
|
||||||
dprintk("NFSD: end of grace period\n");
|
dprintk("NFSD: end of grace period\n");
|
||||||
nfsd4_recdir_purge_old();
|
nfsd4_recdir_purge_old();
|
||||||
in_grace = 0;
|
locks_end_grace(&nfsd4_manager);
|
||||||
}
|
}
|
||||||
|
|
||||||
static time_t
|
static time_t
|
||||||
|
@ -1838,8 +1840,8 @@ nfs4_laundromat(void)
|
||||||
nfs4_lock_state();
|
nfs4_lock_state();
|
||||||
|
|
||||||
dprintk("NFSD: laundromat service - starting\n");
|
dprintk("NFSD: laundromat service - starting\n");
|
||||||
if (in_grace)
|
if (locks_in_grace())
|
||||||
end_grace();
|
nfsd4_end_grace();
|
||||||
list_for_each_safe(pos, next, &client_lru) {
|
list_for_each_safe(pos, next, &client_lru) {
|
||||||
clp = list_entry(pos, struct nfs4_client, cl_lru);
|
clp = list_entry(pos, struct nfs4_client, cl_lru);
|
||||||
if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) {
|
if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) {
|
||||||
|
@ -1974,7 +1976,7 @@ check_special_stateids(svc_fh *current_fh, stateid_t *stateid, int flags)
|
||||||
return nfserr_bad_stateid;
|
return nfserr_bad_stateid;
|
||||||
else if (ONE_STATEID(stateid) && (flags & RD_STATE))
|
else if (ONE_STATEID(stateid) && (flags & RD_STATE))
|
||||||
return nfs_ok;
|
return nfs_ok;
|
||||||
else if (nfs4_in_grace()) {
|
else if (locks_in_grace()) {
|
||||||
/* Answer in remaining cases depends on existance of
|
/* Answer in remaining cases depends on existance of
|
||||||
* conflicting state; so we must wait out the grace period. */
|
* conflicting state; so we must wait out the grace period. */
|
||||||
return nfserr_grace;
|
return nfserr_grace;
|
||||||
|
@ -1993,7 +1995,7 @@ check_special_stateids(svc_fh *current_fh, stateid_t *stateid, int flags)
|
||||||
static inline int
|
static inline int
|
||||||
io_during_grace_disallowed(struct inode *inode, int flags)
|
io_during_grace_disallowed(struct inode *inode, int flags)
|
||||||
{
|
{
|
||||||
return nfs4_in_grace() && (flags & (RD_STATE | WR_STATE))
|
return locks_in_grace() && (flags & (RD_STATE | WR_STATE))
|
||||||
&& mandatory_lock(inode);
|
&& mandatory_lock(inode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2693,10 +2695,10 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||||
filp = lock_stp->st_vfs_file;
|
filp = lock_stp->st_vfs_file;
|
||||||
|
|
||||||
status = nfserr_grace;
|
status = nfserr_grace;
|
||||||
if (nfs4_in_grace() && !lock->lk_reclaim)
|
if (locks_in_grace() && !lock->lk_reclaim)
|
||||||
goto out;
|
goto out;
|
||||||
status = nfserr_no_grace;
|
status = nfserr_no_grace;
|
||||||
if (!nfs4_in_grace() && lock->lk_reclaim)
|
if (!locks_in_grace() && lock->lk_reclaim)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
locks_init_lock(&file_lock);
|
locks_init_lock(&file_lock);
|
||||||
|
@ -2779,7 +2781,7 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||||
int error;
|
int error;
|
||||||
__be32 status;
|
__be32 status;
|
||||||
|
|
||||||
if (nfs4_in_grace())
|
if (locks_in_grace())
|
||||||
return nfserr_grace;
|
return nfserr_grace;
|
||||||
|
|
||||||
if (check_lock_length(lockt->lt_offset, lockt->lt_length))
|
if (check_lock_length(lockt->lt_offset, lockt->lt_length))
|
||||||
|
@ -3192,9 +3194,9 @@ __nfs4_state_start(void)
|
||||||
unsigned long grace_time;
|
unsigned long grace_time;
|
||||||
|
|
||||||
boot_time = get_seconds();
|
boot_time = get_seconds();
|
||||||
grace_time = get_nfs_grace_period();
|
grace_time = get_nfs4_grace_period();
|
||||||
lease_time = user_lease_time;
|
lease_time = user_lease_time;
|
||||||
in_grace = 1;
|
locks_start_grace(&nfsd4_manager);
|
||||||
printk(KERN_INFO "NFSD: starting %ld-second grace period\n",
|
printk(KERN_INFO "NFSD: starting %ld-second grace period\n",
|
||||||
grace_time/HZ);
|
grace_time/HZ);
|
||||||
laundry_wq = create_singlethread_workqueue("nfsd4");
|
laundry_wq = create_singlethread_workqueue("nfsd4");
|
||||||
|
@ -3213,12 +3215,6 @@ nfs4_state_start(void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
|
||||||
nfs4_in_grace(void)
|
|
||||||
{
|
|
||||||
return in_grace;
|
|
||||||
}
|
|
||||||
|
|
||||||
time_t
|
time_t
|
||||||
nfs4_lease_time(void)
|
nfs4_lease_time(void)
|
||||||
{
|
{
|
||||||
|
|
|
@ -412,6 +412,18 @@ out_nfserr:
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static __be32
|
||||||
|
nfsd4_decode_stateid(struct nfsd4_compoundargs *argp, stateid_t *sid)
|
||||||
|
{
|
||||||
|
DECODE_HEAD;
|
||||||
|
|
||||||
|
READ_BUF(sizeof(stateid_t));
|
||||||
|
READ32(sid->si_generation);
|
||||||
|
COPYMEM(&sid->si_opaque, sizeof(stateid_opaque_t));
|
||||||
|
|
||||||
|
DECODE_TAIL;
|
||||||
|
}
|
||||||
|
|
||||||
static __be32
|
static __be32
|
||||||
nfsd4_decode_access(struct nfsd4_compoundargs *argp, struct nfsd4_access *access)
|
nfsd4_decode_access(struct nfsd4_compoundargs *argp, struct nfsd4_access *access)
|
||||||
{
|
{
|
||||||
|
@ -429,10 +441,9 @@ nfsd4_decode_close(struct nfsd4_compoundargs *argp, struct nfsd4_close *close)
|
||||||
DECODE_HEAD;
|
DECODE_HEAD;
|
||||||
|
|
||||||
close->cl_stateowner = NULL;
|
close->cl_stateowner = NULL;
|
||||||
READ_BUF(4 + sizeof(stateid_t));
|
READ_BUF(4);
|
||||||
READ32(close->cl_seqid);
|
READ32(close->cl_seqid);
|
||||||
READ32(close->cl_stateid.si_generation);
|
return nfsd4_decode_stateid(argp, &close->cl_stateid);
|
||||||
COPYMEM(&close->cl_stateid.si_opaque, sizeof(stateid_opaque_t));
|
|
||||||
|
|
||||||
DECODE_TAIL;
|
DECODE_TAIL;
|
||||||
}
|
}
|
||||||
|
@ -493,13 +504,7 @@ nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create
|
||||||
static inline __be32
|
static inline __be32
|
||||||
nfsd4_decode_delegreturn(struct nfsd4_compoundargs *argp, struct nfsd4_delegreturn *dr)
|
nfsd4_decode_delegreturn(struct nfsd4_compoundargs *argp, struct nfsd4_delegreturn *dr)
|
||||||
{
|
{
|
||||||
DECODE_HEAD;
|
return nfsd4_decode_stateid(argp, &dr->dr_stateid);
|
||||||
|
|
||||||
READ_BUF(sizeof(stateid_t));
|
|
||||||
READ32(dr->dr_stateid.si_generation);
|
|
||||||
COPYMEM(&dr->dr_stateid.si_opaque, sizeof(stateid_opaque_t));
|
|
||||||
|
|
||||||
DECODE_TAIL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline __be32
|
static inline __be32
|
||||||
|
@ -542,20 +547,22 @@ nfsd4_decode_lock(struct nfsd4_compoundargs *argp, struct nfsd4_lock *lock)
|
||||||
READ32(lock->lk_is_new);
|
READ32(lock->lk_is_new);
|
||||||
|
|
||||||
if (lock->lk_is_new) {
|
if (lock->lk_is_new) {
|
||||||
READ_BUF(36);
|
READ_BUF(4);
|
||||||
READ32(lock->lk_new_open_seqid);
|
READ32(lock->lk_new_open_seqid);
|
||||||
READ32(lock->lk_new_open_stateid.si_generation);
|
status = nfsd4_decode_stateid(argp, &lock->lk_new_open_stateid);
|
||||||
|
if (status)
|
||||||
COPYMEM(&lock->lk_new_open_stateid.si_opaque, sizeof(stateid_opaque_t));
|
return status;
|
||||||
|
READ_BUF(8 + sizeof(clientid_t));
|
||||||
READ32(lock->lk_new_lock_seqid);
|
READ32(lock->lk_new_lock_seqid);
|
||||||
COPYMEM(&lock->lk_new_clientid, sizeof(clientid_t));
|
COPYMEM(&lock->lk_new_clientid, sizeof(clientid_t));
|
||||||
READ32(lock->lk_new_owner.len);
|
READ32(lock->lk_new_owner.len);
|
||||||
READ_BUF(lock->lk_new_owner.len);
|
READ_BUF(lock->lk_new_owner.len);
|
||||||
READMEM(lock->lk_new_owner.data, lock->lk_new_owner.len);
|
READMEM(lock->lk_new_owner.data, lock->lk_new_owner.len);
|
||||||
} else {
|
} else {
|
||||||
READ_BUF(20);
|
status = nfsd4_decode_stateid(argp, &lock->lk_old_lock_stateid);
|
||||||
READ32(lock->lk_old_lock_stateid.si_generation);
|
if (status)
|
||||||
COPYMEM(&lock->lk_old_lock_stateid.si_opaque, sizeof(stateid_opaque_t));
|
return status;
|
||||||
|
READ_BUF(4);
|
||||||
READ32(lock->lk_old_lock_seqid);
|
READ32(lock->lk_old_lock_seqid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -587,13 +594,15 @@ nfsd4_decode_locku(struct nfsd4_compoundargs *argp, struct nfsd4_locku *locku)
|
||||||
DECODE_HEAD;
|
DECODE_HEAD;
|
||||||
|
|
||||||
locku->lu_stateowner = NULL;
|
locku->lu_stateowner = NULL;
|
||||||
READ_BUF(24 + sizeof(stateid_t));
|
READ_BUF(8);
|
||||||
READ32(locku->lu_type);
|
READ32(locku->lu_type);
|
||||||
if ((locku->lu_type < NFS4_READ_LT) || (locku->lu_type > NFS4_WRITEW_LT))
|
if ((locku->lu_type < NFS4_READ_LT) || (locku->lu_type > NFS4_WRITEW_LT))
|
||||||
goto xdr_error;
|
goto xdr_error;
|
||||||
READ32(locku->lu_seqid);
|
READ32(locku->lu_seqid);
|
||||||
READ32(locku->lu_stateid.si_generation);
|
status = nfsd4_decode_stateid(argp, &locku->lu_stateid);
|
||||||
COPYMEM(&locku->lu_stateid.si_opaque, sizeof(stateid_opaque_t));
|
if (status)
|
||||||
|
return status;
|
||||||
|
READ_BUF(16);
|
||||||
READ64(locku->lu_offset);
|
READ64(locku->lu_offset);
|
||||||
READ64(locku->lu_length);
|
READ64(locku->lu_length);
|
||||||
|
|
||||||
|
@ -678,8 +687,10 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
|
||||||
READ32(open->op_delegate_type);
|
READ32(open->op_delegate_type);
|
||||||
break;
|
break;
|
||||||
case NFS4_OPEN_CLAIM_DELEGATE_CUR:
|
case NFS4_OPEN_CLAIM_DELEGATE_CUR:
|
||||||
READ_BUF(sizeof(stateid_t) + 4);
|
status = nfsd4_decode_stateid(argp, &open->op_delegate_stateid);
|
||||||
COPYMEM(&open->op_delegate_stateid, sizeof(stateid_t));
|
if (status)
|
||||||
|
return status;
|
||||||
|
READ_BUF(4);
|
||||||
READ32(open->op_fname.len);
|
READ32(open->op_fname.len);
|
||||||
READ_BUF(open->op_fname.len);
|
READ_BUF(open->op_fname.len);
|
||||||
SAVEMEM(open->op_fname.data, open->op_fname.len);
|
SAVEMEM(open->op_fname.data, open->op_fname.len);
|
||||||
|
@ -699,9 +710,10 @@ nfsd4_decode_open_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_open_con
|
||||||
DECODE_HEAD;
|
DECODE_HEAD;
|
||||||
|
|
||||||
open_conf->oc_stateowner = NULL;
|
open_conf->oc_stateowner = NULL;
|
||||||
READ_BUF(4 + sizeof(stateid_t));
|
status = nfsd4_decode_stateid(argp, &open_conf->oc_req_stateid);
|
||||||
READ32(open_conf->oc_req_stateid.si_generation);
|
if (status)
|
||||||
COPYMEM(&open_conf->oc_req_stateid.si_opaque, sizeof(stateid_opaque_t));
|
return status;
|
||||||
|
READ_BUF(4);
|
||||||
READ32(open_conf->oc_seqid);
|
READ32(open_conf->oc_seqid);
|
||||||
|
|
||||||
DECODE_TAIL;
|
DECODE_TAIL;
|
||||||
|
@ -713,9 +725,10 @@ nfsd4_decode_open_downgrade(struct nfsd4_compoundargs *argp, struct nfsd4_open_d
|
||||||
DECODE_HEAD;
|
DECODE_HEAD;
|
||||||
|
|
||||||
open_down->od_stateowner = NULL;
|
open_down->od_stateowner = NULL;
|
||||||
READ_BUF(12 + sizeof(stateid_t));
|
status = nfsd4_decode_stateid(argp, &open_down->od_stateid);
|
||||||
READ32(open_down->od_stateid.si_generation);
|
if (status)
|
||||||
COPYMEM(&open_down->od_stateid.si_opaque, sizeof(stateid_opaque_t));
|
return status;
|
||||||
|
READ_BUF(12);
|
||||||
READ32(open_down->od_seqid);
|
READ32(open_down->od_seqid);
|
||||||
READ32(open_down->od_share_access);
|
READ32(open_down->od_share_access);
|
||||||
READ32(open_down->od_share_deny);
|
READ32(open_down->od_share_deny);
|
||||||
|
@ -743,9 +756,10 @@ nfsd4_decode_read(struct nfsd4_compoundargs *argp, struct nfsd4_read *read)
|
||||||
{
|
{
|
||||||
DECODE_HEAD;
|
DECODE_HEAD;
|
||||||
|
|
||||||
READ_BUF(sizeof(stateid_t) + 12);
|
status = nfsd4_decode_stateid(argp, &read->rd_stateid);
|
||||||
READ32(read->rd_stateid.si_generation);
|
if (status)
|
||||||
COPYMEM(&read->rd_stateid.si_opaque, sizeof(stateid_opaque_t));
|
return status;
|
||||||
|
READ_BUF(12);
|
||||||
READ64(read->rd_offset);
|
READ64(read->rd_offset);
|
||||||
READ32(read->rd_length);
|
READ32(read->rd_length);
|
||||||
|
|
||||||
|
@ -834,15 +848,13 @@ nfsd4_decode_secinfo(struct nfsd4_compoundargs *argp,
|
||||||
static __be32
|
static __be32
|
||||||
nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *setattr)
|
nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *setattr)
|
||||||
{
|
{
|
||||||
DECODE_HEAD;
|
__be32 status;
|
||||||
|
|
||||||
READ_BUF(sizeof(stateid_t));
|
status = nfsd4_decode_stateid(argp, &setattr->sa_stateid);
|
||||||
READ32(setattr->sa_stateid.si_generation);
|
if (status)
|
||||||
COPYMEM(&setattr->sa_stateid.si_opaque, sizeof(stateid_opaque_t));
|
return status;
|
||||||
if ((status = nfsd4_decode_fattr(argp, setattr->sa_bmval, &setattr->sa_iattr, &setattr->sa_acl)))
|
return nfsd4_decode_fattr(argp, setattr->sa_bmval,
|
||||||
goto out;
|
&setattr->sa_iattr, &setattr->sa_acl);
|
||||||
|
|
||||||
DECODE_TAIL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static __be32
|
static __be32
|
||||||
|
@ -927,9 +939,10 @@ nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write)
|
||||||
int len;
|
int len;
|
||||||
DECODE_HEAD;
|
DECODE_HEAD;
|
||||||
|
|
||||||
READ_BUF(sizeof(stateid_opaque_t) + 20);
|
status = nfsd4_decode_stateid(argp, &write->wr_stateid);
|
||||||
READ32(write->wr_stateid.si_generation);
|
if (status)
|
||||||
COPYMEM(&write->wr_stateid.si_opaque, sizeof(stateid_opaque_t));
|
return status;
|
||||||
|
READ_BUF(16);
|
||||||
READ64(write->wr_offset);
|
READ64(write->wr_offset);
|
||||||
READ32(write->wr_stable_how);
|
READ32(write->wr_stable_how);
|
||||||
if (write->wr_stable_how > 2)
|
if (write->wr_stable_how > 2)
|
||||||
|
@ -1183,7 +1196,6 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
|
||||||
* Header routine to setup seqid operation replay cache
|
* Header routine to setup seqid operation replay cache
|
||||||
*/
|
*/
|
||||||
#define ENCODE_SEQID_OP_HEAD \
|
#define ENCODE_SEQID_OP_HEAD \
|
||||||
__be32 *p; \
|
|
||||||
__be32 *save; \
|
__be32 *save; \
|
||||||
\
|
\
|
||||||
save = resp->p;
|
save = resp->p;
|
||||||
|
@ -1950,6 +1962,17 @@ fail:
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
nfsd4_encode_stateid(struct nfsd4_compoundres *resp, stateid_t *sid)
|
||||||
|
{
|
||||||
|
ENCODE_HEAD;
|
||||||
|
|
||||||
|
RESERVE_SPACE(sizeof(stateid_t));
|
||||||
|
WRITE32(sid->si_generation);
|
||||||
|
WRITEMEM(&sid->si_opaque, sizeof(stateid_opaque_t));
|
||||||
|
ADJUST_ARGS();
|
||||||
|
}
|
||||||
|
|
||||||
static __be32
|
static __be32
|
||||||
nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_access *access)
|
nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_access *access)
|
||||||
{
|
{
|
||||||
|
@ -1969,12 +1992,9 @@ nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_c
|
||||||
{
|
{
|
||||||
ENCODE_SEQID_OP_HEAD;
|
ENCODE_SEQID_OP_HEAD;
|
||||||
|
|
||||||
if (!nfserr) {
|
if (!nfserr)
|
||||||
RESERVE_SPACE(sizeof(stateid_t));
|
nfsd4_encode_stateid(resp, &close->cl_stateid);
|
||||||
WRITE32(close->cl_stateid.si_generation);
|
|
||||||
WRITEMEM(&close->cl_stateid.si_opaque, sizeof(stateid_opaque_t));
|
|
||||||
ADJUST_ARGS();
|
|
||||||
}
|
|
||||||
ENCODE_SEQID_OP_TAIL(close->cl_stateowner);
|
ENCODE_SEQID_OP_TAIL(close->cl_stateowner);
|
||||||
return nfserr;
|
return nfserr;
|
||||||
}
|
}
|
||||||
|
@ -2074,12 +2094,9 @@ nfsd4_encode_lock(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lo
|
||||||
{
|
{
|
||||||
ENCODE_SEQID_OP_HEAD;
|
ENCODE_SEQID_OP_HEAD;
|
||||||
|
|
||||||
if (!nfserr) {
|
if (!nfserr)
|
||||||
RESERVE_SPACE(4 + sizeof(stateid_t));
|
nfsd4_encode_stateid(resp, &lock->lk_resp_stateid);
|
||||||
WRITE32(lock->lk_resp_stateid.si_generation);
|
else if (nfserr == nfserr_denied)
|
||||||
WRITEMEM(&lock->lk_resp_stateid.si_opaque, sizeof(stateid_opaque_t));
|
|
||||||
ADJUST_ARGS();
|
|
||||||
} else if (nfserr == nfserr_denied)
|
|
||||||
nfsd4_encode_lock_denied(resp, &lock->lk_denied);
|
nfsd4_encode_lock_denied(resp, &lock->lk_denied);
|
||||||
|
|
||||||
ENCODE_SEQID_OP_TAIL(lock->lk_replay_owner);
|
ENCODE_SEQID_OP_TAIL(lock->lk_replay_owner);
|
||||||
|
@ -2099,12 +2116,8 @@ nfsd4_encode_locku(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_l
|
||||||
{
|
{
|
||||||
ENCODE_SEQID_OP_HEAD;
|
ENCODE_SEQID_OP_HEAD;
|
||||||
|
|
||||||
if (!nfserr) {
|
if (!nfserr)
|
||||||
RESERVE_SPACE(sizeof(stateid_t));
|
nfsd4_encode_stateid(resp, &locku->lu_stateid);
|
||||||
WRITE32(locku->lu_stateid.si_generation);
|
|
||||||
WRITEMEM(&locku->lu_stateid.si_opaque, sizeof(stateid_opaque_t));
|
|
||||||
ADJUST_ARGS();
|
|
||||||
}
|
|
||||||
|
|
||||||
ENCODE_SEQID_OP_TAIL(locku->lu_stateowner);
|
ENCODE_SEQID_OP_TAIL(locku->lu_stateowner);
|
||||||
return nfserr;
|
return nfserr;
|
||||||
|
@ -2128,14 +2141,14 @@ nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_li
|
||||||
static __be32
|
static __be32
|
||||||
nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open *open)
|
nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open *open)
|
||||||
{
|
{
|
||||||
|
ENCODE_HEAD;
|
||||||
ENCODE_SEQID_OP_HEAD;
|
ENCODE_SEQID_OP_HEAD;
|
||||||
|
|
||||||
if (nfserr)
|
if (nfserr)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
RESERVE_SPACE(36 + sizeof(stateid_t));
|
nfsd4_encode_stateid(resp, &open->op_stateid);
|
||||||
WRITE32(open->op_stateid.si_generation);
|
RESERVE_SPACE(40);
|
||||||
WRITEMEM(&open->op_stateid.si_opaque, sizeof(stateid_opaque_t));
|
|
||||||
WRITECINFO(open->op_cinfo);
|
WRITECINFO(open->op_cinfo);
|
||||||
WRITE32(open->op_rflags);
|
WRITE32(open->op_rflags);
|
||||||
WRITE32(2);
|
WRITE32(2);
|
||||||
|
@ -2148,8 +2161,8 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_op
|
||||||
case NFS4_OPEN_DELEGATE_NONE:
|
case NFS4_OPEN_DELEGATE_NONE:
|
||||||
break;
|
break;
|
||||||
case NFS4_OPEN_DELEGATE_READ:
|
case NFS4_OPEN_DELEGATE_READ:
|
||||||
RESERVE_SPACE(20 + sizeof(stateid_t));
|
nfsd4_encode_stateid(resp, &open->op_delegate_stateid);
|
||||||
WRITEMEM(&open->op_delegate_stateid, sizeof(stateid_t));
|
RESERVE_SPACE(20);
|
||||||
WRITE32(open->op_recall);
|
WRITE32(open->op_recall);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2162,8 +2175,8 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_op
|
||||||
ADJUST_ARGS();
|
ADJUST_ARGS();
|
||||||
break;
|
break;
|
||||||
case NFS4_OPEN_DELEGATE_WRITE:
|
case NFS4_OPEN_DELEGATE_WRITE:
|
||||||
RESERVE_SPACE(32 + sizeof(stateid_t));
|
nfsd4_encode_stateid(resp, &open->op_delegate_stateid);
|
||||||
WRITEMEM(&open->op_delegate_stateid, sizeof(stateid_t));
|
RESERVE_SPACE(32);
|
||||||
WRITE32(0);
|
WRITE32(0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2196,12 +2209,8 @@ nfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, __be32 nfserr, struct
|
||||||
{
|
{
|
||||||
ENCODE_SEQID_OP_HEAD;
|
ENCODE_SEQID_OP_HEAD;
|
||||||
|
|
||||||
if (!nfserr) {
|
if (!nfserr)
|
||||||
RESERVE_SPACE(sizeof(stateid_t));
|
nfsd4_encode_stateid(resp, &oc->oc_resp_stateid);
|
||||||
WRITE32(oc->oc_resp_stateid.si_generation);
|
|
||||||
WRITEMEM(&oc->oc_resp_stateid.si_opaque, sizeof(stateid_opaque_t));
|
|
||||||
ADJUST_ARGS();
|
|
||||||
}
|
|
||||||
|
|
||||||
ENCODE_SEQID_OP_TAIL(oc->oc_stateowner);
|
ENCODE_SEQID_OP_TAIL(oc->oc_stateowner);
|
||||||
return nfserr;
|
return nfserr;
|
||||||
|
@ -2212,12 +2221,8 @@ nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, __be32 nfserr, struc
|
||||||
{
|
{
|
||||||
ENCODE_SEQID_OP_HEAD;
|
ENCODE_SEQID_OP_HEAD;
|
||||||
|
|
||||||
if (!nfserr) {
|
if (!nfserr)
|
||||||
RESERVE_SPACE(sizeof(stateid_t));
|
nfsd4_encode_stateid(resp, &od->od_stateid);
|
||||||
WRITE32(od->od_stateid.si_generation);
|
|
||||||
WRITEMEM(&od->od_stateid.si_opaque, sizeof(stateid_opaque_t));
|
|
||||||
ADJUST_ARGS();
|
|
||||||
}
|
|
||||||
|
|
||||||
ENCODE_SEQID_OP_TAIL(od->od_stateowner);
|
ENCODE_SEQID_OP_TAIL(od->od_stateowner);
|
||||||
return nfserr;
|
return nfserr;
|
||||||
|
|
|
@ -614,10 +614,9 @@ static ssize_t __write_ports(struct file *file, char *buf, size_t size)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
err = nfsd_create_serv();
|
err = nfsd_create_serv();
|
||||||
if (!err) {
|
if (!err) {
|
||||||
int proto = 0;
|
err = svc_addsock(nfsd_serv, fd, buf);
|
||||||
err = svc_addsock(nfsd_serv, fd, buf, &proto);
|
|
||||||
if (err >= 0) {
|
if (err >= 0) {
|
||||||
err = lockd_up(proto);
|
err = lockd_up();
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
svc_sock_names(buf+strlen(buf)+1, nfsd_serv, buf);
|
svc_sock_names(buf+strlen(buf)+1, nfsd_serv, buf);
|
||||||
}
|
}
|
||||||
|
|
|
@ -302,17 +302,27 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
|
||||||
if (error)
|
if (error)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (!(access & NFSD_MAY_LOCK)) {
|
|
||||||
/*
|
/*
|
||||||
* pseudoflavor restrictions are not enforced on NLM,
|
* pseudoflavor restrictions are not enforced on NLM,
|
||||||
* which clients virtually always use auth_sys for,
|
* which clients virtually always use auth_sys for,
|
||||||
* even while using RPCSEC_GSS for NFS.
|
* even while using RPCSEC_GSS for NFS.
|
||||||
*/
|
*/
|
||||||
|
if (access & NFSD_MAY_LOCK)
|
||||||
|
goto skip_pseudoflavor_check;
|
||||||
|
/*
|
||||||
|
* Clients may expect to be able to use auth_sys during mount,
|
||||||
|
* even if they use gss for everything else; see section 2.3.2
|
||||||
|
* of rfc 2623.
|
||||||
|
*/
|
||||||
|
if (access & NFSD_MAY_BYPASS_GSS_ON_ROOT
|
||||||
|
&& exp->ex_path.dentry == dentry)
|
||||||
|
goto skip_pseudoflavor_check;
|
||||||
|
|
||||||
error = check_nfsd_access(exp, rqstp);
|
error = check_nfsd_access(exp, rqstp);
|
||||||
if (error)
|
if (error)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
|
||||||
|
|
||||||
|
skip_pseudoflavor_check:
|
||||||
/* Finally, check access permissions. */
|
/* Finally, check access permissions. */
|
||||||
error = nfsd_permission(rqstp, exp, dentry, access);
|
error = nfsd_permission(rqstp, exp, dentry, access);
|
||||||
|
|
||||||
|
|
|
@ -65,7 +65,8 @@ nfsd_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle *argp,
|
||||||
dprintk("nfsd: GETATTR %s\n", SVCFH_fmt(&argp->fh));
|
dprintk("nfsd: GETATTR %s\n", SVCFH_fmt(&argp->fh));
|
||||||
|
|
||||||
fh_copy(&resp->fh, &argp->fh);
|
fh_copy(&resp->fh, &argp->fh);
|
||||||
nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP);
|
nfserr = fh_verify(rqstp, &resp->fh, 0,
|
||||||
|
NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT);
|
||||||
return nfsd_return_attrs(nfserr, resp);
|
return nfsd_return_attrs(nfserr, resp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -521,7 +522,8 @@ nfsd_proc_statfs(struct svc_rqst * rqstp, struct nfsd_fhandle *argp,
|
||||||
|
|
||||||
dprintk("nfsd: STATFS %s\n", SVCFH_fmt(&argp->fh));
|
dprintk("nfsd: STATFS %s\n", SVCFH_fmt(&argp->fh));
|
||||||
|
|
||||||
nfserr = nfsd_statfs(rqstp, &argp->fh, &resp->stats);
|
nfserr = nfsd_statfs(rqstp, &argp->fh, &resp->stats,
|
||||||
|
NFSD_MAY_BYPASS_GSS_ON_ROOT);
|
||||||
fh_put(&argp->fh);
|
fh_put(&argp->fh);
|
||||||
return nfserr;
|
return nfserr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -229,6 +229,7 @@ int nfsd_create_serv(void)
|
||||||
|
|
||||||
atomic_set(&nfsd_busy, 0);
|
atomic_set(&nfsd_busy, 0);
|
||||||
nfsd_serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize,
|
nfsd_serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize,
|
||||||
|
AF_INET,
|
||||||
nfsd_last_thread, nfsd, THIS_MODULE);
|
nfsd_last_thread, nfsd, THIS_MODULE);
|
||||||
if (nfsd_serv == NULL)
|
if (nfsd_serv == NULL)
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
|
@ -243,25 +244,20 @@ static int nfsd_init_socks(int port)
|
||||||
if (!list_empty(&nfsd_serv->sv_permsocks))
|
if (!list_empty(&nfsd_serv->sv_permsocks))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error = lockd_up(IPPROTO_UDP);
|
|
||||||
if (error >= 0) {
|
|
||||||
error = svc_create_xprt(nfsd_serv, "udp", port,
|
error = svc_create_xprt(nfsd_serv, "udp", port,
|
||||||
SVC_SOCK_DEFAULTS);
|
SVC_SOCK_DEFAULTS);
|
||||||
if (error < 0)
|
|
||||||
lockd_down();
|
|
||||||
}
|
|
||||||
if (error < 0)
|
if (error < 0)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
error = lockd_up(IPPROTO_TCP);
|
|
||||||
if (error >= 0) {
|
|
||||||
error = svc_create_xprt(nfsd_serv, "tcp", port,
|
error = svc_create_xprt(nfsd_serv, "tcp", port,
|
||||||
SVC_SOCK_DEFAULTS);
|
SVC_SOCK_DEFAULTS);
|
||||||
if (error < 0)
|
if (error < 0)
|
||||||
lockd_down();
|
return error;
|
||||||
}
|
|
||||||
|
error = lockd_up();
|
||||||
if (error < 0)
|
if (error < 0)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -83,7 +83,6 @@ struct raparm_hbucket {
|
||||||
spinlock_t pb_lock;
|
spinlock_t pb_lock;
|
||||||
} ____cacheline_aligned_in_smp;
|
} ____cacheline_aligned_in_smp;
|
||||||
|
|
||||||
static struct raparms * raparml;
|
|
||||||
#define RAPARM_HASH_BITS 4
|
#define RAPARM_HASH_BITS 4
|
||||||
#define RAPARM_HASH_SIZE (1<<RAPARM_HASH_BITS)
|
#define RAPARM_HASH_SIZE (1<<RAPARM_HASH_BITS)
|
||||||
#define RAPARM_HASH_MASK (RAPARM_HASH_SIZE-1)
|
#define RAPARM_HASH_MASK (RAPARM_HASH_SIZE-1)
|
||||||
|
@ -1866,9 +1865,9 @@ out:
|
||||||
* N.B. After this call fhp needs an fh_put
|
* N.B. After this call fhp needs an fh_put
|
||||||
*/
|
*/
|
||||||
__be32
|
__be32
|
||||||
nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat)
|
nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat, int access)
|
||||||
{
|
{
|
||||||
__be32 err = fh_verify(rqstp, fhp, 0, NFSD_MAY_NOP);
|
__be32 err = fh_verify(rqstp, fhp, 0, NFSD_MAY_NOP | access);
|
||||||
if (!err && vfs_statfs(fhp->fh_dentry,stat))
|
if (!err && vfs_statfs(fhp->fh_dentry,stat))
|
||||||
err = nfserr_io;
|
err = nfserr_io;
|
||||||
return err;
|
return err;
|
||||||
|
@ -1966,11 +1965,20 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp,
|
||||||
void
|
void
|
||||||
nfsd_racache_shutdown(void)
|
nfsd_racache_shutdown(void)
|
||||||
{
|
{
|
||||||
if (!raparml)
|
struct raparms *raparm, *last_raparm;
|
||||||
return;
|
unsigned int i;
|
||||||
|
|
||||||
dprintk("nfsd: freeing readahead buffers.\n");
|
dprintk("nfsd: freeing readahead buffers.\n");
|
||||||
kfree(raparml);
|
|
||||||
raparml = NULL;
|
for (i = 0; i < RAPARM_HASH_SIZE; i++) {
|
||||||
|
raparm = raparm_hash[i].pb_head;
|
||||||
|
while(raparm) {
|
||||||
|
last_raparm = raparm;
|
||||||
|
raparm = raparm->p_next;
|
||||||
|
kfree(last_raparm);
|
||||||
|
}
|
||||||
|
raparm_hash[i].pb_head = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* Initialize readahead param cache
|
* Initialize readahead param cache
|
||||||
|
@ -1981,35 +1989,38 @@ nfsd_racache_init(int cache_size)
|
||||||
int i;
|
int i;
|
||||||
int j = 0;
|
int j = 0;
|
||||||
int nperbucket;
|
int nperbucket;
|
||||||
|
struct raparms **raparm = NULL;
|
||||||
|
|
||||||
|
|
||||||
if (raparml)
|
if (raparm_hash[0].pb_head)
|
||||||
return 0;
|
return 0;
|
||||||
if (cache_size < 2*RAPARM_HASH_SIZE)
|
nperbucket = DIV_ROUND_UP(cache_size, RAPARM_HASH_SIZE);
|
||||||
cache_size = 2*RAPARM_HASH_SIZE;
|
if (nperbucket < 2)
|
||||||
raparml = kcalloc(cache_size, sizeof(struct raparms), GFP_KERNEL);
|
nperbucket = 2;
|
||||||
|
cache_size = nperbucket * RAPARM_HASH_SIZE;
|
||||||
if (!raparml) {
|
|
||||||
printk(KERN_WARNING
|
|
||||||
"nfsd: Could not allocate memory read-ahead cache.\n");
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
dprintk("nfsd: allocating %d readahead buffers.\n", cache_size);
|
dprintk("nfsd: allocating %d readahead buffers.\n", cache_size);
|
||||||
|
|
||||||
for (i = 0; i < RAPARM_HASH_SIZE; i++) {
|
for (i = 0; i < RAPARM_HASH_SIZE; i++) {
|
||||||
raparm_hash[i].pb_head = NULL;
|
|
||||||
spin_lock_init(&raparm_hash[i].pb_lock);
|
spin_lock_init(&raparm_hash[i].pb_lock);
|
||||||
|
|
||||||
|
raparm = &raparm_hash[i].pb_head;
|
||||||
|
for (j = 0; j < nperbucket; j++) {
|
||||||
|
*raparm = kzalloc(sizeof(struct raparms), GFP_KERNEL);
|
||||||
|
if (!*raparm)
|
||||||
|
goto out_nomem;
|
||||||
|
raparm = &(*raparm)->p_next;
|
||||||
}
|
}
|
||||||
nperbucket = DIV_ROUND_UP(cache_size, RAPARM_HASH_SIZE);
|
*raparm = NULL;
|
||||||
for (i = 0; i < cache_size - 1; i++) {
|
|
||||||
if (i % nperbucket == 0)
|
|
||||||
raparm_hash[j++].pb_head = raparml + i;
|
|
||||||
if (i % nperbucket < nperbucket-1)
|
|
||||||
raparml[i].p_next = raparml + i + 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nfsdstats.ra_size = cache_size;
|
nfsdstats.ra_size = cache_size;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
out_nomem:
|
||||||
|
dprintk("nfsd: kmalloc failed, freeing readahead buffers\n");
|
||||||
|
nfsd_racache_shutdown();
|
||||||
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
|
#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
|
||||||
|
|
|
@ -683,6 +683,7 @@ static int cmdline_read_proc(char *page, char **start, off_t off,
|
||||||
return proc_calc_metrics(page, start, off, count, eof, len);
|
return proc_calc_metrics(page, start, off, count, eof, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_FILE_LOCKING
|
||||||
static int locks_open(struct inode *inode, struct file *filp)
|
static int locks_open(struct inode *inode, struct file *filp)
|
||||||
{
|
{
|
||||||
return seq_open(filp, &locks_seq_operations);
|
return seq_open(filp, &locks_seq_operations);
|
||||||
|
@ -694,6 +695,7 @@ static const struct file_operations proc_locks_operations = {
|
||||||
.llseek = seq_lseek,
|
.llseek = seq_lseek,
|
||||||
.release = seq_release,
|
.release = seq_release,
|
||||||
};
|
};
|
||||||
|
#endif /* CONFIG_FILE_LOCKING */
|
||||||
|
|
||||||
static int execdomains_read_proc(char *page, char **start, off_t off,
|
static int execdomains_read_proc(char *page, char **start, off_t off,
|
||||||
int count, int *eof, void *data)
|
int count, int *eof, void *data)
|
||||||
|
@ -887,7 +889,9 @@ void __init proc_misc_init(void)
|
||||||
#ifdef CONFIG_PRINTK
|
#ifdef CONFIG_PRINTK
|
||||||
proc_create("kmsg", S_IRUSR, NULL, &proc_kmsg_operations);
|
proc_create("kmsg", S_IRUSR, NULL, &proc_kmsg_operations);
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef CONFIG_FILE_LOCKING
|
||||||
proc_create("locks", 0, NULL, &proc_locks_operations);
|
proc_create("locks", 0, NULL, &proc_locks_operations);
|
||||||
|
#endif
|
||||||
proc_create("devices", 0, NULL, &proc_devinfo_operations);
|
proc_create("devices", 0, NULL, &proc_devinfo_operations);
|
||||||
proc_create("cpuinfo", 0, NULL, &proc_cpuinfo_operations);
|
proc_create("cpuinfo", 0, NULL, &proc_cpuinfo_operations);
|
||||||
#ifdef CONFIG_BLOCK
|
#ifdef CONFIG_BLOCK
|
||||||
|
|
|
@ -947,6 +947,14 @@ struct lock_manager_operations {
|
||||||
int (*fl_change)(struct file_lock **, int);
|
int (*fl_change)(struct file_lock **, int);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct lock_manager {
|
||||||
|
struct list_head list;
|
||||||
|
};
|
||||||
|
|
||||||
|
void locks_start_grace(struct lock_manager *);
|
||||||
|
void locks_end_grace(struct lock_manager *);
|
||||||
|
int locks_in_grace(void);
|
||||||
|
|
||||||
/* that will die - we need it for nfs_lock_info */
|
/* that will die - we need it for nfs_lock_info */
|
||||||
#include <linux/nfs_fs_i.h>
|
#include <linux/nfs_fs_i.h>
|
||||||
|
|
||||||
|
@ -988,6 +996,13 @@ struct file_lock {
|
||||||
|
|
||||||
#include <linux/fcntl.h>
|
#include <linux/fcntl.h>
|
||||||
|
|
||||||
|
extern void send_sigio(struct fown_struct *fown, int fd, int band);
|
||||||
|
|
||||||
|
/* fs/sync.c */
|
||||||
|
extern int do_sync_mapping_range(struct address_space *mapping, loff_t offset,
|
||||||
|
loff_t endbyte, unsigned int flags);
|
||||||
|
|
||||||
|
#ifdef CONFIG_FILE_LOCKING
|
||||||
extern int fcntl_getlk(struct file *, struct flock __user *);
|
extern int fcntl_getlk(struct file *, struct flock __user *);
|
||||||
extern int fcntl_setlk(unsigned int, struct file *, unsigned int,
|
extern int fcntl_setlk(unsigned int, struct file *, unsigned int,
|
||||||
struct flock __user *);
|
struct flock __user *);
|
||||||
|
@ -998,14 +1013,9 @@ extern int fcntl_setlk64(unsigned int, struct file *, unsigned int,
|
||||||
struct flock64 __user *);
|
struct flock64 __user *);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern void send_sigio(struct fown_struct *fown, int fd, int band);
|
|
||||||
extern int fcntl_setlease(unsigned int fd, struct file *filp, long arg);
|
extern int fcntl_setlease(unsigned int fd, struct file *filp, long arg);
|
||||||
extern int fcntl_getlease(struct file *filp);
|
extern int fcntl_getlease(struct file *filp);
|
||||||
|
|
||||||
/* fs/sync.c */
|
|
||||||
extern int do_sync_mapping_range(struct address_space *mapping, loff_t offset,
|
|
||||||
loff_t endbyte, unsigned int flags);
|
|
||||||
|
|
||||||
/* fs/locks.c */
|
/* fs/locks.c */
|
||||||
extern void locks_init_lock(struct file_lock *);
|
extern void locks_init_lock(struct file_lock *);
|
||||||
extern void locks_copy_lock(struct file_lock *, struct file_lock *);
|
extern void locks_copy_lock(struct file_lock *, struct file_lock *);
|
||||||
|
@ -1028,6 +1038,37 @@ extern int lease_modify(struct file_lock **, int);
|
||||||
extern int lock_may_read(struct inode *, loff_t start, unsigned long count);
|
extern int lock_may_read(struct inode *, loff_t start, unsigned long count);
|
||||||
extern int lock_may_write(struct inode *, loff_t start, unsigned long count);
|
extern int lock_may_write(struct inode *, loff_t start, unsigned long count);
|
||||||
extern struct seq_operations locks_seq_operations;
|
extern struct seq_operations locks_seq_operations;
|
||||||
|
#else /* !CONFIG_FILE_LOCKING */
|
||||||
|
#define fcntl_getlk(a, b) ({ -EINVAL; })
|
||||||
|
#define fcntl_setlk(a, b, c, d) ({ -EACCES; })
|
||||||
|
#if BITS_PER_LONG == 32
|
||||||
|
#define fcntl_getlk64(a, b) ({ -EINVAL; })
|
||||||
|
#define fcntl_setlk64(a, b, c, d) ({ -EACCES; })
|
||||||
|
#endif
|
||||||
|
#define fcntl_setlease(a, b, c) ({ 0; })
|
||||||
|
#define fcntl_getlease(a) ({ 0; })
|
||||||
|
#define locks_init_lock(a) ({ })
|
||||||
|
#define __locks_copy_lock(a, b) ({ })
|
||||||
|
#define locks_copy_lock(a, b) ({ })
|
||||||
|
#define locks_remove_posix(a, b) ({ })
|
||||||
|
#define locks_remove_flock(a) ({ })
|
||||||
|
#define posix_test_lock(a, b) ({ 0; })
|
||||||
|
#define posix_lock_file(a, b, c) ({ -ENOLCK; })
|
||||||
|
#define posix_lock_file_wait(a, b) ({ -ENOLCK; })
|
||||||
|
#define posix_unblock_lock(a, b) (-ENOENT)
|
||||||
|
#define vfs_test_lock(a, b) ({ 0; })
|
||||||
|
#define vfs_lock_file(a, b, c, d) (-ENOLCK)
|
||||||
|
#define vfs_cancel_lock(a, b) ({ 0; })
|
||||||
|
#define flock_lock_file_wait(a, b) ({ -ENOLCK; })
|
||||||
|
#define __break_lease(a, b) ({ 0; })
|
||||||
|
#define lease_get_mtime(a, b) ({ })
|
||||||
|
#define generic_setlease(a, b, c) ({ -EINVAL; })
|
||||||
|
#define vfs_setlease(a, b, c) ({ -EINVAL; })
|
||||||
|
#define lease_modify(a, b) ({ -EINVAL; })
|
||||||
|
#define lock_may_read(a, b, c) ({ 1; })
|
||||||
|
#define lock_may_write(a, b, c) ({ 1; })
|
||||||
|
#endif /* !CONFIG_FILE_LOCKING */
|
||||||
|
|
||||||
|
|
||||||
struct fasync_struct {
|
struct fasync_struct {
|
||||||
int magic;
|
int magic;
|
||||||
|
@ -1575,9 +1616,12 @@ extern int vfs_statfs(struct dentry *, struct kstatfs *);
|
||||||
/* /sys/fs */
|
/* /sys/fs */
|
||||||
extern struct kobject *fs_kobj;
|
extern struct kobject *fs_kobj;
|
||||||
|
|
||||||
|
extern int rw_verify_area(int, struct file *, loff_t *, size_t);
|
||||||
|
|
||||||
#define FLOCK_VERIFY_READ 1
|
#define FLOCK_VERIFY_READ 1
|
||||||
#define FLOCK_VERIFY_WRITE 2
|
#define FLOCK_VERIFY_WRITE 2
|
||||||
|
|
||||||
|
#ifdef CONFIG_FILE_LOCKING
|
||||||
extern int locks_mandatory_locked(struct inode *);
|
extern int locks_mandatory_locked(struct inode *);
|
||||||
extern int locks_mandatory_area(int, struct inode *, struct file *, loff_t, size_t);
|
extern int locks_mandatory_area(int, struct inode *, struct file *, loff_t, size_t);
|
||||||
|
|
||||||
|
@ -1608,8 +1652,6 @@ static inline int locks_verify_locked(struct inode *inode)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int rw_verify_area(int, struct file *, loff_t *, size_t);
|
|
||||||
|
|
||||||
static inline int locks_verify_truncate(struct inode *inode,
|
static inline int locks_verify_truncate(struct inode *inode,
|
||||||
struct file *filp,
|
struct file *filp,
|
||||||
loff_t size)
|
loff_t size)
|
||||||
|
@ -1630,6 +1672,15 @@ static inline int break_lease(struct inode *inode, unsigned int mode)
|
||||||
return __break_lease(inode, mode);
|
return __break_lease(inode, mode);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#else /* !CONFIG_FILE_LOCKING */
|
||||||
|
#define locks_mandatory_locked(a) ({ 0; })
|
||||||
|
#define locks_mandatory_area(a, b, c, d, e) ({ 0; })
|
||||||
|
#define __mandatory_lock(a) ({ 0; })
|
||||||
|
#define mandatory_lock(a) ({ 0; })
|
||||||
|
#define locks_verify_locked(a) ({ 0; })
|
||||||
|
#define locks_verify_truncate(a, b, c) ({ 0; })
|
||||||
|
#define break_lease(a, b) ({ 0; })
|
||||||
|
#endif /* CONFIG_FILE_LOCKING */
|
||||||
|
|
||||||
/* fs/open.c */
|
/* fs/open.c */
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,6 @@ struct nlmsvc_binding {
|
||||||
struct nfs_fh *,
|
struct nfs_fh *,
|
||||||
struct file **);
|
struct file **);
|
||||||
void (*fclose)(struct file *);
|
void (*fclose)(struct file *);
|
||||||
unsigned long (*get_grace_period)(void);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct nlmsvc_binding * nlmsvc_ops;
|
extern struct nlmsvc_binding * nlmsvc_ops;
|
||||||
|
@ -53,15 +52,7 @@ extern void nlmclnt_done(struct nlm_host *host);
|
||||||
|
|
||||||
extern int nlmclnt_proc(struct nlm_host *host, int cmd,
|
extern int nlmclnt_proc(struct nlm_host *host, int cmd,
|
||||||
struct file_lock *fl);
|
struct file_lock *fl);
|
||||||
extern int lockd_up(int proto);
|
extern int lockd_up(void);
|
||||||
extern void lockd_down(void);
|
extern void lockd_down(void);
|
||||||
|
|
||||||
unsigned long get_nfs_grace_period(void);
|
|
||||||
|
|
||||||
#ifdef CONFIG_NFSD_V4
|
|
||||||
unsigned long get_nfs4_grace_period(void);
|
|
||||||
#else
|
|
||||||
static inline unsigned long get_nfs4_grace_period(void) {return 0;}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* LINUX_LOCKD_BIND_H */
|
#endif /* LINUX_LOCKD_BIND_H */
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
#ifdef __KERNEL__
|
#ifdef __KERNEL__
|
||||||
|
|
||||||
#include <linux/in.h>
|
#include <linux/in.h>
|
||||||
|
#include <linux/in6.h>
|
||||||
|
#include <net/ipv6.h>
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
#include <linux/kref.h>
|
#include <linux/kref.h>
|
||||||
#include <linux/utsname.h>
|
#include <linux/utsname.h>
|
||||||
|
@ -38,8 +40,9 @@
|
||||||
*/
|
*/
|
||||||
struct nlm_host {
|
struct nlm_host {
|
||||||
struct hlist_node h_hash; /* doubly linked list */
|
struct hlist_node h_hash; /* doubly linked list */
|
||||||
struct sockaddr_in h_addr; /* peer address */
|
struct sockaddr_storage h_addr; /* peer address */
|
||||||
struct sockaddr_in h_saddr; /* our address (optional) */
|
size_t h_addrlen;
|
||||||
|
struct sockaddr_storage h_srcaddr; /* our address (optional) */
|
||||||
struct rpc_clnt * h_rpcclnt; /* RPC client to talk to peer */
|
struct rpc_clnt * h_rpcclnt; /* RPC client to talk to peer */
|
||||||
char * h_name; /* remote hostname */
|
char * h_name; /* remote hostname */
|
||||||
u32 h_version; /* interface version */
|
u32 h_version; /* interface version */
|
||||||
|
@ -61,17 +64,55 @@ struct nlm_host {
|
||||||
struct list_head h_granted; /* Locks in GRANTED state */
|
struct list_head h_granted; /* Locks in GRANTED state */
|
||||||
struct list_head h_reclaim; /* Locks in RECLAIM state */
|
struct list_head h_reclaim; /* Locks in RECLAIM state */
|
||||||
struct nsm_handle * h_nsmhandle; /* NSM status handle */
|
struct nsm_handle * h_nsmhandle; /* NSM status handle */
|
||||||
|
|
||||||
|
char h_addrbuf[48], /* address eyecatchers */
|
||||||
|
h_srcaddrbuf[48];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct nsm_handle {
|
struct nsm_handle {
|
||||||
struct list_head sm_link;
|
struct list_head sm_link;
|
||||||
atomic_t sm_count;
|
atomic_t sm_count;
|
||||||
char * sm_name;
|
char * sm_name;
|
||||||
struct sockaddr_in sm_addr;
|
struct sockaddr_storage sm_addr;
|
||||||
|
size_t sm_addrlen;
|
||||||
unsigned int sm_monitored : 1,
|
unsigned int sm_monitored : 1,
|
||||||
sm_sticky : 1; /* don't unmonitor */
|
sm_sticky : 1; /* don't unmonitor */
|
||||||
|
char sm_addrbuf[48]; /* address eyecatcher */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Rigorous type checking on sockaddr type conversions
|
||||||
|
*/
|
||||||
|
static inline struct sockaddr_in *nlm_addr_in(const struct nlm_host *host)
|
||||||
|
{
|
||||||
|
return (struct sockaddr_in *)&host->h_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct sockaddr *nlm_addr(const struct nlm_host *host)
|
||||||
|
{
|
||||||
|
return (struct sockaddr *)&host->h_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct sockaddr_in *nlm_srcaddr_in(const struct nlm_host *host)
|
||||||
|
{
|
||||||
|
return (struct sockaddr_in *)&host->h_srcaddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
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"
|
* Map an fl_owner_t into a unique 32-bit "pid"
|
||||||
*/
|
*/
|
||||||
|
@ -166,7 +207,8 @@ int nlm_async_reply(struct nlm_rqst *, u32, const struct rpc_call_ops *);
|
||||||
struct nlm_wait * nlmclnt_prepare_block(struct nlm_host *host, struct file_lock *fl);
|
struct nlm_wait * nlmclnt_prepare_block(struct nlm_host *host, struct file_lock *fl);
|
||||||
void nlmclnt_finish_block(struct nlm_wait *block);
|
void nlmclnt_finish_block(struct nlm_wait *block);
|
||||||
int nlmclnt_block(struct nlm_wait *block, struct nlm_rqst *req, long timeout);
|
int nlmclnt_block(struct nlm_wait *block, struct nlm_rqst *req, long timeout);
|
||||||
__be32 nlmclnt_grant(const struct sockaddr_in *addr, const struct nlm_lock *);
|
__be32 nlmclnt_grant(const struct sockaddr *addr,
|
||||||
|
const struct nlm_lock *lock);
|
||||||
void nlmclnt_recovery(struct nlm_host *);
|
void nlmclnt_recovery(struct nlm_host *);
|
||||||
int nlmclnt_reclaim(struct nlm_host *, struct file_lock *);
|
int nlmclnt_reclaim(struct nlm_host *, struct file_lock *);
|
||||||
void nlmclnt_next_cookie(struct nlm_cookie *);
|
void nlmclnt_next_cookie(struct nlm_cookie *);
|
||||||
|
@ -174,12 +216,14 @@ void nlmclnt_next_cookie(struct nlm_cookie *);
|
||||||
/*
|
/*
|
||||||
* Host cache
|
* Host cache
|
||||||
*/
|
*/
|
||||||
struct nlm_host *nlmclnt_lookup_host(const struct sockaddr_in *sin,
|
struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap,
|
||||||
int proto, u32 version,
|
const size_t salen,
|
||||||
|
const unsigned short protocol,
|
||||||
|
const u32 version,
|
||||||
|
const char *hostname);
|
||||||
|
struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp,
|
||||||
const char *hostname,
|
const char *hostname,
|
||||||
unsigned int hostname_len);
|
const size_t hostname_len);
|
||||||
struct nlm_host *nlmsvc_lookup_host(struct svc_rqst *, const char *,
|
|
||||||
unsigned int);
|
|
||||||
struct rpc_clnt * nlm_bind_host(struct nlm_host *);
|
struct rpc_clnt * nlm_bind_host(struct nlm_host *);
|
||||||
void nlm_rebind_host(struct nlm_host *);
|
void nlm_rebind_host(struct nlm_host *);
|
||||||
struct nlm_host * nlm_get_host(struct nlm_host *);
|
struct nlm_host * nlm_get_host(struct nlm_host *);
|
||||||
|
@ -201,7 +245,7 @@ typedef int (*nlm_host_match_fn_t)(void *cur, struct nlm_host *ref);
|
||||||
*/
|
*/
|
||||||
__be32 nlmsvc_lock(struct svc_rqst *, struct nlm_file *,
|
__be32 nlmsvc_lock(struct svc_rqst *, struct nlm_file *,
|
||||||
struct nlm_host *, struct nlm_lock *, int,
|
struct nlm_host *, struct nlm_lock *, int,
|
||||||
struct nlm_cookie *);
|
struct nlm_cookie *, int);
|
||||||
__be32 nlmsvc_unlock(struct nlm_file *, struct nlm_lock *);
|
__be32 nlmsvc_unlock(struct nlm_file *, struct nlm_lock *);
|
||||||
__be32 nlmsvc_testlock(struct svc_rqst *, struct nlm_file *,
|
__be32 nlmsvc_testlock(struct svc_rqst *, struct nlm_file *,
|
||||||
struct nlm_host *, struct nlm_lock *,
|
struct nlm_host *, struct nlm_lock *,
|
||||||
|
@ -233,15 +277,82 @@ static inline struct inode *nlmsvc_file_inode(struct nlm_file *file)
|
||||||
return file->f_file->f_path.dentry->d_inode;
|
return file->f_file->f_path.dentry->d_inode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static inline int __nlm_privileged_request4(const struct sockaddr *sap)
|
||||||
* Compare two host addresses (needs modifying for ipv6)
|
|
||||||
*/
|
|
||||||
static inline int nlm_cmp_addr(const struct sockaddr_in *sin1,
|
|
||||||
const struct sockaddr_in *sin2)
|
|
||||||
{
|
{
|
||||||
|
const struct sockaddr_in *sin = (struct sockaddr_in *)sap;
|
||||||
|
return (sin->sin_addr.s_addr == htonl(INADDR_LOOPBACK)) &&
|
||||||
|
(ntohs(sin->sin_port) < 1024);
|
||||||
|
}
|
||||||
|
|
||||||
|
#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);
|
||||||
|
}
|
||||||
|
#else /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
|
||||||
|
static inline int __nlm_privileged_request6(const struct sockaddr *sap)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ensure incoming requests are from local privileged callers.
|
||||||
|
*
|
||||||
|
* Return TRUE if sender is local and is connecting via a privileged port;
|
||||||
|
* otherwise return FALSE.
|
||||||
|
*/
|
||||||
|
static inline int nlm_privileged_requester(const struct svc_rqst *rqstp)
|
||||||
|
{
|
||||||
|
const struct sockaddr *sap = svc_addr(rqstp);
|
||||||
|
|
||||||
|
switch (sap->sa_family) {
|
||||||
|
case AF_INET:
|
||||||
|
return __nlm_privileged_request4(sap);
|
||||||
|
case AF_INET6:
|
||||||
|
return __nlm_privileged_request6(sap);
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int __nlm_cmp_addr4(const struct sockaddr *sap1,
|
||||||
|
const struct sockaddr *sap2)
|
||||||
|
{
|
||||||
|
const struct sockaddr_in *sin1 = (const struct sockaddr_in *)sap1;
|
||||||
|
const struct sockaddr_in *sin2 = (const struct sockaddr_in *)sap2;
|
||||||
return sin1->sin_addr.s_addr == sin2->sin_addr.s_addr;
|
return sin1->sin_addr.s_addr == sin2->sin_addr.s_addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int __nlm_cmp_addr6(const struct sockaddr *sap1,
|
||||||
|
const struct sockaddr *sap2)
|
||||||
|
{
|
||||||
|
const struct sockaddr_in6 *sin1 = (const struct sockaddr_in6 *)sap1;
|
||||||
|
const struct sockaddr_in6 *sin2 = (const struct sockaddr_in6 *)sap2;
|
||||||
|
return ipv6_addr_equal(&sin1->sin6_addr, &sin2->sin6_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compare two host addresses
|
||||||
|
*
|
||||||
|
* Return TRUE if the addresses are the same; otherwise FALSE.
|
||||||
|
*/
|
||||||
|
static inline int nlm_cmp_addr(const struct sockaddr *sap1,
|
||||||
|
const struct sockaddr *sap2)
|
||||||
|
{
|
||||||
|
if (sap1->sa_family == sap2->sa_family) {
|
||||||
|
switch (sap1->sa_family) {
|
||||||
|
case AF_INET:
|
||||||
|
return __nlm_cmp_addr4(sap1, sap2);
|
||||||
|
case AF_INET6:
|
||||||
|
return __nlm_cmp_addr6(sap1, sap2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Compare two NLM locks.
|
* Compare two NLM locks.
|
||||||
* When the second lock is of type F_UNLCK, this acts like a wildcard.
|
* When the second lock is of type F_UNLCK, this acts like a wildcard.
|
||||||
|
|
|
@ -81,8 +81,6 @@ struct nlm_reboot {
|
||||||
unsigned int len;
|
unsigned int len;
|
||||||
u32 state;
|
u32 state;
|
||||||
__be32 addr;
|
__be32 addr;
|
||||||
__be32 vers;
|
|
||||||
__be32 proto;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
#define NFSD_MAY_LOCK 32
|
#define NFSD_MAY_LOCK 32
|
||||||
#define NFSD_MAY_OWNER_OVERRIDE 64
|
#define NFSD_MAY_OWNER_OVERRIDE 64
|
||||||
#define NFSD_MAY_LOCAL_ACCESS 128 /* IRIX doing local access check on device special file*/
|
#define NFSD_MAY_LOCAL_ACCESS 128 /* IRIX doing local access check on device special file*/
|
||||||
|
#define NFSD_MAY_BYPASS_GSS_ON_ROOT 256
|
||||||
|
|
||||||
#define NFSD_MAY_CREATE (NFSD_MAY_EXEC|NFSD_MAY_WRITE)
|
#define NFSD_MAY_CREATE (NFSD_MAY_EXEC|NFSD_MAY_WRITE)
|
||||||
#define NFSD_MAY_REMOVE (NFSD_MAY_EXEC|NFSD_MAY_WRITE|NFSD_MAY_TRUNC)
|
#define NFSD_MAY_REMOVE (NFSD_MAY_EXEC|NFSD_MAY_WRITE|NFSD_MAY_TRUNC)
|
||||||
|
@ -125,7 +126,7 @@ int nfsd_truncate(struct svc_rqst *, struct svc_fh *,
|
||||||
__be32 nfsd_readdir(struct svc_rqst *, struct svc_fh *,
|
__be32 nfsd_readdir(struct svc_rqst *, struct svc_fh *,
|
||||||
loff_t *, struct readdir_cd *, filldir_t);
|
loff_t *, struct readdir_cd *, filldir_t);
|
||||||
__be32 nfsd_statfs(struct svc_rqst *, struct svc_fh *,
|
__be32 nfsd_statfs(struct svc_rqst *, struct svc_fh *,
|
||||||
struct kstatfs *);
|
struct kstatfs *, int access);
|
||||||
|
|
||||||
int nfsd_notify_change(struct inode *, struct iattr *);
|
int nfsd_notify_change(struct inode *, struct iattr *);
|
||||||
__be32 nfsd_permission(struct svc_rqst *, struct svc_export *,
|
__be32 nfsd_permission(struct svc_rqst *, struct svc_export *,
|
||||||
|
|
|
@ -104,6 +104,7 @@ struct rpc_create_args {
|
||||||
const struct rpc_timeout *timeout;
|
const struct rpc_timeout *timeout;
|
||||||
char *servername;
|
char *servername;
|
||||||
struct rpc_program *program;
|
struct rpc_program *program;
|
||||||
|
u32 prognumber; /* overrides program->number */
|
||||||
u32 version;
|
u32 version;
|
||||||
rpc_authflavor_t authflavor;
|
rpc_authflavor_t authflavor;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
@ -124,10 +125,10 @@ struct rpc_clnt *rpc_clone_client(struct rpc_clnt *);
|
||||||
void rpc_shutdown_client(struct rpc_clnt *);
|
void rpc_shutdown_client(struct rpc_clnt *);
|
||||||
void rpc_release_client(struct rpc_clnt *);
|
void rpc_release_client(struct rpc_clnt *);
|
||||||
|
|
||||||
int rpcb_register(u32, u32, int, unsigned short, int *);
|
int rpcb_register(u32, u32, int, unsigned short);
|
||||||
int rpcb_v4_register(const u32 program, const u32 version,
|
int rpcb_v4_register(const u32 program, const u32 version,
|
||||||
const struct sockaddr *address,
|
const struct sockaddr *address,
|
||||||
const char *netid, int *result);
|
const char *netid);
|
||||||
int rpcb_getport_sync(struct sockaddr_in *, u32, u32, int);
|
int rpcb_getport_sync(struct sockaddr_in *, u32, u32, int);
|
||||||
void rpcb_getport_async(struct rpc_task *);
|
void rpcb_getport_async(struct rpc_task *);
|
||||||
|
|
||||||
|
|
|
@ -66,6 +66,7 @@ struct svc_serv {
|
||||||
struct list_head sv_tempsocks; /* all temporary sockets */
|
struct list_head sv_tempsocks; /* all temporary sockets */
|
||||||
int sv_tmpcnt; /* count of temporary sockets */
|
int sv_tmpcnt; /* count of temporary sockets */
|
||||||
struct timer_list sv_temptimer; /* timer for aging temporary sockets */
|
struct timer_list sv_temptimer; /* timer for aging temporary sockets */
|
||||||
|
sa_family_t sv_family; /* listener's address family */
|
||||||
|
|
||||||
char * sv_name; /* service name */
|
char * sv_name; /* service name */
|
||||||
|
|
||||||
|
@ -265,17 +266,17 @@ struct svc_rqst {
|
||||||
/*
|
/*
|
||||||
* Rigorous type checking on sockaddr type conversions
|
* Rigorous type checking on sockaddr type conversions
|
||||||
*/
|
*/
|
||||||
static inline struct sockaddr_in *svc_addr_in(struct svc_rqst *rqst)
|
static inline struct sockaddr_in *svc_addr_in(const struct svc_rqst *rqst)
|
||||||
{
|
{
|
||||||
return (struct sockaddr_in *) &rqst->rq_addr;
|
return (struct sockaddr_in *) &rqst->rq_addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct sockaddr_in6 *svc_addr_in6(struct svc_rqst *rqst)
|
static inline struct sockaddr_in6 *svc_addr_in6(const struct svc_rqst *rqst)
|
||||||
{
|
{
|
||||||
return (struct sockaddr_in6 *) &rqst->rq_addr;
|
return (struct sockaddr_in6 *) &rqst->rq_addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct sockaddr *svc_addr(struct svc_rqst *rqst)
|
static inline struct sockaddr *svc_addr(const struct svc_rqst *rqst)
|
||||||
{
|
{
|
||||||
return (struct sockaddr *) &rqst->rq_addr;
|
return (struct sockaddr *) &rqst->rq_addr;
|
||||||
}
|
}
|
||||||
|
@ -381,18 +382,20 @@ struct svc_procedure {
|
||||||
/*
|
/*
|
||||||
* Function prototypes.
|
* Function prototypes.
|
||||||
*/
|
*/
|
||||||
struct svc_serv * svc_create(struct svc_program *, unsigned int,
|
struct svc_serv *svc_create(struct svc_program *, unsigned int, sa_family_t,
|
||||||
void (*shutdown)(struct svc_serv *));
|
void (*shutdown)(struct svc_serv *));
|
||||||
struct svc_rqst *svc_prepare_thread(struct svc_serv *serv,
|
struct svc_rqst *svc_prepare_thread(struct svc_serv *serv,
|
||||||
struct svc_pool *pool);
|
struct svc_pool *pool);
|
||||||
void svc_exit_thread(struct svc_rqst *);
|
void svc_exit_thread(struct svc_rqst *);
|
||||||
struct svc_serv * svc_create_pooled(struct svc_program *, unsigned int,
|
struct svc_serv * svc_create_pooled(struct svc_program *, unsigned int,
|
||||||
void (*shutdown)(struct svc_serv*), svc_thread_fn,
|
sa_family_t, void (*shutdown)(struct svc_serv *),
|
||||||
struct module *);
|
svc_thread_fn, struct module *);
|
||||||
int svc_set_num_threads(struct svc_serv *, struct svc_pool *, int);
|
int svc_set_num_threads(struct svc_serv *, struct svc_pool *, int);
|
||||||
void svc_destroy(struct svc_serv *);
|
void svc_destroy(struct svc_serv *);
|
||||||
int svc_process(struct svc_rqst *);
|
int svc_process(struct svc_rqst *);
|
||||||
int svc_register(struct svc_serv *, int, unsigned short);
|
int svc_register(const struct svc_serv *, const unsigned short,
|
||||||
|
const unsigned short);
|
||||||
|
|
||||||
void svc_wake_up(struct svc_serv *);
|
void svc_wake_up(struct svc_serv *);
|
||||||
void svc_reserve(struct svc_rqst *rqstp, int space);
|
void svc_reserve(struct svc_rqst *rqstp, int space);
|
||||||
struct svc_pool * svc_pool_for_cpu(struct svc_serv *serv, int cpu);
|
struct svc_pool * svc_pool_for_cpu(struct svc_serv *serv, int cpu);
|
||||||
|
|
|
@ -72,6 +72,7 @@ extern atomic_t rdma_stat_sq_prod;
|
||||||
*/
|
*/
|
||||||
struct svc_rdma_op_ctxt {
|
struct svc_rdma_op_ctxt {
|
||||||
struct svc_rdma_op_ctxt *read_hdr;
|
struct svc_rdma_op_ctxt *read_hdr;
|
||||||
|
struct svc_rdma_fastreg_mr *frmr;
|
||||||
int hdr_count;
|
int hdr_count;
|
||||||
struct xdr_buf arg;
|
struct xdr_buf arg;
|
||||||
struct list_head dto_q;
|
struct list_head dto_q;
|
||||||
|
@ -103,16 +104,30 @@ struct svc_rdma_chunk_sge {
|
||||||
int start; /* sge no for this chunk */
|
int start; /* sge no for this chunk */
|
||||||
int count; /* sge count for this chunk */
|
int count; /* sge count for this chunk */
|
||||||
};
|
};
|
||||||
|
struct svc_rdma_fastreg_mr {
|
||||||
|
struct ib_mr *mr;
|
||||||
|
void *kva;
|
||||||
|
struct ib_fast_reg_page_list *page_list;
|
||||||
|
int page_list_len;
|
||||||
|
unsigned long access_flags;
|
||||||
|
unsigned long map_len;
|
||||||
|
enum dma_data_direction direction;
|
||||||
|
struct list_head frmr_list;
|
||||||
|
};
|
||||||
struct svc_rdma_req_map {
|
struct svc_rdma_req_map {
|
||||||
|
struct svc_rdma_fastreg_mr *frmr;
|
||||||
unsigned long count;
|
unsigned long count;
|
||||||
union {
|
union {
|
||||||
struct kvec sge[RPCSVC_MAXPAGES];
|
struct kvec sge[RPCSVC_MAXPAGES];
|
||||||
struct svc_rdma_chunk_sge ch[RPCSVC_MAXPAGES];
|
struct svc_rdma_chunk_sge ch[RPCSVC_MAXPAGES];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
#define RDMACTXT_F_FAST_UNREG 1
|
||||||
#define RDMACTXT_F_LAST_CTXT 2
|
#define RDMACTXT_F_LAST_CTXT 2
|
||||||
|
|
||||||
|
#define SVCRDMA_DEVCAP_FAST_REG 1 /* fast mr registration */
|
||||||
|
#define SVCRDMA_DEVCAP_READ_W_INV 2 /* read w/ invalidate */
|
||||||
|
|
||||||
struct svcxprt_rdma {
|
struct svcxprt_rdma {
|
||||||
struct svc_xprt sc_xprt; /* SVC transport structure */
|
struct svc_xprt sc_xprt; /* SVC transport structure */
|
||||||
struct rdma_cm_id *sc_cm_id; /* RDMA connection id */
|
struct rdma_cm_id *sc_cm_id; /* RDMA connection id */
|
||||||
|
@ -136,6 +151,11 @@ struct svcxprt_rdma {
|
||||||
struct ib_cq *sc_rq_cq;
|
struct ib_cq *sc_rq_cq;
|
||||||
struct ib_cq *sc_sq_cq;
|
struct ib_cq *sc_sq_cq;
|
||||||
struct ib_mr *sc_phys_mr; /* MR for server memory */
|
struct ib_mr *sc_phys_mr; /* MR for server memory */
|
||||||
|
u32 sc_dev_caps; /* distilled device caps */
|
||||||
|
u32 sc_dma_lkey; /* local dma key */
|
||||||
|
unsigned int sc_frmr_pg_list_len;
|
||||||
|
struct list_head sc_frmr_q;
|
||||||
|
spinlock_t sc_frmr_q_lock;
|
||||||
|
|
||||||
spinlock_t sc_lock; /* transport lock */
|
spinlock_t sc_lock; /* transport lock */
|
||||||
|
|
||||||
|
@ -192,8 +212,13 @@ extern int svc_rdma_post_recv(struct svcxprt_rdma *);
|
||||||
extern int svc_rdma_create_listen(struct svc_serv *, int, struct sockaddr *);
|
extern int svc_rdma_create_listen(struct svc_serv *, int, struct sockaddr *);
|
||||||
extern struct svc_rdma_op_ctxt *svc_rdma_get_context(struct svcxprt_rdma *);
|
extern struct svc_rdma_op_ctxt *svc_rdma_get_context(struct svcxprt_rdma *);
|
||||||
extern void svc_rdma_put_context(struct svc_rdma_op_ctxt *, int);
|
extern void svc_rdma_put_context(struct svc_rdma_op_ctxt *, int);
|
||||||
|
extern void svc_rdma_unmap_dma(struct svc_rdma_op_ctxt *ctxt);
|
||||||
extern struct svc_rdma_req_map *svc_rdma_get_req_map(void);
|
extern struct svc_rdma_req_map *svc_rdma_get_req_map(void);
|
||||||
extern void svc_rdma_put_req_map(struct svc_rdma_req_map *);
|
extern void svc_rdma_put_req_map(struct svc_rdma_req_map *);
|
||||||
|
extern int svc_rdma_fastreg(struct svcxprt_rdma *, struct svc_rdma_fastreg_mr *);
|
||||||
|
extern struct svc_rdma_fastreg_mr *svc_rdma_get_frmr(struct svcxprt_rdma *);
|
||||||
|
extern void svc_rdma_put_frmr(struct svcxprt_rdma *,
|
||||||
|
struct svc_rdma_fastreg_mr *);
|
||||||
extern void svc_sq_reap(struct svcxprt_rdma *);
|
extern void svc_sq_reap(struct svcxprt_rdma *);
|
||||||
extern void svc_rq_reap(struct svcxprt_rdma *);
|
extern void svc_rq_reap(struct svcxprt_rdma *);
|
||||||
extern struct svc_xprt_class svc_rdma_class;
|
extern struct svc_xprt_class svc_rdma_class;
|
||||||
|
|
|
@ -39,10 +39,7 @@ int svc_send(struct svc_rqst *);
|
||||||
void svc_drop(struct svc_rqst *);
|
void svc_drop(struct svc_rqst *);
|
||||||
void svc_sock_update_bufs(struct svc_serv *serv);
|
void svc_sock_update_bufs(struct svc_serv *serv);
|
||||||
int svc_sock_names(char *buf, struct svc_serv *serv, char *toclose);
|
int svc_sock_names(char *buf, struct svc_serv *serv, char *toclose);
|
||||||
int svc_addsock(struct svc_serv *serv,
|
int svc_addsock(struct svc_serv *serv, int fd, char *name_return);
|
||||||
int fd,
|
|
||||||
char *name_return,
|
|
||||||
int *proto);
|
|
||||||
void svc_init_xprt_sock(void);
|
void svc_init_xprt_sock(void);
|
||||||
void svc_cleanup_xprt_sock(void);
|
void svc_cleanup_xprt_sock(void);
|
||||||
|
|
||||||
|
|
|
@ -125,6 +125,7 @@ cond_syscall(sys_vm86old);
|
||||||
cond_syscall(sys_vm86);
|
cond_syscall(sys_vm86);
|
||||||
cond_syscall(compat_sys_ipc);
|
cond_syscall(compat_sys_ipc);
|
||||||
cond_syscall(compat_sys_sysctl);
|
cond_syscall(compat_sys_sysctl);
|
||||||
|
cond_syscall(sys_flock);
|
||||||
|
|
||||||
/* arch-specific weak syscall entries */
|
/* arch-specific weak syscall entries */
|
||||||
cond_syscall(sys_pciconfig_read);
|
cond_syscall(sys_pciconfig_read);
|
||||||
|
|
|
@ -96,7 +96,7 @@ static int sixty = 60;
|
||||||
static int neg_one = -1;
|
static int neg_one = -1;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_MMU
|
#if defined(CONFIG_MMU) && defined(CONFIG_FILE_LOCKING)
|
||||||
static int two = 2;
|
static int two = 2;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1248,6 +1248,7 @@ static struct ctl_table fs_table[] = {
|
||||||
.extra1 = &minolduid,
|
.extra1 = &minolduid,
|
||||||
.extra2 = &maxolduid,
|
.extra2 = &maxolduid,
|
||||||
},
|
},
|
||||||
|
#ifdef CONFIG_FILE_LOCKING
|
||||||
{
|
{
|
||||||
.ctl_name = FS_LEASES,
|
.ctl_name = FS_LEASES,
|
||||||
.procname = "leases-enable",
|
.procname = "leases-enable",
|
||||||
|
@ -1256,6 +1257,7 @@ static struct ctl_table fs_table[] = {
|
||||||
.mode = 0644,
|
.mode = 0644,
|
||||||
.proc_handler = &proc_dointvec,
|
.proc_handler = &proc_dointvec,
|
||||||
},
|
},
|
||||||
|
#endif
|
||||||
#ifdef CONFIG_DNOTIFY
|
#ifdef CONFIG_DNOTIFY
|
||||||
{
|
{
|
||||||
.ctl_name = FS_DIR_NOTIFY,
|
.ctl_name = FS_DIR_NOTIFY,
|
||||||
|
@ -1267,6 +1269,7 @@ static struct ctl_table fs_table[] = {
|
||||||
},
|
},
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_MMU
|
#ifdef CONFIG_MMU
|
||||||
|
#ifdef CONFIG_FILE_LOCKING
|
||||||
{
|
{
|
||||||
.ctl_name = FS_LEASE_TIME,
|
.ctl_name = FS_LEASE_TIME,
|
||||||
.procname = "lease-break-time",
|
.procname = "lease-break-time",
|
||||||
|
@ -1278,6 +1281,7 @@ static struct ctl_table fs_table[] = {
|
||||||
.extra1 = &zero,
|
.extra1 = &zero,
|
||||||
.extra2 = &two,
|
.extra2 = &two,
|
||||||
},
|
},
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
.procname = "aio-nr",
|
.procname = "aio-nr",
|
||||||
.data = &aio_nr,
|
.data = &aio_nr,
|
||||||
|
|
|
@ -174,7 +174,7 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru
|
||||||
clnt->cl_procinfo = version->procs;
|
clnt->cl_procinfo = version->procs;
|
||||||
clnt->cl_maxproc = version->nrprocs;
|
clnt->cl_maxproc = version->nrprocs;
|
||||||
clnt->cl_protname = program->name;
|
clnt->cl_protname = program->name;
|
||||||
clnt->cl_prog = program->number;
|
clnt->cl_prog = args->prognumber ? : program->number;
|
||||||
clnt->cl_vers = version->number;
|
clnt->cl_vers = version->number;
|
||||||
clnt->cl_stats = program->stats;
|
clnt->cl_stats = program->stats;
|
||||||
clnt->cl_metrics = rpc_alloc_iostats(clnt);
|
clnt->cl_metrics = rpc_alloc_iostats(clnt);
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include <linux/in6.h>
|
#include <linux/in6.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
|
#include <net/ipv6.h>
|
||||||
|
|
||||||
#include <linux/sunrpc/clnt.h>
|
#include <linux/sunrpc/clnt.h>
|
||||||
#include <linux/sunrpc/sched.h>
|
#include <linux/sunrpc/sched.h>
|
||||||
|
@ -176,13 +177,12 @@ static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr,
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rpcb_register_call(struct sockaddr *addr, size_t addrlen,
|
static int rpcb_register_call(struct sockaddr *addr, size_t addrlen,
|
||||||
u32 version, struct rpc_message *msg,
|
u32 version, struct rpc_message *msg)
|
||||||
int *result)
|
|
||||||
{
|
{
|
||||||
struct rpc_clnt *rpcb_clnt;
|
struct rpc_clnt *rpcb_clnt;
|
||||||
int error = 0;
|
int result, error = 0;
|
||||||
|
|
||||||
*result = 0;
|
msg->rpc_resp = &result;
|
||||||
|
|
||||||
rpcb_clnt = rpcb_create_local(addr, addrlen, version);
|
rpcb_clnt = rpcb_create_local(addr, addrlen, version);
|
||||||
if (!IS_ERR(rpcb_clnt)) {
|
if (!IS_ERR(rpcb_clnt)) {
|
||||||
|
@ -191,21 +191,28 @@ static int rpcb_register_call(struct sockaddr *addr, size_t addrlen,
|
||||||
} else
|
} else
|
||||||
error = PTR_ERR(rpcb_clnt);
|
error = PTR_ERR(rpcb_clnt);
|
||||||
|
|
||||||
if (error < 0)
|
if (error < 0) {
|
||||||
printk(KERN_WARNING "RPC: failed to contact local rpcbind "
|
printk(KERN_WARNING "RPC: failed to contact local rpcbind "
|
||||||
"server (errno %d).\n", -error);
|
"server (errno %d).\n", -error);
|
||||||
dprintk("RPC: registration status %d/%d\n", error, *result);
|
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!result)
|
||||||
|
return -EACCES;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* rpcb_register - set or unset a port registration with the local rpcbind svc
|
* rpcb_register - set or unset a port registration with the local rpcbind svc
|
||||||
* @prog: RPC program number to bind
|
* @prog: RPC program number to bind
|
||||||
* @vers: RPC version number to bind
|
* @vers: RPC version number to bind
|
||||||
* @prot: transport protocol to register
|
* @prot: transport protocol to register
|
||||||
* @port: port value to register
|
* @port: port value to register
|
||||||
* @okay: OUT: result code
|
*
|
||||||
|
* Returns zero if the registration request was dispatched successfully
|
||||||
|
* and the rpcbind daemon returned success. Otherwise, returns an errno
|
||||||
|
* value that reflects the nature of the error (request could not be
|
||||||
|
* dispatched, timed out, or rpcbind returned an error).
|
||||||
*
|
*
|
||||||
* RPC services invoke this function to advertise their contact
|
* RPC services invoke this function to advertise their contact
|
||||||
* information via the system's rpcbind daemon. RPC services
|
* information via the system's rpcbind daemon. RPC services
|
||||||
|
@ -217,15 +224,6 @@ static int rpcb_register_call(struct sockaddr *addr, size_t addrlen,
|
||||||
* all registered transports for [program, version] from the local
|
* all registered transports for [program, version] from the local
|
||||||
* rpcbind database.
|
* rpcbind database.
|
||||||
*
|
*
|
||||||
* Returns zero if the registration request was dispatched
|
|
||||||
* successfully and a reply was received. The rpcbind daemon's
|
|
||||||
* boolean result code is stored in *okay.
|
|
||||||
*
|
|
||||||
* Returns an errno value and sets *result to zero if there was
|
|
||||||
* some problem that prevented the rpcbind request from being
|
|
||||||
* dispatched, or if the rpcbind daemon did not respond within
|
|
||||||
* the timeout.
|
|
||||||
*
|
|
||||||
* This function uses rpcbind protocol version 2 to contact the
|
* This function uses rpcbind protocol version 2 to contact the
|
||||||
* local rpcbind daemon.
|
* local rpcbind daemon.
|
||||||
*
|
*
|
||||||
|
@ -236,7 +234,7 @@ static int rpcb_register_call(struct sockaddr *addr, size_t addrlen,
|
||||||
* IN6ADDR_ANY (ie available for all AF_INET and AF_INET6
|
* IN6ADDR_ANY (ie available for all AF_INET and AF_INET6
|
||||||
* addresses).
|
* addresses).
|
||||||
*/
|
*/
|
||||||
int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay)
|
int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port)
|
||||||
{
|
{
|
||||||
struct rpcbind_args map = {
|
struct rpcbind_args map = {
|
||||||
.r_prog = prog,
|
.r_prog = prog,
|
||||||
|
@ -246,7 +244,6 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay)
|
||||||
};
|
};
|
||||||
struct rpc_message msg = {
|
struct rpc_message msg = {
|
||||||
.rpc_argp = &map,
|
.rpc_argp = &map,
|
||||||
.rpc_resp = okay,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
dprintk("RPC: %sregistering (%u, %u, %d, %u) with local "
|
dprintk("RPC: %sregistering (%u, %u, %d, %u) with local "
|
||||||
|
@ -259,7 +256,7 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay)
|
||||||
|
|
||||||
return rpcb_register_call((struct sockaddr *)&rpcb_inaddr_loopback,
|
return rpcb_register_call((struct sockaddr *)&rpcb_inaddr_loopback,
|
||||||
sizeof(rpcb_inaddr_loopback),
|
sizeof(rpcb_inaddr_loopback),
|
||||||
RPCBVERS_2, &msg, okay);
|
RPCBVERS_2, &msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -290,7 +287,7 @@ static int rpcb_register_netid4(struct sockaddr_in *address_to_register,
|
||||||
|
|
||||||
return rpcb_register_call((struct sockaddr *)&rpcb_inaddr_loopback,
|
return rpcb_register_call((struct sockaddr *)&rpcb_inaddr_loopback,
|
||||||
sizeof(rpcb_inaddr_loopback),
|
sizeof(rpcb_inaddr_loopback),
|
||||||
RPCBVERS_4, msg, msg->rpc_resp);
|
RPCBVERS_4, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -304,8 +301,11 @@ static int rpcb_register_netid6(struct sockaddr_in6 *address_to_register,
|
||||||
char buf[64];
|
char buf[64];
|
||||||
|
|
||||||
/* Construct AF_INET6 universal address */
|
/* Construct AF_INET6 universal address */
|
||||||
snprintf(buf, sizeof(buf),
|
if (ipv6_addr_any(&address_to_register->sin6_addr))
|
||||||
NIP6_FMT".%u.%u",
|
snprintf(buf, sizeof(buf), "::.%u.%u",
|
||||||
|
port >> 8, port & 0xff);
|
||||||
|
else
|
||||||
|
snprintf(buf, sizeof(buf), NIP6_FMT".%u.%u",
|
||||||
NIP6(address_to_register->sin6_addr),
|
NIP6(address_to_register->sin6_addr),
|
||||||
port >> 8, port & 0xff);
|
port >> 8, port & 0xff);
|
||||||
map->r_addr = buf;
|
map->r_addr = buf;
|
||||||
|
@ -321,7 +321,7 @@ static int rpcb_register_netid6(struct sockaddr_in6 *address_to_register,
|
||||||
|
|
||||||
return rpcb_register_call((struct sockaddr *)&rpcb_in6addr_loopback,
|
return rpcb_register_call((struct sockaddr *)&rpcb_in6addr_loopback,
|
||||||
sizeof(rpcb_in6addr_loopback),
|
sizeof(rpcb_in6addr_loopback),
|
||||||
RPCBVERS_4, msg, msg->rpc_resp);
|
RPCBVERS_4, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -330,7 +330,11 @@ static int rpcb_register_netid6(struct sockaddr_in6 *address_to_register,
|
||||||
* @version: RPC version number of service to (un)register
|
* @version: RPC version number of service to (un)register
|
||||||
* @address: address family, IP address, and port to (un)register
|
* @address: address family, IP address, and port to (un)register
|
||||||
* @netid: netid of transport protocol to (un)register
|
* @netid: netid of transport protocol to (un)register
|
||||||
* @result: result code from rpcbind RPC call
|
*
|
||||||
|
* Returns zero if the registration request was dispatched successfully
|
||||||
|
* and the rpcbind daemon returned success. Otherwise, returns an errno
|
||||||
|
* value that reflects the nature of the error (request could not be
|
||||||
|
* dispatched, timed out, or rpcbind returned an error).
|
||||||
*
|
*
|
||||||
* RPC services invoke this function to advertise their contact
|
* RPC services invoke this function to advertise their contact
|
||||||
* information via the system's rpcbind daemon. RPC services
|
* information via the system's rpcbind daemon. RPC services
|
||||||
|
@ -342,15 +346,6 @@ static int rpcb_register_netid6(struct sockaddr_in6 *address_to_register,
|
||||||
* to zero. Callers pass a netid of "" to unregister all
|
* to zero. Callers pass a netid of "" to unregister all
|
||||||
* transport netids associated with [program, version, address].
|
* transport netids associated with [program, version, address].
|
||||||
*
|
*
|
||||||
* Returns zero if the registration request was dispatched
|
|
||||||
* successfully and a reply was received. The rpcbind daemon's
|
|
||||||
* result code is stored in *result.
|
|
||||||
*
|
|
||||||
* Returns an errno value and sets *result to zero if there was
|
|
||||||
* some problem that prevented the rpcbind request from being
|
|
||||||
* dispatched, or if the rpcbind daemon did not respond within
|
|
||||||
* the timeout.
|
|
||||||
*
|
|
||||||
* This function uses rpcbind protocol version 4 to contact the
|
* This function uses rpcbind protocol version 4 to contact the
|
||||||
* local rpcbind daemon. The local rpcbind daemon must support
|
* local rpcbind daemon. The local rpcbind daemon must support
|
||||||
* version 4 of the rpcbind protocol in order for these functions
|
* version 4 of the rpcbind protocol in order for these functions
|
||||||
|
@ -372,8 +367,7 @@ static int rpcb_register_netid6(struct sockaddr_in6 *address_to_register,
|
||||||
* advertises the service on all IPv4 and IPv6 addresses.
|
* advertises the service on all IPv4 and IPv6 addresses.
|
||||||
*/
|
*/
|
||||||
int rpcb_v4_register(const u32 program, const u32 version,
|
int rpcb_v4_register(const u32 program, const u32 version,
|
||||||
const struct sockaddr *address, const char *netid,
|
const struct sockaddr *address, const char *netid)
|
||||||
int *result)
|
|
||||||
{
|
{
|
||||||
struct rpcbind_args map = {
|
struct rpcbind_args map = {
|
||||||
.r_prog = program,
|
.r_prog = program,
|
||||||
|
@ -383,11 +377,8 @@ int rpcb_v4_register(const u32 program, const u32 version,
|
||||||
};
|
};
|
||||||
struct rpc_message msg = {
|
struct rpc_message msg = {
|
||||||
.rpc_argp = &map,
|
.rpc_argp = &map,
|
||||||
.rpc_resp = result,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
*result = 0;
|
|
||||||
|
|
||||||
switch (address->sa_family) {
|
switch (address->sa_family) {
|
||||||
case AF_INET:
|
case AF_INET:
|
||||||
return rpcb_register_netid4((struct sockaddr_in *)address,
|
return rpcb_register_netid4((struct sockaddr_in *)address,
|
||||||
|
@ -633,7 +624,7 @@ static void rpcb_getport_done(struct rpc_task *child, void *data)
|
||||||
static int rpcb_encode_mapping(struct rpc_rqst *req, __be32 *p,
|
static int rpcb_encode_mapping(struct rpc_rqst *req, __be32 *p,
|
||||||
struct rpcbind_args *rpcb)
|
struct rpcbind_args *rpcb)
|
||||||
{
|
{
|
||||||
dprintk("RPC: rpcb_encode_mapping(%u, %u, %d, %u)\n",
|
dprintk("RPC: encoding rpcb request (%u, %u, %d, %u)\n",
|
||||||
rpcb->r_prog, rpcb->r_vers, rpcb->r_prot, rpcb->r_port);
|
rpcb->r_prog, rpcb->r_vers, rpcb->r_prot, rpcb->r_port);
|
||||||
*p++ = htonl(rpcb->r_prog);
|
*p++ = htonl(rpcb->r_prog);
|
||||||
*p++ = htonl(rpcb->r_vers);
|
*p++ = htonl(rpcb->r_vers);
|
||||||
|
@ -648,7 +639,7 @@ static int rpcb_decode_getport(struct rpc_rqst *req, __be32 *p,
|
||||||
unsigned short *portp)
|
unsigned short *portp)
|
||||||
{
|
{
|
||||||
*portp = (unsigned short) ntohl(*p++);
|
*portp = (unsigned short) ntohl(*p++);
|
||||||
dprintk("RPC: rpcb_decode_getport result %u\n",
|
dprintk("RPC: rpcb getport result: %u\n",
|
||||||
*portp);
|
*portp);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -657,7 +648,7 @@ static int rpcb_decode_set(struct rpc_rqst *req, __be32 *p,
|
||||||
unsigned int *boolp)
|
unsigned int *boolp)
|
||||||
{
|
{
|
||||||
*boolp = (unsigned int) ntohl(*p++);
|
*boolp = (unsigned int) ntohl(*p++);
|
||||||
dprintk("RPC: rpcb_decode_set: call %s\n",
|
dprintk("RPC: rpcb set/unset call %s\n",
|
||||||
(*boolp ? "succeeded" : "failed"));
|
(*boolp ? "succeeded" : "failed"));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -665,7 +656,7 @@ static int rpcb_decode_set(struct rpc_rqst *req, __be32 *p,
|
||||||
static int rpcb_encode_getaddr(struct rpc_rqst *req, __be32 *p,
|
static int rpcb_encode_getaddr(struct rpc_rqst *req, __be32 *p,
|
||||||
struct rpcbind_args *rpcb)
|
struct rpcbind_args *rpcb)
|
||||||
{
|
{
|
||||||
dprintk("RPC: rpcb_encode_getaddr(%u, %u, %s)\n",
|
dprintk("RPC: encoding rpcb request (%u, %u, %s)\n",
|
||||||
rpcb->r_prog, rpcb->r_vers, rpcb->r_addr);
|
rpcb->r_prog, rpcb->r_vers, rpcb->r_addr);
|
||||||
*p++ = htonl(rpcb->r_prog);
|
*p++ = htonl(rpcb->r_prog);
|
||||||
*p++ = htonl(rpcb->r_vers);
|
*p++ = htonl(rpcb->r_vers);
|
||||||
|
|
253
net/sunrpc/svc.c
253
net/sunrpc/svc.c
|
@ -28,6 +28,8 @@
|
||||||
|
|
||||||
#define RPCDBG_FACILITY RPCDBG_SVCDSP
|
#define RPCDBG_FACILITY RPCDBG_SVCDSP
|
||||||
|
|
||||||
|
static void svc_unregister(const struct svc_serv *serv);
|
||||||
|
|
||||||
#define svc_serv_is_pooled(serv) ((serv)->sv_function)
|
#define svc_serv_is_pooled(serv) ((serv)->sv_function)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -357,7 +359,7 @@ svc_pool_for_cpu(struct svc_serv *serv, int cpu)
|
||||||
*/
|
*/
|
||||||
static struct svc_serv *
|
static struct svc_serv *
|
||||||
__svc_create(struct svc_program *prog, unsigned int bufsize, int npools,
|
__svc_create(struct svc_program *prog, unsigned int bufsize, int npools,
|
||||||
void (*shutdown)(struct svc_serv *serv))
|
sa_family_t family, void (*shutdown)(struct svc_serv *serv))
|
||||||
{
|
{
|
||||||
struct svc_serv *serv;
|
struct svc_serv *serv;
|
||||||
unsigned int vers;
|
unsigned int vers;
|
||||||
|
@ -366,6 +368,7 @@ __svc_create(struct svc_program *prog, unsigned int bufsize, int npools,
|
||||||
|
|
||||||
if (!(serv = kzalloc(sizeof(*serv), GFP_KERNEL)))
|
if (!(serv = kzalloc(sizeof(*serv), GFP_KERNEL)))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
serv->sv_family = family;
|
||||||
serv->sv_name = prog->pg_name;
|
serv->sv_name = prog->pg_name;
|
||||||
serv->sv_program = prog;
|
serv->sv_program = prog;
|
||||||
serv->sv_nrthreads = 1;
|
serv->sv_nrthreads = 1;
|
||||||
|
@ -416,30 +419,29 @@ __svc_create(struct svc_program *prog, unsigned int bufsize, int npools,
|
||||||
spin_lock_init(&pool->sp_lock);
|
spin_lock_init(&pool->sp_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Remove any stale portmap registrations */
|
/* Remove any stale portmap registrations */
|
||||||
svc_register(serv, 0, 0);
|
svc_unregister(serv);
|
||||||
|
|
||||||
return serv;
|
return serv;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct svc_serv *
|
struct svc_serv *
|
||||||
svc_create(struct svc_program *prog, unsigned int bufsize,
|
svc_create(struct svc_program *prog, unsigned int bufsize,
|
||||||
void (*shutdown)(struct svc_serv *serv))
|
sa_family_t family, void (*shutdown)(struct svc_serv *serv))
|
||||||
{
|
{
|
||||||
return __svc_create(prog, bufsize, /*npools*/1, shutdown);
|
return __svc_create(prog, bufsize, /*npools*/1, family, shutdown);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(svc_create);
|
EXPORT_SYMBOL(svc_create);
|
||||||
|
|
||||||
struct svc_serv *
|
struct svc_serv *
|
||||||
svc_create_pooled(struct svc_program *prog, unsigned int bufsize,
|
svc_create_pooled(struct svc_program *prog, unsigned int bufsize,
|
||||||
void (*shutdown)(struct svc_serv *serv),
|
sa_family_t family, void (*shutdown)(struct svc_serv *serv),
|
||||||
svc_thread_fn func, struct module *mod)
|
svc_thread_fn func, struct module *mod)
|
||||||
{
|
{
|
||||||
struct svc_serv *serv;
|
struct svc_serv *serv;
|
||||||
unsigned int npools = svc_pool_map_get();
|
unsigned int npools = svc_pool_map_get();
|
||||||
|
|
||||||
serv = __svc_create(prog, bufsize, npools, shutdown);
|
serv = __svc_create(prog, bufsize, npools, family, shutdown);
|
||||||
|
|
||||||
if (serv != NULL) {
|
if (serv != NULL) {
|
||||||
serv->sv_function = func;
|
serv->sv_function = func;
|
||||||
|
@ -486,8 +488,7 @@ svc_destroy(struct svc_serv *serv)
|
||||||
if (svc_serv_is_pooled(serv))
|
if (svc_serv_is_pooled(serv))
|
||||||
svc_pool_map_put();
|
svc_pool_map_put();
|
||||||
|
|
||||||
/* Unregister service with the portmapper */
|
svc_unregister(serv);
|
||||||
svc_register(serv, 0, 0);
|
|
||||||
kfree(serv->sv_pools);
|
kfree(serv->sv_pools);
|
||||||
kfree(serv);
|
kfree(serv);
|
||||||
}
|
}
|
||||||
|
@ -718,57 +719,247 @@ svc_exit_thread(struct svc_rqst *rqstp)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(svc_exit_thread);
|
EXPORT_SYMBOL(svc_exit_thread);
|
||||||
|
|
||||||
|
#ifdef CONFIG_SUNRPC_REGISTER_V4
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Register an RPC service with the local portmapper.
|
* Register an "inet" protocol family netid with the local
|
||||||
* To unregister a service, call this routine with
|
* rpcbind daemon via an rpcbind v4 SET request.
|
||||||
* proto and port == 0.
|
*
|
||||||
|
* No netconfig infrastructure is available in the kernel, so
|
||||||
|
* we map IP_ protocol numbers to netids by hand.
|
||||||
|
*
|
||||||
|
* Returns zero on success; a negative errno value is returned
|
||||||
|
* if any error occurs.
|
||||||
*/
|
*/
|
||||||
int
|
static int __svc_rpcb_register4(const u32 program, const u32 version,
|
||||||
svc_register(struct svc_serv *serv, int proto, unsigned short port)
|
const unsigned short protocol,
|
||||||
|
const unsigned short port)
|
||||||
|
{
|
||||||
|
struct sockaddr_in sin = {
|
||||||
|
.sin_family = AF_INET,
|
||||||
|
.sin_addr.s_addr = htonl(INADDR_ANY),
|
||||||
|
.sin_port = htons(port),
|
||||||
|
};
|
||||||
|
char *netid;
|
||||||
|
|
||||||
|
switch (protocol) {
|
||||||
|
case IPPROTO_UDP:
|
||||||
|
netid = RPCBIND_NETID_UDP;
|
||||||
|
break;
|
||||||
|
case IPPROTO_TCP:
|
||||||
|
netid = RPCBIND_NETID_TCP;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EPROTONOSUPPORT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rpcb_v4_register(program, version,
|
||||||
|
(struct sockaddr *)&sin, netid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Register an "inet6" protocol family netid with the local
|
||||||
|
* rpcbind daemon via an rpcbind v4 SET request.
|
||||||
|
*
|
||||||
|
* No netconfig infrastructure is available in the kernel, so
|
||||||
|
* we map IP_ protocol numbers to netids by hand.
|
||||||
|
*
|
||||||
|
* Returns zero on success; a negative errno value is returned
|
||||||
|
* if any error occurs.
|
||||||
|
*/
|
||||||
|
static int __svc_rpcb_register6(const u32 program, const u32 version,
|
||||||
|
const unsigned short protocol,
|
||||||
|
const unsigned short port)
|
||||||
|
{
|
||||||
|
struct sockaddr_in6 sin6 = {
|
||||||
|
.sin6_family = AF_INET6,
|
||||||
|
.sin6_addr = IN6ADDR_ANY_INIT,
|
||||||
|
.sin6_port = htons(port),
|
||||||
|
};
|
||||||
|
char *netid;
|
||||||
|
|
||||||
|
switch (protocol) {
|
||||||
|
case IPPROTO_UDP:
|
||||||
|
netid = RPCBIND_NETID_UDP6;
|
||||||
|
break;
|
||||||
|
case IPPROTO_TCP:
|
||||||
|
netid = RPCBIND_NETID_TCP6;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EPROTONOSUPPORT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rpcb_v4_register(program, version,
|
||||||
|
(struct sockaddr *)&sin6, netid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Register a kernel RPC service via rpcbind version 4.
|
||||||
|
*
|
||||||
|
* Returns zero on success; a negative errno value is returned
|
||||||
|
* if any error occurs.
|
||||||
|
*/
|
||||||
|
static int __svc_register(const u32 program, const u32 version,
|
||||||
|
const sa_family_t family,
|
||||||
|
const unsigned short protocol,
|
||||||
|
const unsigned short port)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
|
||||||
|
switch (family) {
|
||||||
|
case AF_INET:
|
||||||
|
return __svc_rpcb_register4(program, version,
|
||||||
|
protocol, port);
|
||||||
|
case AF_INET6:
|
||||||
|
error = __svc_rpcb_register6(program, version,
|
||||||
|
protocol, port);
|
||||||
|
if (error < 0)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Work around bug in some versions of Linux rpcbind
|
||||||
|
* which don't allow registration of both inet and
|
||||||
|
* inet6 netids.
|
||||||
|
*
|
||||||
|
* Error return ignored for now.
|
||||||
|
*/
|
||||||
|
__svc_rpcb_register4(program, version,
|
||||||
|
protocol, port);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -EAFNOSUPPORT;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* CONFIG_SUNRPC_REGISTER_V4 */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Register a kernel RPC service via rpcbind version 2.
|
||||||
|
*
|
||||||
|
* Returns zero on success; a negative errno value is returned
|
||||||
|
* if any error occurs.
|
||||||
|
*/
|
||||||
|
static int __svc_register(const u32 program, const u32 version,
|
||||||
|
sa_family_t family,
|
||||||
|
const unsigned short protocol,
|
||||||
|
const unsigned short port)
|
||||||
|
{
|
||||||
|
if (family != AF_INET)
|
||||||
|
return -EAFNOSUPPORT;
|
||||||
|
|
||||||
|
return rpcb_register(program, version, protocol, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_SUNRPC_REGISTER_V4 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* svc_register - register an RPC service with the local portmapper
|
||||||
|
* @serv: svc_serv struct for the service to register
|
||||||
|
* @proto: transport protocol number to advertise
|
||||||
|
* @port: port to advertise
|
||||||
|
*
|
||||||
|
* Service is registered for any address in serv's address family
|
||||||
|
*/
|
||||||
|
int svc_register(const struct svc_serv *serv, const unsigned short proto,
|
||||||
|
const unsigned short port)
|
||||||
{
|
{
|
||||||
struct svc_program *progp;
|
struct svc_program *progp;
|
||||||
unsigned long flags;
|
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
int error = 0, dummy;
|
int error = 0;
|
||||||
|
|
||||||
if (!port)
|
BUG_ON(proto == 0 && port == 0);
|
||||||
clear_thread_flag(TIF_SIGPENDING);
|
|
||||||
|
|
||||||
for (progp = serv->sv_program; progp; progp = progp->pg_next) {
|
for (progp = serv->sv_program; progp; progp = progp->pg_next) {
|
||||||
for (i = 0; i < progp->pg_nvers; i++) {
|
for (i = 0; i < progp->pg_nvers; i++) {
|
||||||
if (progp->pg_vers[i] == NULL)
|
if (progp->pg_vers[i] == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
dprintk("svc: svc_register(%s, %s, %d, %d)%s\n",
|
dprintk("svc: svc_register(%sv%d, %s, %u, %u)%s\n",
|
||||||
progp->pg_name,
|
progp->pg_name,
|
||||||
|
i,
|
||||||
proto == IPPROTO_UDP? "udp" : "tcp",
|
proto == IPPROTO_UDP? "udp" : "tcp",
|
||||||
port,
|
port,
|
||||||
i,
|
serv->sv_family,
|
||||||
progp->pg_vers[i]->vs_hidden?
|
progp->pg_vers[i]->vs_hidden?
|
||||||
" (but not telling portmap)" : "");
|
" (but not telling portmap)" : "");
|
||||||
|
|
||||||
if (progp->pg_vers[i]->vs_hidden)
|
if (progp->pg_vers[i]->vs_hidden)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
error = rpcb_register(progp->pg_prog, i, proto, port, &dummy);
|
error = __svc_register(progp->pg_prog, i,
|
||||||
|
serv->sv_family, proto, port);
|
||||||
if (error < 0)
|
if (error < 0)
|
||||||
break;
|
break;
|
||||||
if (port && !dummy) {
|
|
||||||
error = -EACCES;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!port) {
|
|
||||||
spin_lock_irqsave(¤t->sighand->siglock, flags);
|
|
||||||
recalc_sigpending();
|
|
||||||
spin_unlock_irqrestore(¤t->sighand->siglock, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_SUNRPC_REGISTER_V4
|
||||||
|
|
||||||
|
static void __svc_unregister(const u32 program, const u32 version,
|
||||||
|
const char *progname)
|
||||||
|
{
|
||||||
|
struct sockaddr_in6 sin6 = {
|
||||||
|
.sin6_family = AF_INET6,
|
||||||
|
.sin6_addr = IN6ADDR_ANY_INIT,
|
||||||
|
.sin6_port = 0,
|
||||||
|
};
|
||||||
|
int error;
|
||||||
|
|
||||||
|
error = rpcb_v4_register(program, version,
|
||||||
|
(struct sockaddr *)&sin6, "");
|
||||||
|
dprintk("svc: %s(%sv%u), error %d\n",
|
||||||
|
__func__, progname, version, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* CONFIG_SUNRPC_REGISTER_V4 */
|
||||||
|
|
||||||
|
static void __svc_unregister(const u32 program, const u32 version,
|
||||||
|
const char *progname)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
|
||||||
|
error = rpcb_register(program, version, 0, 0);
|
||||||
|
dprintk("svc: %s(%sv%u), error %d\n",
|
||||||
|
__func__, progname, version, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_SUNRPC_REGISTER_V4 */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* All netids, bind addresses and ports registered for [program, version]
|
||||||
|
* are removed from the local rpcbind database (if the service is not
|
||||||
|
* hidden) to make way for a new instance of the service.
|
||||||
|
*
|
||||||
|
* The result of unregistration is reported via dprintk for those who want
|
||||||
|
* verification of the result, but is otherwise not important.
|
||||||
|
*/
|
||||||
|
static void svc_unregister(const struct svc_serv *serv)
|
||||||
|
{
|
||||||
|
struct svc_program *progp;
|
||||||
|
unsigned long flags;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
clear_thread_flag(TIF_SIGPENDING);
|
||||||
|
|
||||||
|
for (progp = serv->sv_program; progp; progp = progp->pg_next) {
|
||||||
|
for (i = 0; i < progp->pg_nvers; i++) {
|
||||||
|
if (progp->pg_vers[i] == NULL)
|
||||||
|
continue;
|
||||||
|
if (progp->pg_vers[i]->vs_hidden)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
__svc_unregister(progp->pg_prog, i, progp->pg_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spin_lock_irqsave(¤t->sighand->siglock, flags);
|
||||||
|
recalc_sigpending();
|
||||||
|
spin_unlock_irqrestore(¤t->sighand->siglock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Printk the given error with the address of the client that caused it.
|
* Printk the given error with the address of the client that caused it.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -159,15 +159,44 @@ void svc_xprt_init(struct svc_xprt_class *xcl, struct svc_xprt *xprt,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(svc_xprt_init);
|
EXPORT_SYMBOL_GPL(svc_xprt_init);
|
||||||
|
|
||||||
int svc_create_xprt(struct svc_serv *serv, char *xprt_name, unsigned short port,
|
static struct svc_xprt *__svc_xpo_create(struct svc_xprt_class *xcl,
|
||||||
int flags)
|
struct svc_serv *serv,
|
||||||
|
unsigned short port, int flags)
|
||||||
{
|
{
|
||||||
struct svc_xprt_class *xcl;
|
|
||||||
struct sockaddr_in sin = {
|
struct sockaddr_in sin = {
|
||||||
.sin_family = AF_INET,
|
.sin_family = AF_INET,
|
||||||
.sin_addr.s_addr = htonl(INADDR_ANY),
|
.sin_addr.s_addr = htonl(INADDR_ANY),
|
||||||
.sin_port = htons(port),
|
.sin_port = htons(port),
|
||||||
};
|
};
|
||||||
|
struct sockaddr_in6 sin6 = {
|
||||||
|
.sin6_family = AF_INET6,
|
||||||
|
.sin6_addr = IN6ADDR_ANY_INIT,
|
||||||
|
.sin6_port = htons(port),
|
||||||
|
};
|
||||||
|
struct sockaddr *sap;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
switch (serv->sv_family) {
|
||||||
|
case AF_INET:
|
||||||
|
sap = (struct sockaddr *)&sin;
|
||||||
|
len = sizeof(sin);
|
||||||
|
break;
|
||||||
|
case AF_INET6:
|
||||||
|
sap = (struct sockaddr *)&sin6;
|
||||||
|
len = sizeof(sin6);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return ERR_PTR(-EAFNOSUPPORT);
|
||||||
|
}
|
||||||
|
|
||||||
|
return xcl->xcl_ops->xpo_create(serv, sap, len, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
int svc_create_xprt(struct svc_serv *serv, char *xprt_name, unsigned short port,
|
||||||
|
int flags)
|
||||||
|
{
|
||||||
|
struct svc_xprt_class *xcl;
|
||||||
|
|
||||||
dprintk("svc: creating transport %s[%d]\n", xprt_name, port);
|
dprintk("svc: creating transport %s[%d]\n", xprt_name, port);
|
||||||
spin_lock(&svc_xprt_class_lock);
|
spin_lock(&svc_xprt_class_lock);
|
||||||
list_for_each_entry(xcl, &svc_xprt_class_list, xcl_list) {
|
list_for_each_entry(xcl, &svc_xprt_class_list, xcl_list) {
|
||||||
|
@ -180,9 +209,7 @@ int svc_create_xprt(struct svc_serv *serv, char *xprt_name, unsigned short port,
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
spin_unlock(&svc_xprt_class_lock);
|
spin_unlock(&svc_xprt_class_lock);
|
||||||
newxprt = xcl->xcl_ops->
|
newxprt = __svc_xpo_create(xcl, serv, port, flags);
|
||||||
xpo_create(serv, (struct sockaddr *)&sin, sizeof(sin),
|
|
||||||
flags);
|
|
||||||
if (IS_ERR(newxprt)) {
|
if (IS_ERR(newxprt)) {
|
||||||
module_put(xcl->xcl_owner);
|
module_put(xcl->xcl_owner);
|
||||||
return PTR_ERR(newxprt);
|
return PTR_ERR(newxprt);
|
||||||
|
|
|
@ -1114,6 +1114,7 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv,
|
||||||
struct svc_sock *svsk;
|
struct svc_sock *svsk;
|
||||||
struct sock *inet;
|
struct sock *inet;
|
||||||
int pmap_register = !(flags & SVC_SOCK_ANONYMOUS);
|
int pmap_register = !(flags & SVC_SOCK_ANONYMOUS);
|
||||||
|
int val;
|
||||||
|
|
||||||
dprintk("svc: svc_setup_socket %p\n", sock);
|
dprintk("svc: svc_setup_socket %p\n", sock);
|
||||||
if (!(svsk = kzalloc(sizeof(*svsk), GFP_KERNEL))) {
|
if (!(svsk = kzalloc(sizeof(*svsk), GFP_KERNEL))) {
|
||||||
|
@ -1146,6 +1147,18 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv,
|
||||||
else
|
else
|
||||||
svc_tcp_init(svsk, serv);
|
svc_tcp_init(svsk, serv);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We start one listener per sv_serv. We want AF_INET
|
||||||
|
* requests to be automatically shunted to our AF_INET6
|
||||||
|
* listener using a mapped IPv4 address. Make sure
|
||||||
|
* no-one starts an equivalent IPv4 listener, which
|
||||||
|
* would steal our incoming connections.
|
||||||
|
*/
|
||||||
|
val = 0;
|
||||||
|
if (serv->sv_family == AF_INET6)
|
||||||
|
kernel_setsockopt(sock, SOL_IPV6, IPV6_V6ONLY,
|
||||||
|
(char *)&val, sizeof(val));
|
||||||
|
|
||||||
dprintk("svc: svc_setup_socket created %p (inet %p)\n",
|
dprintk("svc: svc_setup_socket created %p (inet %p)\n",
|
||||||
svsk, svsk->sk_sk);
|
svsk, svsk->sk_sk);
|
||||||
|
|
||||||
|
@ -1154,8 +1167,7 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv,
|
||||||
|
|
||||||
int svc_addsock(struct svc_serv *serv,
|
int svc_addsock(struct svc_serv *serv,
|
||||||
int fd,
|
int fd,
|
||||||
char *name_return,
|
char *name_return)
|
||||||
int *proto)
|
|
||||||
{
|
{
|
||||||
int err = 0;
|
int err = 0;
|
||||||
struct socket *so = sockfd_lookup(fd, &err);
|
struct socket *so = sockfd_lookup(fd, &err);
|
||||||
|
@ -1190,7 +1202,6 @@ int svc_addsock(struct svc_serv *serv,
|
||||||
sockfd_put(so);
|
sockfd_put(so);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
if (proto) *proto = so->sk->sk_protocol;
|
|
||||||
return one_sock_name(name_return, svsk);
|
return one_sock_name(name_return, svsk);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(svc_addsock);
|
EXPORT_SYMBOL_GPL(svc_addsock);
|
||||||
|
|
|
@ -116,7 +116,7 @@ static void rdma_build_arg_xdr(struct svc_rqst *rqstp,
|
||||||
*
|
*
|
||||||
* Assumptions:
|
* Assumptions:
|
||||||
* - chunk[0]->position points to pages[0] at an offset of 0
|
* - chunk[0]->position points to pages[0] at an offset of 0
|
||||||
* - pages[] is not physically or virtually contigous and consists of
|
* - pages[] is not physically or virtually contiguous and consists of
|
||||||
* PAGE_SIZE elements.
|
* PAGE_SIZE elements.
|
||||||
*
|
*
|
||||||
* Output:
|
* Output:
|
||||||
|
@ -125,7 +125,7 @@ static void rdma_build_arg_xdr(struct svc_rqst *rqstp,
|
||||||
* chunk in the read list
|
* chunk in the read list
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static int rdma_rcl_to_sge(struct svcxprt_rdma *xprt,
|
static int map_read_chunks(struct svcxprt_rdma *xprt,
|
||||||
struct svc_rqst *rqstp,
|
struct svc_rqst *rqstp,
|
||||||
struct svc_rdma_op_ctxt *head,
|
struct svc_rdma_op_ctxt *head,
|
||||||
struct rpcrdma_msg *rmsgp,
|
struct rpcrdma_msg *rmsgp,
|
||||||
|
@ -211,8 +211,99 @@ static int rdma_rcl_to_sge(struct svcxprt_rdma *xprt,
|
||||||
return sge_no;
|
return sge_no;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rdma_set_ctxt_sge(struct svcxprt_rdma *xprt,
|
/* Map a read-chunk-list to an XDR and fast register the page-list.
|
||||||
|
*
|
||||||
|
* Assumptions:
|
||||||
|
* - chunk[0] position points to pages[0] at an offset of 0
|
||||||
|
* - pages[] will be made physically contiguous by creating a one-off memory
|
||||||
|
* region using the fastreg verb.
|
||||||
|
* - byte_count is # of bytes in read-chunk-list
|
||||||
|
* - ch_count is # of chunks in read-chunk-list
|
||||||
|
*
|
||||||
|
* Output:
|
||||||
|
* - sge array pointing into pages[] array.
|
||||||
|
* - chunk_sge array specifying sge index and count for each
|
||||||
|
* chunk in the read list
|
||||||
|
*/
|
||||||
|
static int fast_reg_read_chunks(struct svcxprt_rdma *xprt,
|
||||||
|
struct svc_rqst *rqstp,
|
||||||
|
struct svc_rdma_op_ctxt *head,
|
||||||
|
struct rpcrdma_msg *rmsgp,
|
||||||
|
struct svc_rdma_req_map *rpl_map,
|
||||||
|
struct svc_rdma_req_map *chl_map,
|
||||||
|
int ch_count,
|
||||||
|
int byte_count)
|
||||||
|
{
|
||||||
|
int page_no;
|
||||||
|
int ch_no;
|
||||||
|
u32 offset;
|
||||||
|
struct rpcrdma_read_chunk *ch;
|
||||||
|
struct svc_rdma_fastreg_mr *frmr;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
frmr = svc_rdma_get_frmr(xprt);
|
||||||
|
if (IS_ERR(frmr))
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
head->frmr = frmr;
|
||||||
|
head->arg.head[0] = rqstp->rq_arg.head[0];
|
||||||
|
head->arg.tail[0] = rqstp->rq_arg.tail[0];
|
||||||
|
head->arg.pages = &head->pages[head->count];
|
||||||
|
head->hdr_count = head->count; /* save count of hdr pages */
|
||||||
|
head->arg.page_base = 0;
|
||||||
|
head->arg.page_len = byte_count;
|
||||||
|
head->arg.len = rqstp->rq_arg.len + byte_count;
|
||||||
|
head->arg.buflen = rqstp->rq_arg.buflen + byte_count;
|
||||||
|
|
||||||
|
/* Fast register the page list */
|
||||||
|
frmr->kva = page_address(rqstp->rq_arg.pages[0]);
|
||||||
|
frmr->direction = DMA_FROM_DEVICE;
|
||||||
|
frmr->access_flags = (IB_ACCESS_LOCAL_WRITE|IB_ACCESS_REMOTE_WRITE);
|
||||||
|
frmr->map_len = byte_count;
|
||||||
|
frmr->page_list_len = PAGE_ALIGN(byte_count) >> PAGE_SHIFT;
|
||||||
|
for (page_no = 0; page_no < frmr->page_list_len; page_no++) {
|
||||||
|
frmr->page_list->page_list[page_no] =
|
||||||
|
ib_dma_map_single(xprt->sc_cm_id->device,
|
||||||
|
page_address(rqstp->rq_arg.pages[page_no]),
|
||||||
|
PAGE_SIZE, DMA_TO_DEVICE);
|
||||||
|
if (ib_dma_mapping_error(xprt->sc_cm_id->device,
|
||||||
|
frmr->page_list->page_list[page_no]))
|
||||||
|
goto fatal_err;
|
||||||
|
atomic_inc(&xprt->sc_dma_used);
|
||||||
|
head->arg.pages[page_no] = rqstp->rq_arg.pages[page_no];
|
||||||
|
}
|
||||||
|
head->count += page_no;
|
||||||
|
|
||||||
|
/* rq_respages points one past arg pages */
|
||||||
|
rqstp->rq_respages = &rqstp->rq_arg.pages[page_no];
|
||||||
|
|
||||||
|
/* Create the reply and chunk maps */
|
||||||
|
offset = 0;
|
||||||
|
ch = (struct rpcrdma_read_chunk *)&rmsgp->rm_body.rm_chunks[0];
|
||||||
|
for (ch_no = 0; ch_no < ch_count; ch_no++) {
|
||||||
|
rpl_map->sge[ch_no].iov_base = frmr->kva + offset;
|
||||||
|
rpl_map->sge[ch_no].iov_len = ch->rc_target.rs_length;
|
||||||
|
chl_map->ch[ch_no].count = 1;
|
||||||
|
chl_map->ch[ch_no].start = ch_no;
|
||||||
|
offset += ch->rc_target.rs_length;
|
||||||
|
ch++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = svc_rdma_fastreg(xprt, frmr);
|
||||||
|
if (ret)
|
||||||
|
goto fatal_err;
|
||||||
|
|
||||||
|
return ch_no;
|
||||||
|
|
||||||
|
fatal_err:
|
||||||
|
printk("svcrdma: error fast registering xdr for xprt %p", xprt);
|
||||||
|
svc_rdma_put_frmr(xprt, frmr);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rdma_set_ctxt_sge(struct svcxprt_rdma *xprt,
|
||||||
struct svc_rdma_op_ctxt *ctxt,
|
struct svc_rdma_op_ctxt *ctxt,
|
||||||
|
struct svc_rdma_fastreg_mr *frmr,
|
||||||
struct kvec *vec,
|
struct kvec *vec,
|
||||||
u64 *sgl_offset,
|
u64 *sgl_offset,
|
||||||
int count)
|
int count)
|
||||||
|
@ -222,15 +313,26 @@ static void rdma_set_ctxt_sge(struct svcxprt_rdma *xprt,
|
||||||
ctxt->count = count;
|
ctxt->count = count;
|
||||||
ctxt->direction = DMA_FROM_DEVICE;
|
ctxt->direction = DMA_FROM_DEVICE;
|
||||||
for (i = 0; i < count; i++) {
|
for (i = 0; i < count; i++) {
|
||||||
atomic_inc(&xprt->sc_dma_used);
|
ctxt->sge[i].length = 0; /* in case map fails */
|
||||||
|
if (!frmr) {
|
||||||
ctxt->sge[i].addr =
|
ctxt->sge[i].addr =
|
||||||
ib_dma_map_single(xprt->sc_cm_id->device,
|
ib_dma_map_single(xprt->sc_cm_id->device,
|
||||||
vec[i].iov_base, vec[i].iov_len,
|
vec[i].iov_base,
|
||||||
|
vec[i].iov_len,
|
||||||
DMA_FROM_DEVICE);
|
DMA_FROM_DEVICE);
|
||||||
|
if (ib_dma_mapping_error(xprt->sc_cm_id->device,
|
||||||
|
ctxt->sge[i].addr))
|
||||||
|
return -EINVAL;
|
||||||
|
ctxt->sge[i].lkey = xprt->sc_dma_lkey;
|
||||||
|
atomic_inc(&xprt->sc_dma_used);
|
||||||
|
} else {
|
||||||
|
ctxt->sge[i].addr = (unsigned long)vec[i].iov_base;
|
||||||
|
ctxt->sge[i].lkey = frmr->mr->lkey;
|
||||||
|
}
|
||||||
ctxt->sge[i].length = vec[i].iov_len;
|
ctxt->sge[i].length = vec[i].iov_len;
|
||||||
ctxt->sge[i].lkey = xprt->sc_phys_mr->lkey;
|
|
||||||
*sgl_offset = *sgl_offset + vec[i].iov_len;
|
*sgl_offset = *sgl_offset + vec[i].iov_len;
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rdma_read_max_sge(struct svcxprt_rdma *xprt, int sge_count)
|
static int rdma_read_max_sge(struct svcxprt_rdma *xprt, int sge_count)
|
||||||
|
@ -278,6 +380,7 @@ static int rdma_read_xdr(struct svcxprt_rdma *xprt,
|
||||||
struct svc_rdma_op_ctxt *hdr_ctxt)
|
struct svc_rdma_op_ctxt *hdr_ctxt)
|
||||||
{
|
{
|
||||||
struct ib_send_wr read_wr;
|
struct ib_send_wr read_wr;
|
||||||
|
struct ib_send_wr inv_wr;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
int ch_no;
|
int ch_no;
|
||||||
int ch_count;
|
int ch_count;
|
||||||
|
@ -301,9 +404,20 @@ static int rdma_read_xdr(struct svcxprt_rdma *xprt,
|
||||||
svc_rdma_rcl_chunk_counts(ch, &ch_count, &byte_count);
|
svc_rdma_rcl_chunk_counts(ch, &ch_count, &byte_count);
|
||||||
if (ch_count > RPCSVC_MAXPAGES)
|
if (ch_count > RPCSVC_MAXPAGES)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
sge_count = rdma_rcl_to_sge(xprt, rqstp, hdr_ctxt, rmsgp,
|
|
||||||
rpl_map, chl_map,
|
if (!xprt->sc_frmr_pg_list_len)
|
||||||
ch_count, byte_count);
|
sge_count = map_read_chunks(xprt, rqstp, hdr_ctxt, rmsgp,
|
||||||
|
rpl_map, chl_map, ch_count,
|
||||||
|
byte_count);
|
||||||
|
else
|
||||||
|
sge_count = fast_reg_read_chunks(xprt, rqstp, hdr_ctxt, rmsgp,
|
||||||
|
rpl_map, chl_map, ch_count,
|
||||||
|
byte_count);
|
||||||
|
if (sge_count < 0) {
|
||||||
|
err = -EIO;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
sgl_offset = 0;
|
sgl_offset = 0;
|
||||||
ch_no = 0;
|
ch_no = 0;
|
||||||
|
|
||||||
|
@ -312,13 +426,16 @@ static int rdma_read_xdr(struct svcxprt_rdma *xprt,
|
||||||
next_sge:
|
next_sge:
|
||||||
ctxt = svc_rdma_get_context(xprt);
|
ctxt = svc_rdma_get_context(xprt);
|
||||||
ctxt->direction = DMA_FROM_DEVICE;
|
ctxt->direction = DMA_FROM_DEVICE;
|
||||||
|
ctxt->frmr = hdr_ctxt->frmr;
|
||||||
|
ctxt->read_hdr = NULL;
|
||||||
clear_bit(RDMACTXT_F_LAST_CTXT, &ctxt->flags);
|
clear_bit(RDMACTXT_F_LAST_CTXT, &ctxt->flags);
|
||||||
|
clear_bit(RDMACTXT_F_FAST_UNREG, &ctxt->flags);
|
||||||
|
|
||||||
/* Prepare READ WR */
|
/* Prepare READ WR */
|
||||||
memset(&read_wr, 0, sizeof read_wr);
|
memset(&read_wr, 0, sizeof read_wr);
|
||||||
ctxt->wr_op = IB_WR_RDMA_READ;
|
|
||||||
read_wr.wr_id = (unsigned long)ctxt;
|
read_wr.wr_id = (unsigned long)ctxt;
|
||||||
read_wr.opcode = IB_WR_RDMA_READ;
|
read_wr.opcode = IB_WR_RDMA_READ;
|
||||||
|
ctxt->wr_op = read_wr.opcode;
|
||||||
read_wr.send_flags = IB_SEND_SIGNALED;
|
read_wr.send_flags = IB_SEND_SIGNALED;
|
||||||
read_wr.wr.rdma.rkey = ch->rc_target.rs_handle;
|
read_wr.wr.rdma.rkey = ch->rc_target.rs_handle;
|
||||||
read_wr.wr.rdma.remote_addr =
|
read_wr.wr.rdma.remote_addr =
|
||||||
|
@ -327,10 +444,15 @@ next_sge:
|
||||||
read_wr.sg_list = ctxt->sge;
|
read_wr.sg_list = ctxt->sge;
|
||||||
read_wr.num_sge =
|
read_wr.num_sge =
|
||||||
rdma_read_max_sge(xprt, chl_map->ch[ch_no].count);
|
rdma_read_max_sge(xprt, chl_map->ch[ch_no].count);
|
||||||
rdma_set_ctxt_sge(xprt, ctxt,
|
err = rdma_set_ctxt_sge(xprt, ctxt, hdr_ctxt->frmr,
|
||||||
&rpl_map->sge[chl_map->ch[ch_no].start],
|
&rpl_map->sge[chl_map->ch[ch_no].start],
|
||||||
&sgl_offset,
|
&sgl_offset,
|
||||||
read_wr.num_sge);
|
read_wr.num_sge);
|
||||||
|
if (err) {
|
||||||
|
svc_rdma_unmap_dma(ctxt);
|
||||||
|
svc_rdma_put_context(ctxt, 0);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
if (((ch+1)->rc_discrim == 0) &&
|
if (((ch+1)->rc_discrim == 0) &&
|
||||||
(read_wr.num_sge == chl_map->ch[ch_no].count)) {
|
(read_wr.num_sge == chl_map->ch[ch_no].count)) {
|
||||||
/*
|
/*
|
||||||
|
@ -339,6 +461,29 @@ next_sge:
|
||||||
* the client and the RPC needs to be enqueued.
|
* the client and the RPC needs to be enqueued.
|
||||||
*/
|
*/
|
||||||
set_bit(RDMACTXT_F_LAST_CTXT, &ctxt->flags);
|
set_bit(RDMACTXT_F_LAST_CTXT, &ctxt->flags);
|
||||||
|
if (hdr_ctxt->frmr) {
|
||||||
|
set_bit(RDMACTXT_F_FAST_UNREG, &ctxt->flags);
|
||||||
|
/*
|
||||||
|
* Invalidate the local MR used to map the data
|
||||||
|
* sink.
|
||||||
|
*/
|
||||||
|
if (xprt->sc_dev_caps &
|
||||||
|
SVCRDMA_DEVCAP_READ_W_INV) {
|
||||||
|
read_wr.opcode =
|
||||||
|
IB_WR_RDMA_READ_WITH_INV;
|
||||||
|
ctxt->wr_op = read_wr.opcode;
|
||||||
|
read_wr.ex.invalidate_rkey =
|
||||||
|
ctxt->frmr->mr->lkey;
|
||||||
|
} else {
|
||||||
|
/* Prepare INVALIDATE WR */
|
||||||
|
memset(&inv_wr, 0, sizeof inv_wr);
|
||||||
|
inv_wr.opcode = IB_WR_LOCAL_INV;
|
||||||
|
inv_wr.send_flags = IB_SEND_SIGNALED;
|
||||||
|
inv_wr.ex.invalidate_rkey =
|
||||||
|
hdr_ctxt->frmr->mr->lkey;
|
||||||
|
read_wr.next = &inv_wr;
|
||||||
|
}
|
||||||
|
}
|
||||||
ctxt->read_hdr = hdr_ctxt;
|
ctxt->read_hdr = hdr_ctxt;
|
||||||
}
|
}
|
||||||
/* Post the read */
|
/* Post the read */
|
||||||
|
|
|
@ -69,7 +69,125 @@
|
||||||
* array is only concerned with the reply we are assured that we have
|
* array is only concerned with the reply we are assured that we have
|
||||||
* on extra page for the RPCRMDA header.
|
* on extra page for the RPCRMDA header.
|
||||||
*/
|
*/
|
||||||
static void xdr_to_sge(struct svcxprt_rdma *xprt,
|
int fast_reg_xdr(struct svcxprt_rdma *xprt,
|
||||||
|
struct xdr_buf *xdr,
|
||||||
|
struct svc_rdma_req_map *vec)
|
||||||
|
{
|
||||||
|
int sge_no;
|
||||||
|
u32 sge_bytes;
|
||||||
|
u32 page_bytes;
|
||||||
|
u32 page_off;
|
||||||
|
int page_no = 0;
|
||||||
|
u8 *frva;
|
||||||
|
struct svc_rdma_fastreg_mr *frmr;
|
||||||
|
|
||||||
|
frmr = svc_rdma_get_frmr(xprt);
|
||||||
|
if (IS_ERR(frmr))
|
||||||
|
return -ENOMEM;
|
||||||
|
vec->frmr = frmr;
|
||||||
|
|
||||||
|
/* Skip the RPCRDMA header */
|
||||||
|
sge_no = 1;
|
||||||
|
|
||||||
|
/* Map the head. */
|
||||||
|
frva = (void *)((unsigned long)(xdr->head[0].iov_base) & PAGE_MASK);
|
||||||
|
vec->sge[sge_no].iov_base = xdr->head[0].iov_base;
|
||||||
|
vec->sge[sge_no].iov_len = xdr->head[0].iov_len;
|
||||||
|
vec->count = 2;
|
||||||
|
sge_no++;
|
||||||
|
|
||||||
|
/* Build the FRMR */
|
||||||
|
frmr->kva = frva;
|
||||||
|
frmr->direction = DMA_TO_DEVICE;
|
||||||
|
frmr->access_flags = 0;
|
||||||
|
frmr->map_len = PAGE_SIZE;
|
||||||
|
frmr->page_list_len = 1;
|
||||||
|
frmr->page_list->page_list[page_no] =
|
||||||
|
ib_dma_map_single(xprt->sc_cm_id->device,
|
||||||
|
(void *)xdr->head[0].iov_base,
|
||||||
|
PAGE_SIZE, DMA_TO_DEVICE);
|
||||||
|
if (ib_dma_mapping_error(xprt->sc_cm_id->device,
|
||||||
|
frmr->page_list->page_list[page_no]))
|
||||||
|
goto fatal_err;
|
||||||
|
atomic_inc(&xprt->sc_dma_used);
|
||||||
|
|
||||||
|
page_off = xdr->page_base;
|
||||||
|
page_bytes = xdr->page_len + page_off;
|
||||||
|
if (!page_bytes)
|
||||||
|
goto encode_tail;
|
||||||
|
|
||||||
|
/* Map the pages */
|
||||||
|
vec->sge[sge_no].iov_base = frva + frmr->map_len + page_off;
|
||||||
|
vec->sge[sge_no].iov_len = page_bytes;
|
||||||
|
sge_no++;
|
||||||
|
while (page_bytes) {
|
||||||
|
struct page *page;
|
||||||
|
|
||||||
|
page = xdr->pages[page_no++];
|
||||||
|
sge_bytes = min_t(u32, page_bytes, (PAGE_SIZE - page_off));
|
||||||
|
page_bytes -= sge_bytes;
|
||||||
|
|
||||||
|
frmr->page_list->page_list[page_no] =
|
||||||
|
ib_dma_map_page(xprt->sc_cm_id->device, page, 0,
|
||||||
|
PAGE_SIZE, DMA_TO_DEVICE);
|
||||||
|
if (ib_dma_mapping_error(xprt->sc_cm_id->device,
|
||||||
|
frmr->page_list->page_list[page_no]))
|
||||||
|
goto fatal_err;
|
||||||
|
|
||||||
|
atomic_inc(&xprt->sc_dma_used);
|
||||||
|
page_off = 0; /* reset for next time through loop */
|
||||||
|
frmr->map_len += PAGE_SIZE;
|
||||||
|
frmr->page_list_len++;
|
||||||
|
}
|
||||||
|
vec->count++;
|
||||||
|
|
||||||
|
encode_tail:
|
||||||
|
/* Map tail */
|
||||||
|
if (0 == xdr->tail[0].iov_len)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
vec->count++;
|
||||||
|
vec->sge[sge_no].iov_len = xdr->tail[0].iov_len;
|
||||||
|
|
||||||
|
if (((unsigned long)xdr->tail[0].iov_base & PAGE_MASK) ==
|
||||||
|
((unsigned long)xdr->head[0].iov_base & PAGE_MASK)) {
|
||||||
|
/*
|
||||||
|
* If head and tail use the same page, we don't need
|
||||||
|
* to map it again.
|
||||||
|
*/
|
||||||
|
vec->sge[sge_no].iov_base = xdr->tail[0].iov_base;
|
||||||
|
} else {
|
||||||
|
void *va;
|
||||||
|
|
||||||
|
/* Map another page for the tail */
|
||||||
|
page_off = (unsigned long)xdr->tail[0].iov_base & ~PAGE_MASK;
|
||||||
|
va = (void *)((unsigned long)xdr->tail[0].iov_base & PAGE_MASK);
|
||||||
|
vec->sge[sge_no].iov_base = frva + frmr->map_len + page_off;
|
||||||
|
|
||||||
|
frmr->page_list->page_list[page_no] =
|
||||||
|
ib_dma_map_single(xprt->sc_cm_id->device, va, PAGE_SIZE,
|
||||||
|
DMA_TO_DEVICE);
|
||||||
|
if (ib_dma_mapping_error(xprt->sc_cm_id->device,
|
||||||
|
frmr->page_list->page_list[page_no]))
|
||||||
|
goto fatal_err;
|
||||||
|
atomic_inc(&xprt->sc_dma_used);
|
||||||
|
frmr->map_len += PAGE_SIZE;
|
||||||
|
frmr->page_list_len++;
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
if (svc_rdma_fastreg(xprt, frmr))
|
||||||
|
goto fatal_err;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fatal_err:
|
||||||
|
printk("svcrdma: Error fast registering memory for xprt %p\n", xprt);
|
||||||
|
svc_rdma_put_frmr(xprt, frmr);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int map_xdr(struct svcxprt_rdma *xprt,
|
||||||
struct xdr_buf *xdr,
|
struct xdr_buf *xdr,
|
||||||
struct svc_rdma_req_map *vec)
|
struct svc_rdma_req_map *vec)
|
||||||
{
|
{
|
||||||
|
@ -83,6 +201,9 @@ static void xdr_to_sge(struct svcxprt_rdma *xprt,
|
||||||
BUG_ON(xdr->len !=
|
BUG_ON(xdr->len !=
|
||||||
(xdr->head[0].iov_len + xdr->page_len + xdr->tail[0].iov_len));
|
(xdr->head[0].iov_len + xdr->page_len + xdr->tail[0].iov_len));
|
||||||
|
|
||||||
|
if (xprt->sc_frmr_pg_list_len)
|
||||||
|
return fast_reg_xdr(xprt, xdr, vec);
|
||||||
|
|
||||||
/* Skip the first sge, this is for the RPCRDMA header */
|
/* Skip the first sge, this is for the RPCRDMA header */
|
||||||
sge_no = 1;
|
sge_no = 1;
|
||||||
|
|
||||||
|
@ -116,9 +237,12 @@ static void xdr_to_sge(struct svcxprt_rdma *xprt,
|
||||||
|
|
||||||
BUG_ON(sge_no > sge_max);
|
BUG_ON(sge_no > sge_max);
|
||||||
vec->count = sge_no;
|
vec->count = sge_no;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Assumptions:
|
/* Assumptions:
|
||||||
|
* - We are using FRMR
|
||||||
|
* - or -
|
||||||
* - The specified write_len can be represented in sc_max_sge * PAGE_SIZE
|
* - The specified write_len can be represented in sc_max_sge * PAGE_SIZE
|
||||||
*/
|
*/
|
||||||
static int send_write(struct svcxprt_rdma *xprt, struct svc_rqst *rqstp,
|
static int send_write(struct svcxprt_rdma *xprt, struct svc_rqst *rqstp,
|
||||||
|
@ -158,30 +282,35 @@ static int send_write(struct svcxprt_rdma *xprt, struct svc_rqst *rqstp,
|
||||||
sge_no = 0;
|
sge_no = 0;
|
||||||
|
|
||||||
/* Copy the remaining SGE */
|
/* Copy the remaining SGE */
|
||||||
while (bc != 0 && xdr_sge_no < vec->count) {
|
while (bc != 0) {
|
||||||
sge[sge_no].lkey = xprt->sc_phys_mr->lkey;
|
sge_bytes = min_t(size_t,
|
||||||
sge_bytes = min((size_t)bc,
|
bc, vec->sge[xdr_sge_no].iov_len-sge_off);
|
||||||
(size_t)(vec->sge[xdr_sge_no].iov_len-sge_off));
|
|
||||||
sge[sge_no].length = sge_bytes;
|
sge[sge_no].length = sge_bytes;
|
||||||
atomic_inc(&xprt->sc_dma_used);
|
if (!vec->frmr) {
|
||||||
sge[sge_no].addr =
|
sge[sge_no].addr =
|
||||||
ib_dma_map_single(xprt->sc_cm_id->device,
|
ib_dma_map_single(xprt->sc_cm_id->device,
|
||||||
(void *)
|
(void *)
|
||||||
vec->sge[xdr_sge_no].iov_base + sge_off,
|
vec->sge[xdr_sge_no].iov_base + sge_off,
|
||||||
sge_bytes, DMA_TO_DEVICE);
|
sge_bytes, DMA_TO_DEVICE);
|
||||||
if (dma_mapping_error(xprt->sc_cm_id->device->dma_device,
|
if (ib_dma_mapping_error(xprt->sc_cm_id->device,
|
||||||
sge[sge_no].addr))
|
sge[sge_no].addr))
|
||||||
goto err;
|
goto err;
|
||||||
|
atomic_inc(&xprt->sc_dma_used);
|
||||||
|
sge[sge_no].lkey = xprt->sc_dma_lkey;
|
||||||
|
} else {
|
||||||
|
sge[sge_no].addr = (unsigned long)
|
||||||
|
vec->sge[xdr_sge_no].iov_base + sge_off;
|
||||||
|
sge[sge_no].lkey = vec->frmr->mr->lkey;
|
||||||
|
}
|
||||||
|
ctxt->count++;
|
||||||
|
ctxt->frmr = vec->frmr;
|
||||||
sge_off = 0;
|
sge_off = 0;
|
||||||
sge_no++;
|
sge_no++;
|
||||||
ctxt->count++;
|
|
||||||
xdr_sge_no++;
|
xdr_sge_no++;
|
||||||
|
BUG_ON(xdr_sge_no > vec->count);
|
||||||
bc -= sge_bytes;
|
bc -= sge_bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
BUG_ON(bc != 0);
|
|
||||||
BUG_ON(xdr_sge_no > vec->count);
|
|
||||||
|
|
||||||
/* Prepare WRITE WR */
|
/* Prepare WRITE WR */
|
||||||
memset(&write_wr, 0, sizeof write_wr);
|
memset(&write_wr, 0, sizeof write_wr);
|
||||||
ctxt->wr_op = IB_WR_RDMA_WRITE;
|
ctxt->wr_op = IB_WR_RDMA_WRITE;
|
||||||
|
@ -226,6 +355,9 @@ static int send_write_chunks(struct svcxprt_rdma *xprt,
|
||||||
res_ary = (struct rpcrdma_write_array *)
|
res_ary = (struct rpcrdma_write_array *)
|
||||||
&rdma_resp->rm_body.rm_chunks[1];
|
&rdma_resp->rm_body.rm_chunks[1];
|
||||||
|
|
||||||
|
if (vec->frmr)
|
||||||
|
max_write = vec->frmr->map_len;
|
||||||
|
else
|
||||||
max_write = xprt->sc_max_sge * PAGE_SIZE;
|
max_write = xprt->sc_max_sge * PAGE_SIZE;
|
||||||
|
|
||||||
/* Write chunks start at the pagelist */
|
/* Write chunks start at the pagelist */
|
||||||
|
@ -297,6 +429,9 @@ static int send_reply_chunks(struct svcxprt_rdma *xprt,
|
||||||
res_ary = (struct rpcrdma_write_array *)
|
res_ary = (struct rpcrdma_write_array *)
|
||||||
&rdma_resp->rm_body.rm_chunks[2];
|
&rdma_resp->rm_body.rm_chunks[2];
|
||||||
|
|
||||||
|
if (vec->frmr)
|
||||||
|
max_write = vec->frmr->map_len;
|
||||||
|
else
|
||||||
max_write = xprt->sc_max_sge * PAGE_SIZE;
|
max_write = xprt->sc_max_sge * PAGE_SIZE;
|
||||||
|
|
||||||
/* xdr offset starts at RPC message */
|
/* xdr offset starts at RPC message */
|
||||||
|
@ -307,7 +442,6 @@ static int send_reply_chunks(struct svcxprt_rdma *xprt,
|
||||||
ch = &arg_ary->wc_array[chunk_no].wc_target;
|
ch = &arg_ary->wc_array[chunk_no].wc_target;
|
||||||
write_len = min(xfer_len, ch->rs_length);
|
write_len = min(xfer_len, ch->rs_length);
|
||||||
|
|
||||||
|
|
||||||
/* Prepare the reply chunk given the length actually
|
/* Prepare the reply chunk given the length actually
|
||||||
* written */
|
* written */
|
||||||
rs_offset = get_unaligned(&(ch->rs_offset));
|
rs_offset = get_unaligned(&(ch->rs_offset));
|
||||||
|
@ -366,6 +500,7 @@ static int send_reply(struct svcxprt_rdma *rdma,
|
||||||
int byte_count)
|
int byte_count)
|
||||||
{
|
{
|
||||||
struct ib_send_wr send_wr;
|
struct ib_send_wr send_wr;
|
||||||
|
struct ib_send_wr inv_wr;
|
||||||
int sge_no;
|
int sge_no;
|
||||||
int sge_bytes;
|
int sge_bytes;
|
||||||
int page_no;
|
int page_no;
|
||||||
|
@ -385,27 +520,45 @@ static int send_reply(struct svcxprt_rdma *rdma,
|
||||||
/* Prepare the context */
|
/* Prepare the context */
|
||||||
ctxt->pages[0] = page;
|
ctxt->pages[0] = page;
|
||||||
ctxt->count = 1;
|
ctxt->count = 1;
|
||||||
|
ctxt->frmr = vec->frmr;
|
||||||
|
if (vec->frmr)
|
||||||
|
set_bit(RDMACTXT_F_FAST_UNREG, &ctxt->flags);
|
||||||
|
else
|
||||||
|
clear_bit(RDMACTXT_F_FAST_UNREG, &ctxt->flags);
|
||||||
|
|
||||||
/* Prepare the SGE for the RPCRDMA Header */
|
/* Prepare the SGE for the RPCRDMA Header */
|
||||||
atomic_inc(&rdma->sc_dma_used);
|
|
||||||
ctxt->sge[0].addr =
|
ctxt->sge[0].addr =
|
||||||
ib_dma_map_page(rdma->sc_cm_id->device,
|
ib_dma_map_page(rdma->sc_cm_id->device,
|
||||||
page, 0, PAGE_SIZE, DMA_TO_DEVICE);
|
page, 0, PAGE_SIZE, DMA_TO_DEVICE);
|
||||||
|
if (ib_dma_mapping_error(rdma->sc_cm_id->device, ctxt->sge[0].addr))
|
||||||
|
goto err;
|
||||||
|
atomic_inc(&rdma->sc_dma_used);
|
||||||
|
|
||||||
ctxt->direction = DMA_TO_DEVICE;
|
ctxt->direction = DMA_TO_DEVICE;
|
||||||
|
|
||||||
ctxt->sge[0].length = svc_rdma_xdr_get_reply_hdr_len(rdma_resp);
|
ctxt->sge[0].length = svc_rdma_xdr_get_reply_hdr_len(rdma_resp);
|
||||||
ctxt->sge[0].lkey = rdma->sc_phys_mr->lkey;
|
ctxt->sge[0].lkey = rdma->sc_dma_lkey;
|
||||||
|
|
||||||
/* Determine how many of our SGE are to be transmitted */
|
/* Determine how many of our SGE are to be transmitted */
|
||||||
for (sge_no = 1; byte_count && sge_no < vec->count; sge_no++) {
|
for (sge_no = 1; byte_count && sge_no < vec->count; sge_no++) {
|
||||||
sge_bytes = min_t(size_t, vec->sge[sge_no].iov_len, byte_count);
|
sge_bytes = min_t(size_t, vec->sge[sge_no].iov_len, byte_count);
|
||||||
byte_count -= sge_bytes;
|
byte_count -= sge_bytes;
|
||||||
atomic_inc(&rdma->sc_dma_used);
|
if (!vec->frmr) {
|
||||||
ctxt->sge[sge_no].addr =
|
ctxt->sge[sge_no].addr =
|
||||||
ib_dma_map_single(rdma->sc_cm_id->device,
|
ib_dma_map_single(rdma->sc_cm_id->device,
|
||||||
vec->sge[sge_no].iov_base,
|
vec->sge[sge_no].iov_base,
|
||||||
sge_bytes, DMA_TO_DEVICE);
|
sge_bytes, DMA_TO_DEVICE);
|
||||||
|
if (ib_dma_mapping_error(rdma->sc_cm_id->device,
|
||||||
|
ctxt->sge[sge_no].addr))
|
||||||
|
goto err;
|
||||||
|
atomic_inc(&rdma->sc_dma_used);
|
||||||
|
ctxt->sge[sge_no].lkey = rdma->sc_dma_lkey;
|
||||||
|
} else {
|
||||||
|
ctxt->sge[sge_no].addr = (unsigned long)
|
||||||
|
vec->sge[sge_no].iov_base;
|
||||||
|
ctxt->sge[sge_no].lkey = vec->frmr->mr->lkey;
|
||||||
|
}
|
||||||
ctxt->sge[sge_no].length = sge_bytes;
|
ctxt->sge[sge_no].length = sge_bytes;
|
||||||
ctxt->sge[sge_no].lkey = rdma->sc_phys_mr->lkey;
|
|
||||||
}
|
}
|
||||||
BUG_ON(byte_count != 0);
|
BUG_ON(byte_count != 0);
|
||||||
|
|
||||||
|
@ -417,11 +570,16 @@ static int send_reply(struct svcxprt_rdma *rdma,
|
||||||
ctxt->pages[page_no+1] = rqstp->rq_respages[page_no];
|
ctxt->pages[page_no+1] = rqstp->rq_respages[page_no];
|
||||||
ctxt->count++;
|
ctxt->count++;
|
||||||
rqstp->rq_respages[page_no] = NULL;
|
rqstp->rq_respages[page_no] = NULL;
|
||||||
/* If there are more pages than SGE, terminate SGE list */
|
/*
|
||||||
|
* If there are more pages than SGE, terminate SGE
|
||||||
|
* list so that svc_rdma_unmap_dma doesn't attempt to
|
||||||
|
* unmap garbage.
|
||||||
|
*/
|
||||||
if (page_no+1 >= sge_no)
|
if (page_no+1 >= sge_no)
|
||||||
ctxt->sge[page_no+1].length = 0;
|
ctxt->sge[page_no+1].length = 0;
|
||||||
}
|
}
|
||||||
BUG_ON(sge_no > rdma->sc_max_sge);
|
BUG_ON(sge_no > rdma->sc_max_sge);
|
||||||
|
BUG_ON(sge_no > ctxt->count);
|
||||||
memset(&send_wr, 0, sizeof send_wr);
|
memset(&send_wr, 0, sizeof send_wr);
|
||||||
ctxt->wr_op = IB_WR_SEND;
|
ctxt->wr_op = IB_WR_SEND;
|
||||||
send_wr.wr_id = (unsigned long)ctxt;
|
send_wr.wr_id = (unsigned long)ctxt;
|
||||||
|
@ -429,12 +587,26 @@ static int send_reply(struct svcxprt_rdma *rdma,
|
||||||
send_wr.num_sge = sge_no;
|
send_wr.num_sge = sge_no;
|
||||||
send_wr.opcode = IB_WR_SEND;
|
send_wr.opcode = IB_WR_SEND;
|
||||||
send_wr.send_flags = IB_SEND_SIGNALED;
|
send_wr.send_flags = IB_SEND_SIGNALED;
|
||||||
|
if (vec->frmr) {
|
||||||
|
/* Prepare INVALIDATE WR */
|
||||||
|
memset(&inv_wr, 0, sizeof inv_wr);
|
||||||
|
inv_wr.opcode = IB_WR_LOCAL_INV;
|
||||||
|
inv_wr.send_flags = IB_SEND_SIGNALED;
|
||||||
|
inv_wr.ex.invalidate_rkey =
|
||||||
|
vec->frmr->mr->lkey;
|
||||||
|
send_wr.next = &inv_wr;
|
||||||
|
}
|
||||||
|
|
||||||
ret = svc_rdma_send(rdma, &send_wr);
|
ret = svc_rdma_send(rdma, &send_wr);
|
||||||
if (ret)
|
if (ret)
|
||||||
svc_rdma_put_context(ctxt, 1);
|
goto err;
|
||||||
|
|
||||||
return ret;
|
return 0;
|
||||||
|
|
||||||
|
err:
|
||||||
|
svc_rdma_put_frmr(rdma, vec->frmr);
|
||||||
|
svc_rdma_put_context(ctxt, 1);
|
||||||
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
void svc_rdma_prep_reply_hdr(struct svc_rqst *rqstp)
|
void svc_rdma_prep_reply_hdr(struct svc_rqst *rqstp)
|
||||||
|
@ -477,8 +649,9 @@ int svc_rdma_sendto(struct svc_rqst *rqstp)
|
||||||
ctxt = svc_rdma_get_context(rdma);
|
ctxt = svc_rdma_get_context(rdma);
|
||||||
ctxt->direction = DMA_TO_DEVICE;
|
ctxt->direction = DMA_TO_DEVICE;
|
||||||
vec = svc_rdma_get_req_map();
|
vec = svc_rdma_get_req_map();
|
||||||
xdr_to_sge(rdma, &rqstp->rq_res, vec);
|
ret = map_xdr(rdma, &rqstp->rq_res, vec);
|
||||||
|
if (ret)
|
||||||
|
goto err0;
|
||||||
inline_bytes = rqstp->rq_res.len;
|
inline_bytes = rqstp->rq_res.len;
|
||||||
|
|
||||||
/* Create the RDMA response header */
|
/* Create the RDMA response header */
|
||||||
|
@ -498,7 +671,7 @@ int svc_rdma_sendto(struct svc_rqst *rqstp)
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
printk(KERN_ERR "svcrdma: failed to send write chunks, rc=%d\n",
|
printk(KERN_ERR "svcrdma: failed to send write chunks, rc=%d\n",
|
||||||
ret);
|
ret);
|
||||||
goto error;
|
goto err1;
|
||||||
}
|
}
|
||||||
inline_bytes -= ret;
|
inline_bytes -= ret;
|
||||||
|
|
||||||
|
@ -508,7 +681,7 @@ int svc_rdma_sendto(struct svc_rqst *rqstp)
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
printk(KERN_ERR "svcrdma: failed to send reply chunks, rc=%d\n",
|
printk(KERN_ERR "svcrdma: failed to send reply chunks, rc=%d\n",
|
||||||
ret);
|
ret);
|
||||||
goto error;
|
goto err1;
|
||||||
}
|
}
|
||||||
inline_bytes -= ret;
|
inline_bytes -= ret;
|
||||||
|
|
||||||
|
@ -517,9 +690,11 @@ int svc_rdma_sendto(struct svc_rqst *rqstp)
|
||||||
svc_rdma_put_req_map(vec);
|
svc_rdma_put_req_map(vec);
|
||||||
dprintk("svcrdma: send_reply returns %d\n", ret);
|
dprintk("svcrdma: send_reply returns %d\n", ret);
|
||||||
return ret;
|
return ret;
|
||||||
error:
|
|
||||||
|
err1:
|
||||||
|
put_page(res_page);
|
||||||
|
err0:
|
||||||
svc_rdma_put_req_map(vec);
|
svc_rdma_put_req_map(vec);
|
||||||
svc_rdma_put_context(ctxt, 0);
|
svc_rdma_put_context(ctxt, 0);
|
||||||
put_page(res_page);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,15 +100,23 @@ struct svc_rdma_op_ctxt *svc_rdma_get_context(struct svcxprt_rdma *xprt)
|
||||||
ctxt->xprt = xprt;
|
ctxt->xprt = xprt;
|
||||||
INIT_LIST_HEAD(&ctxt->dto_q);
|
INIT_LIST_HEAD(&ctxt->dto_q);
|
||||||
ctxt->count = 0;
|
ctxt->count = 0;
|
||||||
|
ctxt->frmr = NULL;
|
||||||
atomic_inc(&xprt->sc_ctxt_used);
|
atomic_inc(&xprt->sc_ctxt_used);
|
||||||
return ctxt;
|
return ctxt;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void svc_rdma_unmap_dma(struct svc_rdma_op_ctxt *ctxt)
|
void svc_rdma_unmap_dma(struct svc_rdma_op_ctxt *ctxt)
|
||||||
{
|
{
|
||||||
struct svcxprt_rdma *xprt = ctxt->xprt;
|
struct svcxprt_rdma *xprt = ctxt->xprt;
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < ctxt->count && ctxt->sge[i].length; i++) {
|
for (i = 0; i < ctxt->count && ctxt->sge[i].length; i++) {
|
||||||
|
/*
|
||||||
|
* Unmap the DMA addr in the SGE if the lkey matches
|
||||||
|
* the sc_dma_lkey, otherwise, ignore it since it is
|
||||||
|
* an FRMR lkey and will be unmapped later when the
|
||||||
|
* last WR that uses it completes.
|
||||||
|
*/
|
||||||
|
if (ctxt->sge[i].lkey == xprt->sc_dma_lkey) {
|
||||||
atomic_dec(&xprt->sc_dma_used);
|
atomic_dec(&xprt->sc_dma_used);
|
||||||
ib_dma_unmap_single(xprt->sc_cm_id->device,
|
ib_dma_unmap_single(xprt->sc_cm_id->device,
|
||||||
ctxt->sge[i].addr,
|
ctxt->sge[i].addr,
|
||||||
|
@ -116,6 +124,7 @@ static void svc_rdma_unmap_dma(struct svc_rdma_op_ctxt *ctxt)
|
||||||
ctxt->direction);
|
ctxt->direction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void svc_rdma_put_context(struct svc_rdma_op_ctxt *ctxt, int free_pages)
|
void svc_rdma_put_context(struct svc_rdma_op_ctxt *ctxt, int free_pages)
|
||||||
{
|
{
|
||||||
|
@ -150,6 +159,7 @@ struct svc_rdma_req_map *svc_rdma_get_req_map(void)
|
||||||
schedule_timeout_uninterruptible(msecs_to_jiffies(500));
|
schedule_timeout_uninterruptible(msecs_to_jiffies(500));
|
||||||
}
|
}
|
||||||
map->count = 0;
|
map->count = 0;
|
||||||
|
map->frmr = NULL;
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -316,38 +326,17 @@ static void rq_cq_reap(struct svcxprt_rdma *xprt)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Send Queue Completion Handler - potentially called on interrupt context.
|
* Processs a completion context
|
||||||
*
|
|
||||||
* Note that caller must hold a transport reference.
|
|
||||||
*/
|
*/
|
||||||
static void sq_cq_reap(struct svcxprt_rdma *xprt)
|
static void process_context(struct svcxprt_rdma *xprt,
|
||||||
|
struct svc_rdma_op_ctxt *ctxt)
|
||||||
{
|
{
|
||||||
struct svc_rdma_op_ctxt *ctxt = NULL;
|
|
||||||
struct ib_wc wc;
|
|
||||||
struct ib_cq *cq = xprt->sc_sq_cq;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
|
|
||||||
if (!test_and_clear_bit(RDMAXPRT_SQ_PENDING, &xprt->sc_flags))
|
|
||||||
return;
|
|
||||||
|
|
||||||
ib_req_notify_cq(xprt->sc_sq_cq, IB_CQ_NEXT_COMP);
|
|
||||||
atomic_inc(&rdma_stat_sq_poll);
|
|
||||||
while ((ret = ib_poll_cq(cq, 1, &wc)) > 0) {
|
|
||||||
ctxt = (struct svc_rdma_op_ctxt *)(unsigned long)wc.wr_id;
|
|
||||||
xprt = ctxt->xprt;
|
|
||||||
|
|
||||||
svc_rdma_unmap_dma(ctxt);
|
svc_rdma_unmap_dma(ctxt);
|
||||||
if (wc.status != IB_WC_SUCCESS)
|
|
||||||
/* Close the transport */
|
|
||||||
set_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags);
|
|
||||||
|
|
||||||
/* Decrement used SQ WR count */
|
|
||||||
atomic_dec(&xprt->sc_sq_count);
|
|
||||||
wake_up(&xprt->sc_send_wait);
|
|
||||||
|
|
||||||
switch (ctxt->wr_op) {
|
switch (ctxt->wr_op) {
|
||||||
case IB_WR_SEND:
|
case IB_WR_SEND:
|
||||||
|
if (test_bit(RDMACTXT_F_FAST_UNREG, &ctxt->flags))
|
||||||
|
svc_rdma_put_frmr(xprt, ctxt->frmr);
|
||||||
svc_rdma_put_context(ctxt, 1);
|
svc_rdma_put_context(ctxt, 1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -356,9 +345,12 @@ static void sq_cq_reap(struct svcxprt_rdma *xprt)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IB_WR_RDMA_READ:
|
case IB_WR_RDMA_READ:
|
||||||
|
case IB_WR_RDMA_READ_WITH_INV:
|
||||||
if (test_bit(RDMACTXT_F_LAST_CTXT, &ctxt->flags)) {
|
if (test_bit(RDMACTXT_F_LAST_CTXT, &ctxt->flags)) {
|
||||||
struct svc_rdma_op_ctxt *read_hdr = ctxt->read_hdr;
|
struct svc_rdma_op_ctxt *read_hdr = ctxt->read_hdr;
|
||||||
BUG_ON(!read_hdr);
|
BUG_ON(!read_hdr);
|
||||||
|
if (test_bit(RDMACTXT_F_FAST_UNREG, &ctxt->flags))
|
||||||
|
svc_rdma_put_frmr(xprt, ctxt->frmr);
|
||||||
spin_lock_bh(&xprt->sc_rq_dto_lock);
|
spin_lock_bh(&xprt->sc_rq_dto_lock);
|
||||||
set_bit(XPT_DATA, &xprt->sc_xprt.xpt_flags);
|
set_bit(XPT_DATA, &xprt->sc_xprt.xpt_flags);
|
||||||
list_add_tail(&read_hdr->dto_q,
|
list_add_tail(&read_hdr->dto_q,
|
||||||
|
@ -371,10 +363,42 @@ static void sq_cq_reap(struct svcxprt_rdma *xprt)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
printk(KERN_ERR "svcrdma: unexpected completion type, "
|
printk(KERN_ERR "svcrdma: unexpected completion type, "
|
||||||
"opcode=%d, status=%d\n",
|
"opcode=%d\n",
|
||||||
wc.opcode, wc.status);
|
ctxt->wr_op);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Send Queue Completion Handler - potentially called on interrupt context.
|
||||||
|
*
|
||||||
|
* Note that caller must hold a transport reference.
|
||||||
|
*/
|
||||||
|
static void sq_cq_reap(struct svcxprt_rdma *xprt)
|
||||||
|
{
|
||||||
|
struct svc_rdma_op_ctxt *ctxt = NULL;
|
||||||
|
struct ib_wc wc;
|
||||||
|
struct ib_cq *cq = xprt->sc_sq_cq;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!test_and_clear_bit(RDMAXPRT_SQ_PENDING, &xprt->sc_flags))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ib_req_notify_cq(xprt->sc_sq_cq, IB_CQ_NEXT_COMP);
|
||||||
|
atomic_inc(&rdma_stat_sq_poll);
|
||||||
|
while ((ret = ib_poll_cq(cq, 1, &wc)) > 0) {
|
||||||
|
if (wc.status != IB_WC_SUCCESS)
|
||||||
|
/* Close the transport */
|
||||||
|
set_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags);
|
||||||
|
|
||||||
|
/* Decrement used SQ WR count */
|
||||||
|
atomic_dec(&xprt->sc_sq_count);
|
||||||
|
wake_up(&xprt->sc_send_wait);
|
||||||
|
|
||||||
|
ctxt = (struct svc_rdma_op_ctxt *)(unsigned long)wc.wr_id;
|
||||||
|
if (ctxt)
|
||||||
|
process_context(xprt, ctxt);
|
||||||
|
|
||||||
svc_xprt_put(&xprt->sc_xprt);
|
svc_xprt_put(&xprt->sc_xprt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -425,10 +449,12 @@ static struct svcxprt_rdma *rdma_create_xprt(struct svc_serv *serv,
|
||||||
INIT_LIST_HEAD(&cma_xprt->sc_dto_q);
|
INIT_LIST_HEAD(&cma_xprt->sc_dto_q);
|
||||||
INIT_LIST_HEAD(&cma_xprt->sc_rq_dto_q);
|
INIT_LIST_HEAD(&cma_xprt->sc_rq_dto_q);
|
||||||
INIT_LIST_HEAD(&cma_xprt->sc_read_complete_q);
|
INIT_LIST_HEAD(&cma_xprt->sc_read_complete_q);
|
||||||
|
INIT_LIST_HEAD(&cma_xprt->sc_frmr_q);
|
||||||
init_waitqueue_head(&cma_xprt->sc_send_wait);
|
init_waitqueue_head(&cma_xprt->sc_send_wait);
|
||||||
|
|
||||||
spin_lock_init(&cma_xprt->sc_lock);
|
spin_lock_init(&cma_xprt->sc_lock);
|
||||||
spin_lock_init(&cma_xprt->sc_rq_dto_lock);
|
spin_lock_init(&cma_xprt->sc_rq_dto_lock);
|
||||||
|
spin_lock_init(&cma_xprt->sc_frmr_q_lock);
|
||||||
|
|
||||||
cma_xprt->sc_ord = svcrdma_ord;
|
cma_xprt->sc_ord = svcrdma_ord;
|
||||||
|
|
||||||
|
@ -462,7 +488,7 @@ int svc_rdma_post_recv(struct svcxprt_rdma *xprt)
|
||||||
struct ib_recv_wr recv_wr, *bad_recv_wr;
|
struct ib_recv_wr recv_wr, *bad_recv_wr;
|
||||||
struct svc_rdma_op_ctxt *ctxt;
|
struct svc_rdma_op_ctxt *ctxt;
|
||||||
struct page *page;
|
struct page *page;
|
||||||
unsigned long pa;
|
dma_addr_t pa;
|
||||||
int sge_no;
|
int sge_no;
|
||||||
int buflen;
|
int buflen;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -474,13 +500,15 @@ int svc_rdma_post_recv(struct svcxprt_rdma *xprt)
|
||||||
BUG_ON(sge_no >= xprt->sc_max_sge);
|
BUG_ON(sge_no >= xprt->sc_max_sge);
|
||||||
page = svc_rdma_get_page();
|
page = svc_rdma_get_page();
|
||||||
ctxt->pages[sge_no] = page;
|
ctxt->pages[sge_no] = page;
|
||||||
atomic_inc(&xprt->sc_dma_used);
|
|
||||||
pa = ib_dma_map_page(xprt->sc_cm_id->device,
|
pa = ib_dma_map_page(xprt->sc_cm_id->device,
|
||||||
page, 0, PAGE_SIZE,
|
page, 0, PAGE_SIZE,
|
||||||
DMA_FROM_DEVICE);
|
DMA_FROM_DEVICE);
|
||||||
|
if (ib_dma_mapping_error(xprt->sc_cm_id->device, pa))
|
||||||
|
goto err_put_ctxt;
|
||||||
|
atomic_inc(&xprt->sc_dma_used);
|
||||||
ctxt->sge[sge_no].addr = pa;
|
ctxt->sge[sge_no].addr = pa;
|
||||||
ctxt->sge[sge_no].length = PAGE_SIZE;
|
ctxt->sge[sge_no].length = PAGE_SIZE;
|
||||||
ctxt->sge[sge_no].lkey = xprt->sc_phys_mr->lkey;
|
ctxt->sge[sge_no].lkey = xprt->sc_dma_lkey;
|
||||||
buflen += PAGE_SIZE;
|
buflen += PAGE_SIZE;
|
||||||
}
|
}
|
||||||
ctxt->count = sge_no;
|
ctxt->count = sge_no;
|
||||||
|
@ -496,6 +524,10 @@ int svc_rdma_post_recv(struct svcxprt_rdma *xprt)
|
||||||
svc_rdma_put_context(ctxt, 1);
|
svc_rdma_put_context(ctxt, 1);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
err_put_ctxt:
|
||||||
|
svc_rdma_put_context(ctxt, 1);
|
||||||
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -566,7 +598,7 @@ static int rdma_listen_handler(struct rdma_cm_id *cma_id,
|
||||||
dprintk("svcrdma: Connect request on cma_id=%p, xprt = %p, "
|
dprintk("svcrdma: Connect request on cma_id=%p, xprt = %p, "
|
||||||
"event=%d\n", cma_id, cma_id->context, event->event);
|
"event=%d\n", cma_id, cma_id->context, event->event);
|
||||||
handle_connect_req(cma_id,
|
handle_connect_req(cma_id,
|
||||||
event->param.conn.responder_resources);
|
event->param.conn.initiator_depth);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RDMA_CM_EVENT_ESTABLISHED:
|
case RDMA_CM_EVENT_ESTABLISHED:
|
||||||
|
@ -686,6 +718,97 @@ static struct svc_xprt *svc_rdma_create(struct svc_serv *serv,
|
||||||
return ERR_PTR(ret);
|
return ERR_PTR(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct svc_rdma_fastreg_mr *rdma_alloc_frmr(struct svcxprt_rdma *xprt)
|
||||||
|
{
|
||||||
|
struct ib_mr *mr;
|
||||||
|
struct ib_fast_reg_page_list *pl;
|
||||||
|
struct svc_rdma_fastreg_mr *frmr;
|
||||||
|
|
||||||
|
frmr = kmalloc(sizeof(*frmr), GFP_KERNEL);
|
||||||
|
if (!frmr)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
mr = ib_alloc_fast_reg_mr(xprt->sc_pd, RPCSVC_MAXPAGES);
|
||||||
|
if (!mr)
|
||||||
|
goto err_free_frmr;
|
||||||
|
|
||||||
|
pl = ib_alloc_fast_reg_page_list(xprt->sc_cm_id->device,
|
||||||
|
RPCSVC_MAXPAGES);
|
||||||
|
if (!pl)
|
||||||
|
goto err_free_mr;
|
||||||
|
|
||||||
|
frmr->mr = mr;
|
||||||
|
frmr->page_list = pl;
|
||||||
|
INIT_LIST_HEAD(&frmr->frmr_list);
|
||||||
|
return frmr;
|
||||||
|
|
||||||
|
err_free_mr:
|
||||||
|
ib_dereg_mr(mr);
|
||||||
|
err_free_frmr:
|
||||||
|
kfree(frmr);
|
||||||
|
err:
|
||||||
|
return ERR_PTR(-ENOMEM);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rdma_dealloc_frmr_q(struct svcxprt_rdma *xprt)
|
||||||
|
{
|
||||||
|
struct svc_rdma_fastreg_mr *frmr;
|
||||||
|
|
||||||
|
while (!list_empty(&xprt->sc_frmr_q)) {
|
||||||
|
frmr = list_entry(xprt->sc_frmr_q.next,
|
||||||
|
struct svc_rdma_fastreg_mr, frmr_list);
|
||||||
|
list_del_init(&frmr->frmr_list);
|
||||||
|
ib_dereg_mr(frmr->mr);
|
||||||
|
ib_free_fast_reg_page_list(frmr->page_list);
|
||||||
|
kfree(frmr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct svc_rdma_fastreg_mr *svc_rdma_get_frmr(struct svcxprt_rdma *rdma)
|
||||||
|
{
|
||||||
|
struct svc_rdma_fastreg_mr *frmr = NULL;
|
||||||
|
|
||||||
|
spin_lock_bh(&rdma->sc_frmr_q_lock);
|
||||||
|
if (!list_empty(&rdma->sc_frmr_q)) {
|
||||||
|
frmr = list_entry(rdma->sc_frmr_q.next,
|
||||||
|
struct svc_rdma_fastreg_mr, frmr_list);
|
||||||
|
list_del_init(&frmr->frmr_list);
|
||||||
|
frmr->map_len = 0;
|
||||||
|
frmr->page_list_len = 0;
|
||||||
|
}
|
||||||
|
spin_unlock_bh(&rdma->sc_frmr_q_lock);
|
||||||
|
if (frmr)
|
||||||
|
return frmr;
|
||||||
|
|
||||||
|
return rdma_alloc_frmr(rdma);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void frmr_unmap_dma(struct svcxprt_rdma *xprt,
|
||||||
|
struct svc_rdma_fastreg_mr *frmr)
|
||||||
|
{
|
||||||
|
int page_no;
|
||||||
|
for (page_no = 0; page_no < frmr->page_list_len; page_no++) {
|
||||||
|
dma_addr_t addr = frmr->page_list->page_list[page_no];
|
||||||
|
if (ib_dma_mapping_error(frmr->mr->device, addr))
|
||||||
|
continue;
|
||||||
|
atomic_dec(&xprt->sc_dma_used);
|
||||||
|
ib_dma_unmap_single(frmr->mr->device, addr, PAGE_SIZE,
|
||||||
|
frmr->direction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void svc_rdma_put_frmr(struct svcxprt_rdma *rdma,
|
||||||
|
struct svc_rdma_fastreg_mr *frmr)
|
||||||
|
{
|
||||||
|
if (frmr) {
|
||||||
|
frmr_unmap_dma(rdma, frmr);
|
||||||
|
spin_lock_bh(&rdma->sc_frmr_q_lock);
|
||||||
|
BUG_ON(!list_empty(&frmr->frmr_list));
|
||||||
|
list_add(&frmr->frmr_list, &rdma->sc_frmr_q);
|
||||||
|
spin_unlock_bh(&rdma->sc_frmr_q_lock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is the xpo_recvfrom function for listening endpoints. Its
|
* This is the xpo_recvfrom function for listening endpoints. Its
|
||||||
* purpose is to accept incoming connections. The CMA callback handler
|
* purpose is to accept incoming connections. The CMA callback handler
|
||||||
|
@ -704,6 +827,8 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt)
|
||||||
struct rdma_conn_param conn_param;
|
struct rdma_conn_param conn_param;
|
||||||
struct ib_qp_init_attr qp_attr;
|
struct ib_qp_init_attr qp_attr;
|
||||||
struct ib_device_attr devattr;
|
struct ib_device_attr devattr;
|
||||||
|
int dma_mr_acc;
|
||||||
|
int need_dma_mr;
|
||||||
int ret;
|
int ret;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -819,15 +944,77 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt)
|
||||||
}
|
}
|
||||||
newxprt->sc_qp = newxprt->sc_cm_id->qp;
|
newxprt->sc_qp = newxprt->sc_cm_id->qp;
|
||||||
|
|
||||||
/* Register all of physical memory */
|
/*
|
||||||
newxprt->sc_phys_mr = ib_get_dma_mr(newxprt->sc_pd,
|
* Use the most secure set of MR resources based on the
|
||||||
IB_ACCESS_LOCAL_WRITE |
|
* transport type and available memory management features in
|
||||||
|
* the device. Here's the table implemented below:
|
||||||
|
*
|
||||||
|
* Fast Global DMA Remote WR
|
||||||
|
* Reg LKEY MR Access
|
||||||
|
* Sup'd Sup'd Needed Needed
|
||||||
|
*
|
||||||
|
* IWARP N N Y Y
|
||||||
|
* N Y Y Y
|
||||||
|
* Y N Y N
|
||||||
|
* Y Y N -
|
||||||
|
*
|
||||||
|
* IB N N Y N
|
||||||
|
* N Y N -
|
||||||
|
* Y N Y N
|
||||||
|
* Y Y N -
|
||||||
|
*
|
||||||
|
* NB: iWARP requires remote write access for the data sink
|
||||||
|
* of an RDMA_READ. IB does not.
|
||||||
|
*/
|
||||||
|
if (devattr.device_cap_flags & IB_DEVICE_MEM_MGT_EXTENSIONS) {
|
||||||
|
newxprt->sc_frmr_pg_list_len =
|
||||||
|
devattr.max_fast_reg_page_list_len;
|
||||||
|
newxprt->sc_dev_caps |= SVCRDMA_DEVCAP_FAST_REG;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Determine if a DMA MR is required and if so, what privs are required
|
||||||
|
*/
|
||||||
|
switch (rdma_node_get_transport(newxprt->sc_cm_id->device->node_type)) {
|
||||||
|
case RDMA_TRANSPORT_IWARP:
|
||||||
|
newxprt->sc_dev_caps |= SVCRDMA_DEVCAP_READ_W_INV;
|
||||||
|
if (!(newxprt->sc_dev_caps & SVCRDMA_DEVCAP_FAST_REG)) {
|
||||||
|
need_dma_mr = 1;
|
||||||
|
dma_mr_acc =
|
||||||
|
(IB_ACCESS_LOCAL_WRITE |
|
||||||
IB_ACCESS_REMOTE_WRITE);
|
IB_ACCESS_REMOTE_WRITE);
|
||||||
if (IS_ERR(newxprt->sc_phys_mr)) {
|
} else if (!(devattr.device_cap_flags & IB_DEVICE_LOCAL_DMA_LKEY)) {
|
||||||
dprintk("svcrdma: Failed to create DMA MR ret=%d\n", ret);
|
need_dma_mr = 1;
|
||||||
|
dma_mr_acc = IB_ACCESS_LOCAL_WRITE;
|
||||||
|
} else
|
||||||
|
need_dma_mr = 0;
|
||||||
|
break;
|
||||||
|
case RDMA_TRANSPORT_IB:
|
||||||
|
if (!(devattr.device_cap_flags & IB_DEVICE_LOCAL_DMA_LKEY)) {
|
||||||
|
need_dma_mr = 1;
|
||||||
|
dma_mr_acc = IB_ACCESS_LOCAL_WRITE;
|
||||||
|
} else
|
||||||
|
need_dma_mr = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
goto errout;
|
goto errout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Create the DMA MR if needed, otherwise, use the DMA LKEY */
|
||||||
|
if (need_dma_mr) {
|
||||||
|
/* Register all of physical memory */
|
||||||
|
newxprt->sc_phys_mr =
|
||||||
|
ib_get_dma_mr(newxprt->sc_pd, dma_mr_acc);
|
||||||
|
if (IS_ERR(newxprt->sc_phys_mr)) {
|
||||||
|
dprintk("svcrdma: Failed to create DMA MR ret=%d\n",
|
||||||
|
ret);
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
newxprt->sc_dma_lkey = newxprt->sc_phys_mr->lkey;
|
||||||
|
} else
|
||||||
|
newxprt->sc_dma_lkey =
|
||||||
|
newxprt->sc_cm_id->device->local_dma_lkey;
|
||||||
|
|
||||||
/* Post receive buffers */
|
/* Post receive buffers */
|
||||||
for (i = 0; i < newxprt->sc_max_requests; i++) {
|
for (i = 0; i < newxprt->sc_max_requests; i++) {
|
||||||
ret = svc_rdma_post_recv(newxprt);
|
ret = svc_rdma_post_recv(newxprt);
|
||||||
|
@ -961,6 +1148,9 @@ static void __svc_rdma_free(struct work_struct *work)
|
||||||
WARN_ON(atomic_read(&rdma->sc_ctxt_used) != 0);
|
WARN_ON(atomic_read(&rdma->sc_ctxt_used) != 0);
|
||||||
WARN_ON(atomic_read(&rdma->sc_dma_used) != 0);
|
WARN_ON(atomic_read(&rdma->sc_dma_used) != 0);
|
||||||
|
|
||||||
|
/* De-allocate fastreg mr */
|
||||||
|
rdma_dealloc_frmr_q(rdma);
|
||||||
|
|
||||||
/* Destroy the QP if present (not a listener) */
|
/* Destroy the QP if present (not a listener) */
|
||||||
if (rdma->sc_qp && !IS_ERR(rdma->sc_qp))
|
if (rdma->sc_qp && !IS_ERR(rdma->sc_qp))
|
||||||
ib_destroy_qp(rdma->sc_qp);
|
ib_destroy_qp(rdma->sc_qp);
|
||||||
|
@ -1014,21 +1204,59 @@ static int svc_rdma_has_wspace(struct svc_xprt *xprt)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Attempt to register the kvec representing the RPC memory with the
|
||||||
|
* device.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* NULL : The device does not support fastreg or there were no more
|
||||||
|
* fastreg mr.
|
||||||
|
* frmr : The kvec register request was successfully posted.
|
||||||
|
* <0 : An error was encountered attempting to register the kvec.
|
||||||
|
*/
|
||||||
|
int svc_rdma_fastreg(struct svcxprt_rdma *xprt,
|
||||||
|
struct svc_rdma_fastreg_mr *frmr)
|
||||||
|
{
|
||||||
|
struct ib_send_wr fastreg_wr;
|
||||||
|
u8 key;
|
||||||
|
|
||||||
|
/* Bump the key */
|
||||||
|
key = (u8)(frmr->mr->lkey & 0x000000FF);
|
||||||
|
ib_update_fast_reg_key(frmr->mr, ++key);
|
||||||
|
|
||||||
|
/* Prepare FASTREG WR */
|
||||||
|
memset(&fastreg_wr, 0, sizeof fastreg_wr);
|
||||||
|
fastreg_wr.opcode = IB_WR_FAST_REG_MR;
|
||||||
|
fastreg_wr.send_flags = IB_SEND_SIGNALED;
|
||||||
|
fastreg_wr.wr.fast_reg.iova_start = (unsigned long)frmr->kva;
|
||||||
|
fastreg_wr.wr.fast_reg.page_list = frmr->page_list;
|
||||||
|
fastreg_wr.wr.fast_reg.page_list_len = frmr->page_list_len;
|
||||||
|
fastreg_wr.wr.fast_reg.page_shift = PAGE_SHIFT;
|
||||||
|
fastreg_wr.wr.fast_reg.length = frmr->map_len;
|
||||||
|
fastreg_wr.wr.fast_reg.access_flags = frmr->access_flags;
|
||||||
|
fastreg_wr.wr.fast_reg.rkey = frmr->mr->lkey;
|
||||||
|
return svc_rdma_send(xprt, &fastreg_wr);
|
||||||
|
}
|
||||||
|
|
||||||
int svc_rdma_send(struct svcxprt_rdma *xprt, struct ib_send_wr *wr)
|
int svc_rdma_send(struct svcxprt_rdma *xprt, struct ib_send_wr *wr)
|
||||||
{
|
{
|
||||||
struct ib_send_wr *bad_wr;
|
struct ib_send_wr *bad_wr, *n_wr;
|
||||||
|
int wr_count;
|
||||||
|
int i;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (test_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags))
|
if (test_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags))
|
||||||
return -ENOTCONN;
|
return -ENOTCONN;
|
||||||
|
|
||||||
BUG_ON(wr->send_flags != IB_SEND_SIGNALED);
|
BUG_ON(wr->send_flags != IB_SEND_SIGNALED);
|
||||||
BUG_ON(((struct svc_rdma_op_ctxt *)(unsigned long)wr->wr_id)->wr_op !=
|
wr_count = 1;
|
||||||
wr->opcode);
|
for (n_wr = wr->next; n_wr; n_wr = n_wr->next)
|
||||||
|
wr_count++;
|
||||||
|
|
||||||
/* If the SQ is full, wait until an SQ entry is available */
|
/* If the SQ is full, wait until an SQ entry is available */
|
||||||
while (1) {
|
while (1) {
|
||||||
spin_lock_bh(&xprt->sc_lock);
|
spin_lock_bh(&xprt->sc_lock);
|
||||||
if (xprt->sc_sq_depth == atomic_read(&xprt->sc_sq_count)) {
|
if (xprt->sc_sq_depth < atomic_read(&xprt->sc_sq_count) + wr_count) {
|
||||||
spin_unlock_bh(&xprt->sc_lock);
|
spin_unlock_bh(&xprt->sc_lock);
|
||||||
atomic_inc(&rdma_stat_sq_starve);
|
atomic_inc(&rdma_stat_sq_starve);
|
||||||
|
|
||||||
|
@ -1043,12 +1271,17 @@ int svc_rdma_send(struct svcxprt_rdma *xprt, struct ib_send_wr *wr)
|
||||||
return 0;
|
return 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/* Bumped used SQ WR count and post */
|
/* Take a transport ref for each WR posted */
|
||||||
|
for (i = 0; i < wr_count; i++)
|
||||||
svc_xprt_get(&xprt->sc_xprt);
|
svc_xprt_get(&xprt->sc_xprt);
|
||||||
|
|
||||||
|
/* Bump used SQ WR count and post */
|
||||||
|
atomic_add(wr_count, &xprt->sc_sq_count);
|
||||||
ret = ib_post_send(xprt->sc_qp, wr, &bad_wr);
|
ret = ib_post_send(xprt->sc_qp, wr, &bad_wr);
|
||||||
if (!ret)
|
if (ret) {
|
||||||
atomic_inc(&xprt->sc_sq_count);
|
set_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags);
|
||||||
else {
|
atomic_sub(wr_count, &xprt->sc_sq_count);
|
||||||
|
for (i = 0; i < wr_count; i ++)
|
||||||
svc_xprt_put(&xprt->sc_xprt);
|
svc_xprt_put(&xprt->sc_xprt);
|
||||||
dprintk("svcrdma: failed to post SQ WR rc=%d, "
|
dprintk("svcrdma: failed to post SQ WR rc=%d, "
|
||||||
"sc_sq_count=%d, sc_sq_depth=%d\n",
|
"sc_sq_count=%d, sc_sq_depth=%d\n",
|
||||||
|
@ -1056,6 +1289,8 @@ int svc_rdma_send(struct svcxprt_rdma *xprt, struct ib_send_wr *wr)
|
||||||
xprt->sc_sq_depth);
|
xprt->sc_sq_depth);
|
||||||
}
|
}
|
||||||
spin_unlock_bh(&xprt->sc_lock);
|
spin_unlock_bh(&xprt->sc_lock);
|
||||||
|
if (ret)
|
||||||
|
wake_up(&xprt->sc_send_wait);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -1079,10 +1314,14 @@ void svc_rdma_send_error(struct svcxprt_rdma *xprt, struct rpcrdma_msg *rmsgp,
|
||||||
length = svc_rdma_xdr_encode_error(xprt, rmsgp, err, va);
|
length = svc_rdma_xdr_encode_error(xprt, rmsgp, err, va);
|
||||||
|
|
||||||
/* Prepare SGE for local address */
|
/* Prepare SGE for local address */
|
||||||
atomic_inc(&xprt->sc_dma_used);
|
|
||||||
sge.addr = ib_dma_map_page(xprt->sc_cm_id->device,
|
sge.addr = ib_dma_map_page(xprt->sc_cm_id->device,
|
||||||
p, 0, PAGE_SIZE, DMA_FROM_DEVICE);
|
p, 0, PAGE_SIZE, DMA_FROM_DEVICE);
|
||||||
sge.lkey = xprt->sc_phys_mr->lkey;
|
if (ib_dma_mapping_error(xprt->sc_cm_id->device, sge.addr)) {
|
||||||
|
put_page(p);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
atomic_inc(&xprt->sc_dma_used);
|
||||||
|
sge.lkey = xprt->sc_dma_lkey;
|
||||||
sge.length = length;
|
sge.length = length;
|
||||||
|
|
||||||
ctxt = svc_rdma_get_context(xprt);
|
ctxt = svc_rdma_get_context(xprt);
|
||||||
|
@ -1103,6 +1342,9 @@ void svc_rdma_send_error(struct svcxprt_rdma *xprt, struct rpcrdma_msg *rmsgp,
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dprintk("svcrdma: Error %d posting send for protocol error\n",
|
dprintk("svcrdma: Error %d posting send for protocol error\n",
|
||||||
ret);
|
ret);
|
||||||
|
ib_dma_unmap_page(xprt->sc_cm_id->device,
|
||||||
|
sge.addr, PAGE_SIZE,
|
||||||
|
DMA_FROM_DEVICE);
|
||||||
svc_rdma_put_context(ctxt, 1);
|
svc_rdma_put_context(ctxt, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue