forked from Minki/linux
Merge git://git.linux-nfs.org/pub/linux/nfs-2.6
* git://git.linux-nfs.org/pub/linux/nfs-2.6: (74 commits) NFS: unmark NFS direct I/O as experimental NFS: add comments clarifying the use of nfs_post_op_update() NFSv4: rpc_mkpipe creating socket inodes w/out sk buffers NFS: Use SEEK_END instead of hardcoded value NFSv4: When mounting with a port=0 argument, substitute port=2049 NFSv4: Poll more aggressively when handling NFS4ERR_DELAY NFSv4: Handle the condition NFS4ERR_FILE_OPEN NFSv4: Retry lease recovery if it failed during a synchronous operation. NFS: Don't invalidate the symlink we just stuffed into the cache NFS: Make read() return an ESTALE if the file has been deleted NFSv4: It's perfectly legal for clp to be NULL here.... NFS: nfs_lookup - don't hash dentry when optimising away the lookup SUNRPC: Fix Oops in pmap_getport_done SUNRPC: Add refcounting to the struct rpc_xprt SUNRPC: Clean up soft task error handling SUNRPC: Handle ENETUNREACH, EHOSTUNREACH and EHOSTDOWN socket errors SUNRPC: rpc_delay() should not clobber the rpc_task->tk_status Fix a referral error Oops NFS: NFS_ROOT should use the new rpc_create API NFS: Fix up compiler warnings on 64-bit platforms in client.c ... Manually resolved conflict in net/sunrpc/xprtsock.c
This commit is contained in:
commit
9f261e0113
@ -2734,6 +2734,18 @@ long blk_congestion_wait(int rw, long timeout)
|
||||
|
||||
EXPORT_SYMBOL(blk_congestion_wait);
|
||||
|
||||
/**
|
||||
* blk_congestion_end - wake up sleepers on a congestion queue
|
||||
* @rw: READ or WRITE
|
||||
*/
|
||||
void blk_congestion_end(int rw)
|
||||
{
|
||||
wait_queue_head_t *wqh = &congestion_wqh[rw];
|
||||
|
||||
if (waitqueue_active(wqh))
|
||||
wake_up(wqh);
|
||||
}
|
||||
|
||||
/*
|
||||
* Has to be called with the request spinlock acquired
|
||||
*/
|
||||
|
@ -1471,8 +1471,8 @@ config NFS_V4
|
||||
If unsure, say N.
|
||||
|
||||
config NFS_DIRECTIO
|
||||
bool "Allow direct I/O on NFS files (EXPERIMENTAL)"
|
||||
depends on NFS_FS && EXPERIMENTAL
|
||||
bool "Allow direct I/O on NFS files"
|
||||
depends on NFS_FS
|
||||
help
|
||||
This option enables applications to perform uncached I/O on files
|
||||
in NFS file systems using the O_DIRECT open() flag. When O_DIRECT
|
||||
|
164
fs/dcache.c
164
fs/dcache.c
@ -828,17 +828,19 @@ void d_instantiate(struct dentry *entry, struct inode * inode)
|
||||
* (or otherwise set) by the caller to indicate that it is now
|
||||
* in use by the dcache.
|
||||
*/
|
||||
struct dentry *d_instantiate_unique(struct dentry *entry, struct inode *inode)
|
||||
static struct dentry *__d_instantiate_unique(struct dentry *entry,
|
||||
struct inode *inode)
|
||||
{
|
||||
struct dentry *alias;
|
||||
int len = entry->d_name.len;
|
||||
const char *name = entry->d_name.name;
|
||||
unsigned int hash = entry->d_name.hash;
|
||||
|
||||
BUG_ON(!list_empty(&entry->d_alias));
|
||||
spin_lock(&dcache_lock);
|
||||
if (!inode)
|
||||
goto do_negative;
|
||||
if (!inode) {
|
||||
entry->d_inode = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list_for_each_entry(alias, &inode->i_dentry, d_alias) {
|
||||
struct qstr *qstr = &alias->d_name;
|
||||
|
||||
@ -851,19 +853,35 @@ struct dentry *d_instantiate_unique(struct dentry *entry, struct inode *inode)
|
||||
if (memcmp(qstr->name, name, len))
|
||||
continue;
|
||||
dget_locked(alias);
|
||||
spin_unlock(&dcache_lock);
|
||||
BUG_ON(!d_unhashed(alias));
|
||||
iput(inode);
|
||||
return alias;
|
||||
}
|
||||
|
||||
list_add(&entry->d_alias, &inode->i_dentry);
|
||||
do_negative:
|
||||
entry->d_inode = inode;
|
||||
fsnotify_d_instantiate(entry, inode);
|
||||
spin_unlock(&dcache_lock);
|
||||
security_d_instantiate(entry, inode);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct dentry *d_instantiate_unique(struct dentry *entry, struct inode *inode)
|
||||
{
|
||||
struct dentry *result;
|
||||
|
||||
BUG_ON(!list_empty(&entry->d_alias));
|
||||
|
||||
spin_lock(&dcache_lock);
|
||||
result = __d_instantiate_unique(entry, inode);
|
||||
spin_unlock(&dcache_lock);
|
||||
|
||||
if (!result) {
|
||||
security_d_instantiate(entry, inode);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BUG_ON(!d_unhashed(result));
|
||||
iput(inode);
|
||||
return result;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(d_instantiate_unique);
|
||||
|
||||
/**
|
||||
@ -1235,6 +1253,11 @@ static void __d_rehash(struct dentry * entry, struct hlist_head *list)
|
||||
hlist_add_head_rcu(&entry->d_hash, list);
|
||||
}
|
||||
|
||||
static void _d_rehash(struct dentry * entry)
|
||||
{
|
||||
__d_rehash(entry, d_hash(entry->d_parent, entry->d_name.hash));
|
||||
}
|
||||
|
||||
/**
|
||||
* d_rehash - add an entry back to the hash
|
||||
* @entry: dentry to add to the hash
|
||||
@ -1244,11 +1267,9 @@ static void __d_rehash(struct dentry * entry, struct hlist_head *list)
|
||||
|
||||
void d_rehash(struct dentry * entry)
|
||||
{
|
||||
struct hlist_head *list = d_hash(entry->d_parent, entry->d_name.hash);
|
||||
|
||||
spin_lock(&dcache_lock);
|
||||
spin_lock(&entry->d_lock);
|
||||
__d_rehash(entry, list);
|
||||
_d_rehash(entry);
|
||||
spin_unlock(&entry->d_lock);
|
||||
spin_unlock(&dcache_lock);
|
||||
}
|
||||
@ -1386,6 +1407,120 @@ already_unhashed:
|
||||
spin_unlock(&dcache_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Prepare an anonymous dentry for life in the superblock's dentry tree as a
|
||||
* named dentry in place of the dentry to be replaced.
|
||||
*/
|
||||
static void __d_materialise_dentry(struct dentry *dentry, struct dentry *anon)
|
||||
{
|
||||
struct dentry *dparent, *aparent;
|
||||
|
||||
switch_names(dentry, anon);
|
||||
do_switch(dentry->d_name.len, anon->d_name.len);
|
||||
do_switch(dentry->d_name.hash, anon->d_name.hash);
|
||||
|
||||
dparent = dentry->d_parent;
|
||||
aparent = anon->d_parent;
|
||||
|
||||
dentry->d_parent = (aparent == anon) ? dentry : aparent;
|
||||
list_del(&dentry->d_u.d_child);
|
||||
if (!IS_ROOT(dentry))
|
||||
list_add(&dentry->d_u.d_child, &dentry->d_parent->d_subdirs);
|
||||
else
|
||||
INIT_LIST_HEAD(&dentry->d_u.d_child);
|
||||
|
||||
anon->d_parent = (dparent == dentry) ? anon : dparent;
|
||||
list_del(&anon->d_u.d_child);
|
||||
if (!IS_ROOT(anon))
|
||||
list_add(&anon->d_u.d_child, &anon->d_parent->d_subdirs);
|
||||
else
|
||||
INIT_LIST_HEAD(&anon->d_u.d_child);
|
||||
|
||||
anon->d_flags &= ~DCACHE_DISCONNECTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* d_materialise_unique - introduce an inode into the tree
|
||||
* @dentry: candidate dentry
|
||||
* @inode: inode to bind to the dentry, to which aliases may be attached
|
||||
*
|
||||
* Introduces an dentry into the tree, substituting an extant disconnected
|
||||
* root directory alias in its place if there is one
|
||||
*/
|
||||
struct dentry *d_materialise_unique(struct dentry *dentry, struct inode *inode)
|
||||
{
|
||||
struct dentry *alias, *actual;
|
||||
|
||||
BUG_ON(!d_unhashed(dentry));
|
||||
|
||||
spin_lock(&dcache_lock);
|
||||
|
||||
if (!inode) {
|
||||
actual = dentry;
|
||||
dentry->d_inode = NULL;
|
||||
goto found_lock;
|
||||
}
|
||||
|
||||
/* See if a disconnected directory already exists as an anonymous root
|
||||
* that we should splice into the tree instead */
|
||||
if (S_ISDIR(inode->i_mode) && (alias = __d_find_alias(inode, 1))) {
|
||||
spin_lock(&alias->d_lock);
|
||||
|
||||
/* Is this a mountpoint that we could splice into our tree? */
|
||||
if (IS_ROOT(alias))
|
||||
goto connect_mountpoint;
|
||||
|
||||
if (alias->d_name.len == dentry->d_name.len &&
|
||||
alias->d_parent == dentry->d_parent &&
|
||||
memcmp(alias->d_name.name,
|
||||
dentry->d_name.name,
|
||||
dentry->d_name.len) == 0)
|
||||
goto replace_with_alias;
|
||||
|
||||
spin_unlock(&alias->d_lock);
|
||||
|
||||
/* Doh! Seem to be aliasing directories for some reason... */
|
||||
dput(alias);
|
||||
}
|
||||
|
||||
/* Add a unique reference */
|
||||
actual = __d_instantiate_unique(dentry, inode);
|
||||
if (!actual)
|
||||
actual = dentry;
|
||||
else if (unlikely(!d_unhashed(actual)))
|
||||
goto shouldnt_be_hashed;
|
||||
|
||||
found_lock:
|
||||
spin_lock(&actual->d_lock);
|
||||
found:
|
||||
_d_rehash(actual);
|
||||
spin_unlock(&actual->d_lock);
|
||||
spin_unlock(&dcache_lock);
|
||||
|
||||
if (actual == dentry) {
|
||||
security_d_instantiate(dentry, inode);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
iput(inode);
|
||||
return actual;
|
||||
|
||||
/* Convert the anonymous/root alias into an ordinary dentry */
|
||||
connect_mountpoint:
|
||||
__d_materialise_dentry(dentry, alias);
|
||||
|
||||
/* Replace the candidate dentry with the alias in the tree */
|
||||
replace_with_alias:
|
||||
__d_drop(alias);
|
||||
actual = alias;
|
||||
goto found;
|
||||
|
||||
shouldnt_be_hashed:
|
||||
spin_unlock(&dcache_lock);
|
||||
BUG();
|
||||
goto shouldnt_be_hashed;
|
||||
}
|
||||
|
||||
/**
|
||||
* d_path - return the path of a dentry
|
||||
* @dentry: dentry to report
|
||||
@ -1784,6 +1919,7 @@ EXPORT_SYMBOL(d_instantiate);
|
||||
EXPORT_SYMBOL(d_invalidate);
|
||||
EXPORT_SYMBOL(d_lookup);
|
||||
EXPORT_SYMBOL(d_move);
|
||||
EXPORT_SYMBOL_GPL(d_materialise_unique);
|
||||
EXPORT_SYMBOL(d_path);
|
||||
EXPORT_SYMBOL(d_prune_aliases);
|
||||
EXPORT_SYMBOL(d_rehash);
|
||||
|
@ -151,11 +151,13 @@ static void nlmclnt_release_lockargs(struct nlm_rqst *req)
|
||||
int
|
||||
nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl)
|
||||
{
|
||||
struct rpc_clnt *client = NFS_CLIENT(inode);
|
||||
struct sockaddr_in addr;
|
||||
struct nlm_host *host;
|
||||
struct nlm_rqst *call;
|
||||
sigset_t oldset;
|
||||
unsigned long flags;
|
||||
int status, proto, vers;
|
||||
int status, vers;
|
||||
|
||||
vers = (NFS_PROTO(inode)->version == 3) ? 4 : 1;
|
||||
if (NFS_PROTO(inode)->version > 3) {
|
||||
@ -163,10 +165,8 @@ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl)
|
||||
return -ENOLCK;
|
||||
}
|
||||
|
||||
/* Retrieve transport protocol from NFS client */
|
||||
proto = NFS_CLIENT(inode)->cl_xprt->prot;
|
||||
|
||||
host = nlmclnt_lookup_host(NFS_ADDR(inode), proto, vers);
|
||||
rpc_peeraddr(client, (struct sockaddr *) &addr, sizeof(addr));
|
||||
host = nlmclnt_lookup_host(&addr, client->cl_xprt->prot, vers);
|
||||
if (host == NULL)
|
||||
return -ENOLCK;
|
||||
|
||||
|
@ -26,7 +26,6 @@
|
||||
#define NLM_HOST_REBIND (60 * HZ)
|
||||
#define NLM_HOST_EXPIRE ((nrhosts > NLM_HOST_MAX)? 300 * HZ : 120 * HZ)
|
||||
#define NLM_HOST_COLLECT ((nrhosts > NLM_HOST_MAX)? 120 * HZ : 60 * HZ)
|
||||
#define NLM_HOST_ADDR(sv) (&(sv)->s_nlmclnt->cl_xprt->addr)
|
||||
|
||||
static struct nlm_host * nlm_hosts[NLM_HOST_NRHASH];
|
||||
static unsigned long next_gc;
|
||||
@ -167,7 +166,6 @@ struct rpc_clnt *
|
||||
nlm_bind_host(struct nlm_host *host)
|
||||
{
|
||||
struct rpc_clnt *clnt;
|
||||
struct rpc_xprt *xprt;
|
||||
|
||||
dprintk("lockd: nlm_bind_host(%08x)\n",
|
||||
(unsigned)ntohl(host->h_addr.sin_addr.s_addr));
|
||||
@ -179,7 +177,6 @@ nlm_bind_host(struct nlm_host *host)
|
||||
* RPC rebind is required
|
||||
*/
|
||||
if ((clnt = host->h_rpcclnt) != NULL) {
|
||||
xprt = clnt->cl_xprt;
|
||||
if (time_after_eq(jiffies, host->h_nextrebind)) {
|
||||
rpc_force_rebind(clnt);
|
||||
host->h_nextrebind = jiffies + NLM_HOST_REBIND;
|
||||
@ -187,31 +184,37 @@ nlm_bind_host(struct nlm_host *host)
|
||||
host->h_nextrebind - jiffies);
|
||||
}
|
||||
} else {
|
||||
xprt = xprt_create_proto(host->h_proto, &host->h_addr, NULL);
|
||||
if (IS_ERR(xprt))
|
||||
goto forgetit;
|
||||
unsigned long increment = nlmsvc_timeout * HZ;
|
||||
struct rpc_timeout timeparms = {
|
||||
.to_initval = increment,
|
||||
.to_increment = increment,
|
||||
.to_maxval = increment * 6UL,
|
||||
.to_retries = 5U,
|
||||
};
|
||||
struct rpc_create_args args = {
|
||||
.protocol = host->h_proto,
|
||||
.address = (struct sockaddr *)&host->h_addr,
|
||||
.addrsize = sizeof(host->h_addr),
|
||||
.timeout = &timeparms,
|
||||
.servername = host->h_name,
|
||||
.program = &nlm_program,
|
||||
.version = host->h_version,
|
||||
.authflavor = RPC_AUTH_UNIX,
|
||||
.flags = (RPC_CLNT_CREATE_HARDRTRY |
|
||||
RPC_CLNT_CREATE_AUTOBIND),
|
||||
};
|
||||
|
||||
xprt_set_timeout(&xprt->timeout, 5, nlmsvc_timeout);
|
||||
xprt->resvport = 1; /* NLM requires a reserved port */
|
||||
|
||||
/* Existing NLM servers accept AUTH_UNIX only */
|
||||
clnt = rpc_new_client(xprt, host->h_name, &nlm_program,
|
||||
host->h_version, RPC_AUTH_UNIX);
|
||||
if (IS_ERR(clnt))
|
||||
goto forgetit;
|
||||
clnt->cl_autobind = 1; /* turn on pmap queries */
|
||||
clnt->cl_softrtry = 1; /* All queries are soft */
|
||||
|
||||
host->h_rpcclnt = clnt;
|
||||
clnt = rpc_create(&args);
|
||||
if (!IS_ERR(clnt))
|
||||
host->h_rpcclnt = clnt;
|
||||
else {
|
||||
printk("lockd: couldn't create RPC handle for %s\n", host->h_name);
|
||||
clnt = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&host->h_mutex);
|
||||
return clnt;
|
||||
|
||||
forgetit:
|
||||
printk("lockd: couldn't create RPC handle for %s\n", host->h_name);
|
||||
mutex_unlock(&host->h_mutex);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -109,30 +109,23 @@ nsm_unmonitor(struct nlm_host *host)
|
||||
static struct rpc_clnt *
|
||||
nsm_create(void)
|
||||
{
|
||||
struct rpc_xprt *xprt;
|
||||
struct rpc_clnt *clnt;
|
||||
struct sockaddr_in sin;
|
||||
struct sockaddr_in sin = {
|
||||
.sin_family = AF_INET,
|
||||
.sin_addr.s_addr = htonl(INADDR_LOOPBACK),
|
||||
.sin_port = 0,
|
||||
};
|
||||
struct rpc_create_args args = {
|
||||
.protocol = IPPROTO_UDP,
|
||||
.address = (struct sockaddr *)&sin,
|
||||
.addrsize = sizeof(sin),
|
||||
.servername = "localhost",
|
||||
.program = &nsm_program,
|
||||
.version = SM_VERSION,
|
||||
.authflavor = RPC_AUTH_NULL,
|
||||
.flags = (RPC_CLNT_CREATE_ONESHOT),
|
||||
};
|
||||
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
sin.sin_port = 0;
|
||||
|
||||
xprt = xprt_create_proto(IPPROTO_UDP, &sin, NULL);
|
||||
if (IS_ERR(xprt))
|
||||
return (struct rpc_clnt *)xprt;
|
||||
xprt->resvport = 1; /* NSM requires a reserved port */
|
||||
|
||||
clnt = rpc_create_client(xprt, "localhost",
|
||||
&nsm_program, SM_VERSION,
|
||||
RPC_AUTH_NULL);
|
||||
if (IS_ERR(clnt))
|
||||
goto out_err;
|
||||
clnt->cl_softrtry = 1;
|
||||
clnt->cl_oneshot = 1;
|
||||
return clnt;
|
||||
|
||||
out_err:
|
||||
return clnt;
|
||||
return rpc_create(&args);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -4,9 +4,9 @@
|
||||
|
||||
obj-$(CONFIG_NFS_FS) += nfs.o
|
||||
|
||||
nfs-y := dir.o file.o inode.o super.o nfs2xdr.o pagelist.o \
|
||||
proc.o read.o symlink.o unlink.o write.o \
|
||||
namespace.o
|
||||
nfs-y := client.o dir.o file.o getroot.o inode.o super.o nfs2xdr.o \
|
||||
pagelist.o proc.o read.o symlink.o unlink.o \
|
||||
write.o namespace.o
|
||||
nfs-$(CONFIG_ROOT_NFS) += nfsroot.o mount_clnt.o
|
||||
nfs-$(CONFIG_NFS_V3) += nfs3proc.o nfs3xdr.o
|
||||
nfs-$(CONFIG_NFS_V3_ACL) += nfs3acl.o
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
#include "nfs4_fs.h"
|
||||
#include "callback.h"
|
||||
#include "internal.h"
|
||||
|
||||
#define NFSDBG_FACILITY NFSDBG_CALLBACK
|
||||
|
||||
@ -36,6 +37,21 @@ static struct svc_program nfs4_callback_program;
|
||||
|
||||
unsigned int nfs_callback_set_tcpport;
|
||||
unsigned short nfs_callback_tcpport;
|
||||
static const int nfs_set_port_min = 0;
|
||||
static const int nfs_set_port_max = 65535;
|
||||
|
||||
static int param_set_port(const char *val, struct kernel_param *kp)
|
||||
{
|
||||
char *endp;
|
||||
int num = simple_strtol(val, &endp, 0);
|
||||
if (endp == val || *endp || num < nfs_set_port_min || num > nfs_set_port_max)
|
||||
return -EINVAL;
|
||||
*((int *)kp->arg) = num;
|
||||
return 0;
|
||||
}
|
||||
|
||||
module_param_call(callback_tcpport, param_set_port, param_get_int,
|
||||
&nfs_callback_set_tcpport, 0644);
|
||||
|
||||
/*
|
||||
* This is the callback kernel thread.
|
||||
@ -134,10 +150,8 @@ out_err:
|
||||
/*
|
||||
* Kill the server process if it is not already up.
|
||||
*/
|
||||
int nfs_callback_down(void)
|
||||
void nfs_callback_down(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
lock_kernel();
|
||||
mutex_lock(&nfs_callback_mutex);
|
||||
nfs_callback_info.users--;
|
||||
@ -149,20 +163,19 @@ int nfs_callback_down(void)
|
||||
} while (wait_for_completion_timeout(&nfs_callback_info.stopped, 5*HZ) == 0);
|
||||
mutex_unlock(&nfs_callback_mutex);
|
||||
unlock_kernel();
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int nfs_callback_authenticate(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct in_addr *addr = &rqstp->rq_addr.sin_addr;
|
||||
struct nfs4_client *clp;
|
||||
struct sockaddr_in *addr = &rqstp->rq_addr;
|
||||
struct nfs_client *clp;
|
||||
|
||||
/* Don't talk to strangers */
|
||||
clp = nfs4_find_client(addr);
|
||||
clp = nfs_find_client(addr, 4);
|
||||
if (clp == NULL)
|
||||
return SVC_DROP;
|
||||
dprintk("%s: %u.%u.%u.%u NFSv4 callback!\n", __FUNCTION__, NIPQUAD(addr));
|
||||
nfs4_put_client(clp);
|
||||
dprintk("%s: %u.%u.%u.%u NFSv4 callback!\n", __FUNCTION__, NIPQUAD(addr->sin_addr));
|
||||
nfs_put_client(clp);
|
||||
switch (rqstp->rq_authop->flavour) {
|
||||
case RPC_AUTH_NULL:
|
||||
if (rqstp->rq_proc != CB_NULL)
|
||||
|
@ -62,8 +62,13 @@ struct cb_recallargs {
|
||||
extern unsigned nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res);
|
||||
extern unsigned nfs4_callback_recall(struct cb_recallargs *args, void *dummy);
|
||||
|
||||
#ifdef CONFIG_NFS_V4
|
||||
extern int nfs_callback_up(void);
|
||||
extern int nfs_callback_down(void);
|
||||
extern void nfs_callback_down(void);
|
||||
#else
|
||||
#define nfs_callback_up() (0)
|
||||
#define nfs_callback_down() do {} while(0)
|
||||
#endif
|
||||
|
||||
extern unsigned int nfs_callback_set_tcpport;
|
||||
extern unsigned short nfs_callback_tcpport;
|
||||
|
@ -10,19 +10,20 @@
|
||||
#include "nfs4_fs.h"
|
||||
#include "callback.h"
|
||||
#include "delegation.h"
|
||||
#include "internal.h"
|
||||
|
||||
#define NFSDBG_FACILITY NFSDBG_CALLBACK
|
||||
|
||||
unsigned nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res)
|
||||
{
|
||||
struct nfs4_client *clp;
|
||||
struct nfs_client *clp;
|
||||
struct nfs_delegation *delegation;
|
||||
struct nfs_inode *nfsi;
|
||||
struct inode *inode;
|
||||
|
||||
res->bitmap[0] = res->bitmap[1] = 0;
|
||||
res->status = htonl(NFS4ERR_BADHANDLE);
|
||||
clp = nfs4_find_client(&args->addr->sin_addr);
|
||||
clp = nfs_find_client(args->addr, 4);
|
||||
if (clp == NULL)
|
||||
goto out;
|
||||
inode = nfs_delegation_find_inode(clp, &args->fh);
|
||||
@ -48,7 +49,7 @@ out_iput:
|
||||
up_read(&nfsi->rwsem);
|
||||
iput(inode);
|
||||
out_putclient:
|
||||
nfs4_put_client(clp);
|
||||
nfs_put_client(clp);
|
||||
out:
|
||||
dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(res->status));
|
||||
return res->status;
|
||||
@ -56,12 +57,12 @@ out:
|
||||
|
||||
unsigned nfs4_callback_recall(struct cb_recallargs *args, void *dummy)
|
||||
{
|
||||
struct nfs4_client *clp;
|
||||
struct nfs_client *clp;
|
||||
struct inode *inode;
|
||||
unsigned res;
|
||||
|
||||
res = htonl(NFS4ERR_BADHANDLE);
|
||||
clp = nfs4_find_client(&args->addr->sin_addr);
|
||||
clp = nfs_find_client(args->addr, 4);
|
||||
if (clp == NULL)
|
||||
goto out;
|
||||
inode = nfs_delegation_find_inode(clp, &args->fh);
|
||||
@ -80,7 +81,7 @@ unsigned nfs4_callback_recall(struct cb_recallargs *args, void *dummy)
|
||||
}
|
||||
iput(inode);
|
||||
out_putclient:
|
||||
nfs4_put_client(clp);
|
||||
nfs_put_client(clp);
|
||||
out:
|
||||
dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(res));
|
||||
return res;
|
||||
|
1448
fs/nfs/client.c
Normal file
1448
fs/nfs/client.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -18,6 +18,7 @@
|
||||
|
||||
#include "nfs4_fs.h"
|
||||
#include "delegation.h"
|
||||
#include "internal.h"
|
||||
|
||||
static struct nfs_delegation *nfs_alloc_delegation(void)
|
||||
{
|
||||
@ -52,7 +53,7 @@ static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_
|
||||
case -NFS4ERR_EXPIRED:
|
||||
/* kill_proc(fl->fl_pid, SIGLOST, 1); */
|
||||
case -NFS4ERR_STALE_CLIENTID:
|
||||
nfs4_schedule_state_recovery(NFS_SERVER(inode)->nfs4_state);
|
||||
nfs4_schedule_state_recovery(NFS_SERVER(inode)->nfs_client);
|
||||
goto out_err;
|
||||
}
|
||||
}
|
||||
@ -114,7 +115,7 @@ void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, st
|
||||
*/
|
||||
int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res)
|
||||
{
|
||||
struct nfs4_client *clp = NFS_SERVER(inode)->nfs4_state;
|
||||
struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
|
||||
struct nfs_inode *nfsi = NFS_I(inode);
|
||||
struct nfs_delegation *delegation;
|
||||
int status = 0;
|
||||
@ -145,7 +146,7 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
|
||||
sizeof(delegation->stateid)) != 0 ||
|
||||
delegation->type != nfsi->delegation->type) {
|
||||
printk("%s: server %u.%u.%u.%u, handed out a duplicate delegation!\n",
|
||||
__FUNCTION__, NIPQUAD(clp->cl_addr));
|
||||
__FUNCTION__, NIPQUAD(clp->cl_addr.sin_addr));
|
||||
status = -EIO;
|
||||
}
|
||||
}
|
||||
@ -176,7 +177,7 @@ static void nfs_msync_inode(struct inode *inode)
|
||||
*/
|
||||
int __nfs_inode_return_delegation(struct inode *inode)
|
||||
{
|
||||
struct nfs4_client *clp = NFS_SERVER(inode)->nfs4_state;
|
||||
struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
|
||||
struct nfs_inode *nfsi = NFS_I(inode);
|
||||
struct nfs_delegation *delegation;
|
||||
int res = 0;
|
||||
@ -208,7 +209,7 @@ int __nfs_inode_return_delegation(struct inode *inode)
|
||||
*/
|
||||
void nfs_return_all_delegations(struct super_block *sb)
|
||||
{
|
||||
struct nfs4_client *clp = NFS_SB(sb)->nfs4_state;
|
||||
struct nfs_client *clp = NFS_SB(sb)->nfs_client;
|
||||
struct nfs_delegation *delegation;
|
||||
struct inode *inode;
|
||||
|
||||
@ -232,7 +233,7 @@ restart:
|
||||
|
||||
int nfs_do_expire_all_delegations(void *ptr)
|
||||
{
|
||||
struct nfs4_client *clp = ptr;
|
||||
struct nfs_client *clp = ptr;
|
||||
struct nfs_delegation *delegation;
|
||||
struct inode *inode;
|
||||
|
||||
@ -254,11 +255,11 @@ restart:
|
||||
}
|
||||
out:
|
||||
spin_unlock(&clp->cl_lock);
|
||||
nfs4_put_client(clp);
|
||||
nfs_put_client(clp);
|
||||
module_put_and_exit(0);
|
||||
}
|
||||
|
||||
void nfs_expire_all_delegations(struct nfs4_client *clp)
|
||||
void nfs_expire_all_delegations(struct nfs_client *clp)
|
||||
{
|
||||
struct task_struct *task;
|
||||
|
||||
@ -266,17 +267,17 @@ void nfs_expire_all_delegations(struct nfs4_client *clp)
|
||||
atomic_inc(&clp->cl_count);
|
||||
task = kthread_run(nfs_do_expire_all_delegations, clp,
|
||||
"%u.%u.%u.%u-delegreturn",
|
||||
NIPQUAD(clp->cl_addr));
|
||||
NIPQUAD(clp->cl_addr.sin_addr));
|
||||
if (!IS_ERR(task))
|
||||
return;
|
||||
nfs4_put_client(clp);
|
||||
nfs_put_client(clp);
|
||||
module_put(THIS_MODULE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return all delegations following an NFS4ERR_CB_PATH_DOWN error.
|
||||
*/
|
||||
void nfs_handle_cb_pathdown(struct nfs4_client *clp)
|
||||
void nfs_handle_cb_pathdown(struct nfs_client *clp)
|
||||
{
|
||||
struct nfs_delegation *delegation;
|
||||
struct inode *inode;
|
||||
@ -299,7 +300,7 @@ restart:
|
||||
|
||||
struct recall_threadargs {
|
||||
struct inode *inode;
|
||||
struct nfs4_client *clp;
|
||||
struct nfs_client *clp;
|
||||
const nfs4_stateid *stateid;
|
||||
|
||||
struct completion started;
|
||||
@ -310,7 +311,7 @@ static int recall_thread(void *data)
|
||||
{
|
||||
struct recall_threadargs *args = (struct recall_threadargs *)data;
|
||||
struct inode *inode = igrab(args->inode);
|
||||
struct nfs4_client *clp = NFS_SERVER(inode)->nfs4_state;
|
||||
struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
|
||||
struct nfs_inode *nfsi = NFS_I(inode);
|
||||
struct nfs_delegation *delegation;
|
||||
|
||||
@ -371,7 +372,7 @@ out_module_put:
|
||||
/*
|
||||
* Retrieve the inode associated with a delegation
|
||||
*/
|
||||
struct inode *nfs_delegation_find_inode(struct nfs4_client *clp, const struct nfs_fh *fhandle)
|
||||
struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle)
|
||||
{
|
||||
struct nfs_delegation *delegation;
|
||||
struct inode *res = NULL;
|
||||
@ -389,7 +390,7 @@ struct inode *nfs_delegation_find_inode(struct nfs4_client *clp, const struct nf
|
||||
/*
|
||||
* Mark all delegations as needing to be reclaimed
|
||||
*/
|
||||
void nfs_delegation_mark_reclaim(struct nfs4_client *clp)
|
||||
void nfs_delegation_mark_reclaim(struct nfs_client *clp)
|
||||
{
|
||||
struct nfs_delegation *delegation;
|
||||
spin_lock(&clp->cl_lock);
|
||||
@ -401,7 +402,7 @@ void nfs_delegation_mark_reclaim(struct nfs4_client *clp)
|
||||
/*
|
||||
* Reap all unclaimed delegations after reboot recovery is done
|
||||
*/
|
||||
void nfs_delegation_reap_unclaimed(struct nfs4_client *clp)
|
||||
void nfs_delegation_reap_unclaimed(struct nfs_client *clp)
|
||||
{
|
||||
struct nfs_delegation *delegation, *n;
|
||||
LIST_HEAD(head);
|
||||
@ -423,7 +424,7 @@ void nfs_delegation_reap_unclaimed(struct nfs4_client *clp)
|
||||
|
||||
int nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode)
|
||||
{
|
||||
struct nfs4_client *clp = NFS_SERVER(inode)->nfs4_state;
|
||||
struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
|
||||
struct nfs_inode *nfsi = NFS_I(inode);
|
||||
struct nfs_delegation *delegation;
|
||||
int res = 0;
|
||||
|
@ -29,13 +29,13 @@ void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, st
|
||||
int __nfs_inode_return_delegation(struct inode *inode);
|
||||
int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid);
|
||||
|
||||
struct inode *nfs_delegation_find_inode(struct nfs4_client *clp, const struct nfs_fh *fhandle);
|
||||
struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle);
|
||||
void nfs_return_all_delegations(struct super_block *sb);
|
||||
void nfs_expire_all_delegations(struct nfs4_client *clp);
|
||||
void nfs_handle_cb_pathdown(struct nfs4_client *clp);
|
||||
void nfs_expire_all_delegations(struct nfs_client *clp);
|
||||
void nfs_handle_cb_pathdown(struct nfs_client *clp);
|
||||
|
||||
void nfs_delegation_mark_reclaim(struct nfs4_client *clp);
|
||||
void nfs_delegation_reap_unclaimed(struct nfs4_client *clp);
|
||||
void nfs_delegation_mark_reclaim(struct nfs_client *clp);
|
||||
void nfs_delegation_reap_unclaimed(struct nfs_client *clp);
|
||||
|
||||
/* NFSv4 delegation-related procedures */
|
||||
int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid);
|
||||
|
350
fs/nfs/dir.c
350
fs/nfs/dir.c
@ -30,7 +30,9 @@
|
||||
#include <linux/nfs_mount.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/pagevec.h>
|
||||
#include <linux/namei.h>
|
||||
#include <linux/mount.h>
|
||||
|
||||
#include "nfs4_fs.h"
|
||||
#include "delegation.h"
|
||||
@ -870,14 +872,14 @@ int nfs_is_exclusive_create(struct inode *dir, struct nameidata *nd)
|
||||
return (nd->intent.open.flags & O_EXCL) != 0;
|
||||
}
|
||||
|
||||
static inline int nfs_reval_fsid(struct inode *dir,
|
||||
struct nfs_fh *fh, struct nfs_fattr *fattr)
|
||||
static inline int nfs_reval_fsid(struct vfsmount *mnt, struct inode *dir,
|
||||
struct nfs_fh *fh, struct nfs_fattr *fattr)
|
||||
{
|
||||
struct nfs_server *server = NFS_SERVER(dir);
|
||||
|
||||
if (!nfs_fsid_equal(&server->fsid, &fattr->fsid))
|
||||
/* Revalidate fsid on root dir */
|
||||
return __nfs_revalidate_inode(server, dir->i_sb->s_root->d_inode);
|
||||
return __nfs_revalidate_inode(server, mnt->mnt_root->d_inode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -902,9 +904,15 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru
|
||||
|
||||
lock_kernel();
|
||||
|
||||
/* If we're doing an exclusive create, optimize away the lookup */
|
||||
if (nfs_is_exclusive_create(dir, nd))
|
||||
goto no_entry;
|
||||
/*
|
||||
* If we're doing an exclusive create, optimize away the lookup
|
||||
* but don't hash the dentry.
|
||||
*/
|
||||
if (nfs_is_exclusive_create(dir, nd)) {
|
||||
d_instantiate(dentry, NULL);
|
||||
res = NULL;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr);
|
||||
if (error == -ENOENT)
|
||||
@ -913,7 +921,7 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru
|
||||
res = ERR_PTR(error);
|
||||
goto out_unlock;
|
||||
}
|
||||
error = nfs_reval_fsid(dir, &fhandle, &fattr);
|
||||
error = nfs_reval_fsid(nd->mnt, dir, &fhandle, &fattr);
|
||||
if (error < 0) {
|
||||
res = ERR_PTR(error);
|
||||
goto out_unlock;
|
||||
@ -922,8 +930,9 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru
|
||||
res = (struct dentry *)inode;
|
||||
if (IS_ERR(res))
|
||||
goto out_unlock;
|
||||
|
||||
no_entry:
|
||||
res = d_add_unique(dentry, inode);
|
||||
res = d_materialise_unique(dentry, inode);
|
||||
if (res != NULL)
|
||||
dentry = res;
|
||||
nfs_renew_times(dentry);
|
||||
@ -1117,11 +1126,13 @@ static struct dentry *nfs_readdir_lookup(nfs_readdir_descriptor_t *desc)
|
||||
dput(dentry);
|
||||
return NULL;
|
||||
}
|
||||
alias = d_add_unique(dentry, inode);
|
||||
|
||||
alias = d_materialise_unique(dentry, inode);
|
||||
if (alias != NULL) {
|
||||
dput(dentry);
|
||||
dentry = alias;
|
||||
}
|
||||
|
||||
nfs_renew_times(dentry);
|
||||
nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
|
||||
return dentry;
|
||||
@ -1143,23 +1154,22 @@ int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle,
|
||||
struct inode *dir = dentry->d_parent->d_inode;
|
||||
error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr);
|
||||
if (error)
|
||||
goto out_err;
|
||||
return error;
|
||||
}
|
||||
if (!(fattr->valid & NFS_ATTR_FATTR)) {
|
||||
struct nfs_server *server = NFS_SB(dentry->d_sb);
|
||||
error = server->rpc_ops->getattr(server, fhandle, fattr);
|
||||
error = server->nfs_client->rpc_ops->getattr(server, fhandle, fattr);
|
||||
if (error < 0)
|
||||
goto out_err;
|
||||
return error;
|
||||
}
|
||||
inode = nfs_fhget(dentry->d_sb, fhandle, fattr);
|
||||
error = PTR_ERR(inode);
|
||||
if (IS_ERR(inode))
|
||||
goto out_err;
|
||||
return error;
|
||||
d_instantiate(dentry, inode);
|
||||
if (d_unhashed(dentry))
|
||||
d_rehash(dentry);
|
||||
return 0;
|
||||
out_err:
|
||||
d_drop(dentry);
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1440,48 +1450,82 @@ static int nfs_unlink(struct inode *dir, struct dentry *dentry)
|
||||
return error;
|
||||
}
|
||||
|
||||
static int
|
||||
nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
|
||||
/*
|
||||
* To create a symbolic link, most file systems instantiate a new inode,
|
||||
* add a page to it containing the path, then write it out to the disk
|
||||
* using prepare_write/commit_write.
|
||||
*
|
||||
* Unfortunately the NFS client can't create the in-core inode first
|
||||
* because it needs a file handle to create an in-core inode (see
|
||||
* fs/nfs/inode.c:nfs_fhget). We only have a file handle *after* the
|
||||
* symlink request has completed on the server.
|
||||
*
|
||||
* So instead we allocate a raw page, copy the symname into it, then do
|
||||
* the SYMLINK request with the page as the buffer. If it succeeds, we
|
||||
* now have a new file handle and can instantiate an in-core NFS inode
|
||||
* and move the raw page into its mapping.
|
||||
*/
|
||||
static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
|
||||
{
|
||||
struct pagevec lru_pvec;
|
||||
struct page *page;
|
||||
char *kaddr;
|
||||
struct iattr attr;
|
||||
struct nfs_fattr sym_attr;
|
||||
struct nfs_fh sym_fh;
|
||||
struct qstr qsymname;
|
||||
unsigned int pathlen = strlen(symname);
|
||||
int error;
|
||||
|
||||
dfprintk(VFS, "NFS: symlink(%s/%ld, %s, %s)\n", dir->i_sb->s_id,
|
||||
dir->i_ino, dentry->d_name.name, symname);
|
||||
|
||||
#ifdef NFS_PARANOIA
|
||||
if (dentry->d_inode)
|
||||
printk("nfs_proc_symlink: %s/%s not negative!\n",
|
||||
dentry->d_parent->d_name.name, dentry->d_name.name);
|
||||
#endif
|
||||
/*
|
||||
* Fill in the sattr for the call.
|
||||
* Note: SunOS 4.1.2 crashes if the mode isn't initialized!
|
||||
*/
|
||||
attr.ia_valid = ATTR_MODE;
|
||||
attr.ia_mode = S_IFLNK | S_IRWXUGO;
|
||||
if (pathlen > PAGE_SIZE)
|
||||
return -ENAMETOOLONG;
|
||||
|
||||
qsymname.name = symname;
|
||||
qsymname.len = strlen(symname);
|
||||
attr.ia_mode = S_IFLNK | S_IRWXUGO;
|
||||
attr.ia_valid = ATTR_MODE;
|
||||
|
||||
lock_kernel();
|
||||
nfs_begin_data_update(dir);
|
||||
error = NFS_PROTO(dir)->symlink(dir, &dentry->d_name, &qsymname,
|
||||
&attr, &sym_fh, &sym_attr);
|
||||
nfs_end_data_update(dir);
|
||||
if (!error) {
|
||||
error = nfs_instantiate(dentry, &sym_fh, &sym_attr);
|
||||
} else {
|
||||
if (error == -EEXIST)
|
||||
printk("nfs_proc_symlink: %s/%s already exists??\n",
|
||||
dentry->d_parent->d_name.name, dentry->d_name.name);
|
||||
d_drop(dentry);
|
||||
|
||||
page = alloc_page(GFP_KERNEL);
|
||||
if (!page) {
|
||||
unlock_kernel();
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
kaddr = kmap_atomic(page, KM_USER0);
|
||||
memcpy(kaddr, symname, pathlen);
|
||||
if (pathlen < PAGE_SIZE)
|
||||
memset(kaddr + pathlen, 0, PAGE_SIZE - pathlen);
|
||||
kunmap_atomic(kaddr, KM_USER0);
|
||||
|
||||
nfs_begin_data_update(dir);
|
||||
error = NFS_PROTO(dir)->symlink(dir, dentry, page, pathlen, &attr);
|
||||
nfs_end_data_update(dir);
|
||||
if (error != 0) {
|
||||
dfprintk(VFS, "NFS: symlink(%s/%ld, %s, %s) error %d\n",
|
||||
dir->i_sb->s_id, dir->i_ino,
|
||||
dentry->d_name.name, symname, error);
|
||||
d_drop(dentry);
|
||||
__free_page(page);
|
||||
unlock_kernel();
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* No big deal if we can't add this page to the page cache here.
|
||||
* READLINK will get the missing page from the server if needed.
|
||||
*/
|
||||
pagevec_init(&lru_pvec, 0);
|
||||
if (!add_to_page_cache(page, dentry->d_inode->i_mapping, 0,
|
||||
GFP_KERNEL)) {
|
||||
if (!pagevec_add(&lru_pvec, page))
|
||||
__pagevec_lru_add(&lru_pvec);
|
||||
SetPageUptodate(page);
|
||||
unlock_page(page);
|
||||
} else
|
||||
__free_page(page);
|
||||
|
||||
unlock_kernel();
|
||||
return error;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
@ -1638,35 +1682,211 @@ out:
|
||||
return error;
|
||||
}
|
||||
|
||||
static DEFINE_SPINLOCK(nfs_access_lru_lock);
|
||||
static LIST_HEAD(nfs_access_lru_list);
|
||||
static atomic_long_t nfs_access_nr_entries;
|
||||
|
||||
static void nfs_access_free_entry(struct nfs_access_entry *entry)
|
||||
{
|
||||
put_rpccred(entry->cred);
|
||||
kfree(entry);
|
||||
smp_mb__before_atomic_dec();
|
||||
atomic_long_dec(&nfs_access_nr_entries);
|
||||
smp_mb__after_atomic_dec();
|
||||
}
|
||||
|
||||
int nfs_access_cache_shrinker(int nr_to_scan, gfp_t gfp_mask)
|
||||
{
|
||||
LIST_HEAD(head);
|
||||
struct nfs_inode *nfsi;
|
||||
struct nfs_access_entry *cache;
|
||||
|
||||
spin_lock(&nfs_access_lru_lock);
|
||||
restart:
|
||||
list_for_each_entry(nfsi, &nfs_access_lru_list, access_cache_inode_lru) {
|
||||
struct inode *inode;
|
||||
|
||||
if (nr_to_scan-- == 0)
|
||||
break;
|
||||
inode = igrab(&nfsi->vfs_inode);
|
||||
if (inode == NULL)
|
||||
continue;
|
||||
spin_lock(&inode->i_lock);
|
||||
if (list_empty(&nfsi->access_cache_entry_lru))
|
||||
goto remove_lru_entry;
|
||||
cache = list_entry(nfsi->access_cache_entry_lru.next,
|
||||
struct nfs_access_entry, lru);
|
||||
list_move(&cache->lru, &head);
|
||||
rb_erase(&cache->rb_node, &nfsi->access_cache);
|
||||
if (!list_empty(&nfsi->access_cache_entry_lru))
|
||||
list_move_tail(&nfsi->access_cache_inode_lru,
|
||||
&nfs_access_lru_list);
|
||||
else {
|
||||
remove_lru_entry:
|
||||
list_del_init(&nfsi->access_cache_inode_lru);
|
||||
clear_bit(NFS_INO_ACL_LRU_SET, &nfsi->flags);
|
||||
}
|
||||
spin_unlock(&inode->i_lock);
|
||||
iput(inode);
|
||||
goto restart;
|
||||
}
|
||||
spin_unlock(&nfs_access_lru_lock);
|
||||
while (!list_empty(&head)) {
|
||||
cache = list_entry(head.next, struct nfs_access_entry, lru);
|
||||
list_del(&cache->lru);
|
||||
nfs_access_free_entry(cache);
|
||||
}
|
||||
return (atomic_long_read(&nfs_access_nr_entries) / 100) * sysctl_vfs_cache_pressure;
|
||||
}
|
||||
|
||||
static void __nfs_access_zap_cache(struct inode *inode)
|
||||
{
|
||||
struct nfs_inode *nfsi = NFS_I(inode);
|
||||
struct rb_root *root_node = &nfsi->access_cache;
|
||||
struct rb_node *n, *dispose = NULL;
|
||||
struct nfs_access_entry *entry;
|
||||
|
||||
/* Unhook entries from the cache */
|
||||
while ((n = rb_first(root_node)) != NULL) {
|
||||
entry = rb_entry(n, struct nfs_access_entry, rb_node);
|
||||
rb_erase(n, root_node);
|
||||
list_del(&entry->lru);
|
||||
n->rb_left = dispose;
|
||||
dispose = n;
|
||||
}
|
||||
nfsi->cache_validity &= ~NFS_INO_INVALID_ACCESS;
|
||||
spin_unlock(&inode->i_lock);
|
||||
|
||||
/* Now kill them all! */
|
||||
while (dispose != NULL) {
|
||||
n = dispose;
|
||||
dispose = n->rb_left;
|
||||
nfs_access_free_entry(rb_entry(n, struct nfs_access_entry, rb_node));
|
||||
}
|
||||
}
|
||||
|
||||
void nfs_access_zap_cache(struct inode *inode)
|
||||
{
|
||||
/* Remove from global LRU init */
|
||||
if (test_and_clear_bit(NFS_INO_ACL_LRU_SET, &NFS_FLAGS(inode))) {
|
||||
spin_lock(&nfs_access_lru_lock);
|
||||
list_del_init(&NFS_I(inode)->access_cache_inode_lru);
|
||||
spin_unlock(&nfs_access_lru_lock);
|
||||
}
|
||||
|
||||
spin_lock(&inode->i_lock);
|
||||
/* This will release the spinlock */
|
||||
__nfs_access_zap_cache(inode);
|
||||
}
|
||||
|
||||
static struct nfs_access_entry *nfs_access_search_rbtree(struct inode *inode, struct rpc_cred *cred)
|
||||
{
|
||||
struct rb_node *n = NFS_I(inode)->access_cache.rb_node;
|
||||
struct nfs_access_entry *entry;
|
||||
|
||||
while (n != NULL) {
|
||||
entry = rb_entry(n, struct nfs_access_entry, rb_node);
|
||||
|
||||
if (cred < entry->cred)
|
||||
n = n->rb_left;
|
||||
else if (cred > entry->cred)
|
||||
n = n->rb_right;
|
||||
else
|
||||
return entry;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int nfs_access_get_cached(struct inode *inode, struct rpc_cred *cred, struct nfs_access_entry *res)
|
||||
{
|
||||
struct nfs_inode *nfsi = NFS_I(inode);
|
||||
struct nfs_access_entry *cache = &nfsi->cache_access;
|
||||
struct nfs_access_entry *cache;
|
||||
int err = -ENOENT;
|
||||
|
||||
if (cache->cred != cred
|
||||
|| time_after(jiffies, cache->jiffies + NFS_ATTRTIMEO(inode))
|
||||
|| (nfsi->cache_validity & NFS_INO_INVALID_ACCESS))
|
||||
return -ENOENT;
|
||||
memcpy(res, cache, sizeof(*res));
|
||||
return 0;
|
||||
spin_lock(&inode->i_lock);
|
||||
if (nfsi->cache_validity & NFS_INO_INVALID_ACCESS)
|
||||
goto out_zap;
|
||||
cache = nfs_access_search_rbtree(inode, cred);
|
||||
if (cache == NULL)
|
||||
goto out;
|
||||
if (time_after(jiffies, cache->jiffies + NFS_ATTRTIMEO(inode)))
|
||||
goto out_stale;
|
||||
res->jiffies = cache->jiffies;
|
||||
res->cred = cache->cred;
|
||||
res->mask = cache->mask;
|
||||
list_move_tail(&cache->lru, &nfsi->access_cache_entry_lru);
|
||||
err = 0;
|
||||
out:
|
||||
spin_unlock(&inode->i_lock);
|
||||
return err;
|
||||
out_stale:
|
||||
rb_erase(&cache->rb_node, &nfsi->access_cache);
|
||||
list_del(&cache->lru);
|
||||
spin_unlock(&inode->i_lock);
|
||||
nfs_access_free_entry(cache);
|
||||
return -ENOENT;
|
||||
out_zap:
|
||||
/* This will release the spinlock */
|
||||
__nfs_access_zap_cache(inode);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static void nfs_access_add_rbtree(struct inode *inode, struct nfs_access_entry *set)
|
||||
{
|
||||
struct nfs_inode *nfsi = NFS_I(inode);
|
||||
struct rb_root *root_node = &nfsi->access_cache;
|
||||
struct rb_node **p = &root_node->rb_node;
|
||||
struct rb_node *parent = NULL;
|
||||
struct nfs_access_entry *entry;
|
||||
|
||||
spin_lock(&inode->i_lock);
|
||||
while (*p != NULL) {
|
||||
parent = *p;
|
||||
entry = rb_entry(parent, struct nfs_access_entry, rb_node);
|
||||
|
||||
if (set->cred < entry->cred)
|
||||
p = &parent->rb_left;
|
||||
else if (set->cred > entry->cred)
|
||||
p = &parent->rb_right;
|
||||
else
|
||||
goto found;
|
||||
}
|
||||
rb_link_node(&set->rb_node, parent, p);
|
||||
rb_insert_color(&set->rb_node, root_node);
|
||||
list_add_tail(&set->lru, &nfsi->access_cache_entry_lru);
|
||||
spin_unlock(&inode->i_lock);
|
||||
return;
|
||||
found:
|
||||
rb_replace_node(parent, &set->rb_node, root_node);
|
||||
list_add_tail(&set->lru, &nfsi->access_cache_entry_lru);
|
||||
list_del(&entry->lru);
|
||||
spin_unlock(&inode->i_lock);
|
||||
nfs_access_free_entry(entry);
|
||||
}
|
||||
|
||||
void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *set)
|
||||
{
|
||||
struct nfs_inode *nfsi = NFS_I(inode);
|
||||
struct nfs_access_entry *cache = &nfsi->cache_access;
|
||||
|
||||
if (cache->cred != set->cred) {
|
||||
if (cache->cred)
|
||||
put_rpccred(cache->cred);
|
||||
cache->cred = get_rpccred(set->cred);
|
||||
}
|
||||
/* FIXME: replace current access_cache BKL reliance with inode->i_lock */
|
||||
spin_lock(&inode->i_lock);
|
||||
nfsi->cache_validity &= ~NFS_INO_INVALID_ACCESS;
|
||||
spin_unlock(&inode->i_lock);
|
||||
struct nfs_access_entry *cache = kmalloc(sizeof(*cache), GFP_KERNEL);
|
||||
if (cache == NULL)
|
||||
return;
|
||||
RB_CLEAR_NODE(&cache->rb_node);
|
||||
cache->jiffies = set->jiffies;
|
||||
cache->cred = get_rpccred(set->cred);
|
||||
cache->mask = set->mask;
|
||||
|
||||
nfs_access_add_rbtree(inode, cache);
|
||||
|
||||
/* Update accounting */
|
||||
smp_mb__before_atomic_inc();
|
||||
atomic_long_inc(&nfs_access_nr_entries);
|
||||
smp_mb__after_atomic_inc();
|
||||
|
||||
/* Add inode to global LRU list */
|
||||
if (!test_and_set_bit(NFS_INO_ACL_LRU_SET, &NFS_FLAGS(inode))) {
|
||||
spin_lock(&nfs_access_lru_lock);
|
||||
list_add_tail(&NFS_I(inode)->access_cache_inode_lru, &nfs_access_lru_list);
|
||||
spin_unlock(&nfs_access_lru_lock);
|
||||
}
|
||||
}
|
||||
|
||||
static int nfs_do_access(struct inode *inode, struct rpc_cred *cred, int mask)
|
||||
|
@ -111,7 +111,7 @@ nfs_file_open(struct inode *inode, struct file *filp)
|
||||
|
||||
nfs_inc_stats(inode, NFSIOS_VFSOPEN);
|
||||
lock_kernel();
|
||||
res = NFS_SERVER(inode)->rpc_ops->file_open(inode, filp);
|
||||
res = NFS_PROTO(inode)->file_open(inode, filp);
|
||||
unlock_kernel();
|
||||
return res;
|
||||
}
|
||||
@ -157,7 +157,7 @@ force_reval:
|
||||
static loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin)
|
||||
{
|
||||
/* origin == SEEK_END => we must revalidate the cached file length */
|
||||
if (origin == 2) {
|
||||
if (origin == SEEK_END) {
|
||||
struct inode *inode = filp->f_mapping->host;
|
||||
int retval = nfs_revalidate_file_size(inode, filp);
|
||||
if (retval < 0)
|
||||
|
311
fs/nfs/getroot.c
Normal file
311
fs/nfs/getroot.c
Normal file
@ -0,0 +1,311 @@
|
||||
/* getroot.c: get the root dentry for an NFS mount
|
||||
*
|
||||
* Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include <linux/time.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/unistd.h>
|
||||
#include <linux/sunrpc/clnt.h>
|
||||
#include <linux/sunrpc/stats.h>
|
||||
#include <linux/nfs_fs.h>
|
||||
#include <linux/nfs_mount.h>
|
||||
#include <linux/nfs4_mount.h>
|
||||
#include <linux/lockd/bind.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/mount.h>
|
||||
#include <linux/nfs_idmap.h>
|
||||
#include <linux/vfs.h>
|
||||
#include <linux/namei.h>
|
||||
#include <linux/namespace.h>
|
||||
#include <linux/security.h>
|
||||
|
||||
#include <asm/system.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#include "nfs4_fs.h"
|
||||
#include "delegation.h"
|
||||
#include "internal.h"
|
||||
|
||||
#define NFSDBG_FACILITY NFSDBG_CLIENT
|
||||
#define NFS_PARANOIA 1
|
||||
|
||||
/*
|
||||
* get an NFS2/NFS3 root dentry from the root filehandle
|
||||
*/
|
||||
struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh)
|
||||
{
|
||||
struct nfs_server *server = NFS_SB(sb);
|
||||
struct nfs_fsinfo fsinfo;
|
||||
struct nfs_fattr fattr;
|
||||
struct dentry *mntroot;
|
||||
struct inode *inode;
|
||||
int error;
|
||||
|
||||
/* create a dummy root dentry with dummy inode for this superblock */
|
||||
if (!sb->s_root) {
|
||||
struct nfs_fh dummyfh;
|
||||
struct dentry *root;
|
||||
struct inode *iroot;
|
||||
|
||||
memset(&dummyfh, 0, sizeof(dummyfh));
|
||||
memset(&fattr, 0, sizeof(fattr));
|
||||
nfs_fattr_init(&fattr);
|
||||
fattr.valid = NFS_ATTR_FATTR;
|
||||
fattr.type = NFDIR;
|
||||
fattr.mode = S_IFDIR | S_IRUSR | S_IWUSR;
|
||||
fattr.nlink = 2;
|
||||
|
||||
iroot = nfs_fhget(sb, &dummyfh, &fattr);
|
||||
if (IS_ERR(iroot))
|
||||
return ERR_PTR(PTR_ERR(iroot));
|
||||
|
||||
root = d_alloc_root(iroot);
|
||||
if (!root) {
|
||||
iput(iroot);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
sb->s_root = root;
|
||||
}
|
||||
|
||||
/* get the actual root for this mount */
|
||||
fsinfo.fattr = &fattr;
|
||||
|
||||
error = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo);
|
||||
if (error < 0) {
|
||||
dprintk("nfs_get_root: getattr error = %d\n", -error);
|
||||
return ERR_PTR(error);
|
||||
}
|
||||
|
||||
inode = nfs_fhget(sb, mntfh, fsinfo.fattr);
|
||||
if (IS_ERR(inode)) {
|
||||
dprintk("nfs_get_root: get root inode failed\n");
|
||||
return ERR_PTR(PTR_ERR(inode));
|
||||
}
|
||||
|
||||
/* root dentries normally start off anonymous and get spliced in later
|
||||
* if the dentry tree reaches them; however if the dentry already
|
||||
* exists, we'll pick it up at this point and use it as the root
|
||||
*/
|
||||
mntroot = d_alloc_anon(inode);
|
||||
if (!mntroot) {
|
||||
iput(inode);
|
||||
dprintk("nfs_get_root: get root dentry failed\n");
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
security_d_instantiate(mntroot, inode);
|
||||
|
||||
if (!mntroot->d_op)
|
||||
mntroot->d_op = server->nfs_client->rpc_ops->dentry_ops;
|
||||
|
||||
return mntroot;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NFS_V4
|
||||
|
||||
/*
|
||||
* Do a simple pathwalk from the root FH of the server to the nominated target
|
||||
* of the mountpoint
|
||||
* - give error on symlinks
|
||||
* - give error on ".." occurring in the path
|
||||
* - follow traversals
|
||||
*/
|
||||
int nfs4_path_walk(struct nfs_server *server,
|
||||
struct nfs_fh *mntfh,
|
||||
const char *path)
|
||||
{
|
||||
struct nfs_fsinfo fsinfo;
|
||||
struct nfs_fattr fattr;
|
||||
struct nfs_fh lastfh;
|
||||
struct qstr name;
|
||||
int ret;
|
||||
//int referral_count = 0;
|
||||
|
||||
dprintk("--> nfs4_path_walk(,,%s)\n", path);
|
||||
|
||||
fsinfo.fattr = &fattr;
|
||||
nfs_fattr_init(&fattr);
|
||||
|
||||
if (*path++ != '/') {
|
||||
dprintk("nfs4_get_root: Path does not begin with a slash\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Start by getting the root filehandle from the server */
|
||||
ret = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo);
|
||||
if (ret < 0) {
|
||||
dprintk("nfs4_get_root: getroot error = %d\n", -ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (fattr.type != NFDIR) {
|
||||
printk(KERN_ERR "nfs4_get_root:"
|
||||
" getroot encountered non-directory\n");
|
||||
return -ENOTDIR;
|
||||
}
|
||||
|
||||
if (fattr.valid & NFS_ATTR_FATTR_V4_REFERRAL) {
|
||||
printk(KERN_ERR "nfs4_get_root:"
|
||||
" getroot obtained referral\n");
|
||||
return -EREMOTE;
|
||||
}
|
||||
|
||||
next_component:
|
||||
dprintk("Next: %s\n", path);
|
||||
|
||||
/* extract the next bit of the path */
|
||||
if (!*path)
|
||||
goto path_walk_complete;
|
||||
|
||||
name.name = path;
|
||||
while (*path && *path != '/')
|
||||
path++;
|
||||
name.len = path - (const char *) name.name;
|
||||
|
||||
eat_dot_dir:
|
||||
while (*path == '/')
|
||||
path++;
|
||||
|
||||
if (path[0] == '.' && (path[1] == '/' || !path[1])) {
|
||||
path += 2;
|
||||
goto eat_dot_dir;
|
||||
}
|
||||
|
||||
if (path[0] == '.' && path[1] == '.' && (path[2] == '/' || !path[2])
|
||||
) {
|
||||
printk(KERN_ERR "nfs4_get_root:"
|
||||
" Mount path contains reference to \"..\"\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* lookup the next FH in the sequence */
|
||||
memcpy(&lastfh, mntfh, sizeof(lastfh));
|
||||
|
||||
dprintk("LookupFH: %*.*s [%s]\n", name.len, name.len, name.name, path);
|
||||
|
||||
ret = server->nfs_client->rpc_ops->lookupfh(server, &lastfh, &name,
|
||||
mntfh, &fattr);
|
||||
if (ret < 0) {
|
||||
dprintk("nfs4_get_root: getroot error = %d\n", -ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (fattr.type != NFDIR) {
|
||||
printk(KERN_ERR "nfs4_get_root:"
|
||||
" lookupfh encountered non-directory\n");
|
||||
return -ENOTDIR;
|
||||
}
|
||||
|
||||
if (fattr.valid & NFS_ATTR_FATTR_V4_REFERRAL) {
|
||||
printk(KERN_ERR "nfs4_get_root:"
|
||||
" lookupfh obtained referral\n");
|
||||
return -EREMOTE;
|
||||
}
|
||||
|
||||
goto next_component;
|
||||
|
||||
path_walk_complete:
|
||||
memcpy(&server->fsid, &fattr.fsid, sizeof(server->fsid));
|
||||
dprintk("<-- nfs4_path_walk() = 0\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* get an NFS4 root dentry from the root filehandle
|
||||
*/
|
||||
struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh)
|
||||
{
|
||||
struct nfs_server *server = NFS_SB(sb);
|
||||
struct nfs_fattr fattr;
|
||||
struct dentry *mntroot;
|
||||
struct inode *inode;
|
||||
int error;
|
||||
|
||||
dprintk("--> nfs4_get_root()\n");
|
||||
|
||||
/* create a dummy root dentry with dummy inode for this superblock */
|
||||
if (!sb->s_root) {
|
||||
struct nfs_fh dummyfh;
|
||||
struct dentry *root;
|
||||
struct inode *iroot;
|
||||
|
||||
memset(&dummyfh, 0, sizeof(dummyfh));
|
||||
memset(&fattr, 0, sizeof(fattr));
|
||||
nfs_fattr_init(&fattr);
|
||||
fattr.valid = NFS_ATTR_FATTR;
|
||||
fattr.type = NFDIR;
|
||||
fattr.mode = S_IFDIR | S_IRUSR | S_IWUSR;
|
||||
fattr.nlink = 2;
|
||||
|
||||
iroot = nfs_fhget(sb, &dummyfh, &fattr);
|
||||
if (IS_ERR(iroot))
|
||||
return ERR_PTR(PTR_ERR(iroot));
|
||||
|
||||
root = d_alloc_root(iroot);
|
||||
if (!root) {
|
||||
iput(iroot);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
sb->s_root = root;
|
||||
}
|
||||
|
||||
/* get the info about the server and filesystem */
|
||||
error = nfs4_server_capabilities(server, mntfh);
|
||||
if (error < 0) {
|
||||
dprintk("nfs_get_root: getcaps error = %d\n",
|
||||
-error);
|
||||
return ERR_PTR(error);
|
||||
}
|
||||
|
||||
/* get the actual root for this mount */
|
||||
error = server->nfs_client->rpc_ops->getattr(server, mntfh, &fattr);
|
||||
if (error < 0) {
|
||||
dprintk("nfs_get_root: getattr error = %d\n", -error);
|
||||
return ERR_PTR(error);
|
||||
}
|
||||
|
||||
inode = nfs_fhget(sb, mntfh, &fattr);
|
||||
if (IS_ERR(inode)) {
|
||||
dprintk("nfs_get_root: get root inode failed\n");
|
||||
return ERR_PTR(PTR_ERR(inode));
|
||||
}
|
||||
|
||||
/* root dentries normally start off anonymous and get spliced in later
|
||||
* if the dentry tree reaches them; however if the dentry already
|
||||
* exists, we'll pick it up at this point and use it as the root
|
||||
*/
|
||||
mntroot = d_alloc_anon(inode);
|
||||
if (!mntroot) {
|
||||
iput(inode);
|
||||
dprintk("nfs_get_root: get root dentry failed\n");
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
security_d_instantiate(mntroot, inode);
|
||||
|
||||
if (!mntroot->d_op)
|
||||
mntroot->d_op = server->nfs_client->rpc_ops->dentry_ops;
|
||||
|
||||
dprintk("<-- nfs4_get_root()\n");
|
||||
return mntroot;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_NFS_V4 */
|
@ -57,6 +57,20 @@
|
||||
/* Default cache timeout is 10 minutes */
|
||||
unsigned int nfs_idmap_cache_timeout = 600 * HZ;
|
||||
|
||||
static int param_set_idmap_timeout(const char *val, struct kernel_param *kp)
|
||||
{
|
||||
char *endp;
|
||||
int num = simple_strtol(val, &endp, 0);
|
||||
int jif = num * HZ;
|
||||
if (endp == val || *endp || num < 0 || jif < num)
|
||||
return -EINVAL;
|
||||
*((int *)kp->arg) = jif;
|
||||
return 0;
|
||||
}
|
||||
|
||||
module_param_call(idmap_cache_timeout, param_set_idmap_timeout, param_get_int,
|
||||
&nfs_idmap_cache_timeout, 0644);
|
||||
|
||||
struct idmap_hashent {
|
||||
unsigned long ih_expires;
|
||||
__u32 ih_id;
|
||||
@ -70,7 +84,6 @@ struct idmap_hashtable {
|
||||
};
|
||||
|
||||
struct idmap {
|
||||
char idmap_path[48];
|
||||
struct dentry *idmap_dentry;
|
||||
wait_queue_head_t idmap_wq;
|
||||
struct idmap_msg idmap_im;
|
||||
@ -94,24 +107,23 @@ static struct rpc_pipe_ops idmap_upcall_ops = {
|
||||
.destroy_msg = idmap_pipe_destroy_msg,
|
||||
};
|
||||
|
||||
void
|
||||
nfs_idmap_new(struct nfs4_client *clp)
|
||||
int
|
||||
nfs_idmap_new(struct nfs_client *clp)
|
||||
{
|
||||
struct idmap *idmap;
|
||||
int error;
|
||||
|
||||
BUG_ON(clp->cl_idmap != NULL);
|
||||
|
||||
if (clp->cl_idmap != NULL)
|
||||
return;
|
||||
if ((idmap = kzalloc(sizeof(*idmap), GFP_KERNEL)) == NULL)
|
||||
return;
|
||||
return -ENOMEM;
|
||||
|
||||
snprintf(idmap->idmap_path, sizeof(idmap->idmap_path),
|
||||
"%s/idmap", clp->cl_rpcclient->cl_pathname);
|
||||
|
||||
idmap->idmap_dentry = rpc_mkpipe(idmap->idmap_path,
|
||||
idmap->idmap_dentry = rpc_mkpipe(clp->cl_rpcclient->cl_dentry, "idmap",
|
||||
idmap, &idmap_upcall_ops, 0);
|
||||
if (IS_ERR(idmap->idmap_dentry)) {
|
||||
error = PTR_ERR(idmap->idmap_dentry);
|
||||
kfree(idmap);
|
||||
return;
|
||||
return error;
|
||||
}
|
||||
|
||||
mutex_init(&idmap->idmap_lock);
|
||||
@ -121,10 +133,11 @@ nfs_idmap_new(struct nfs4_client *clp)
|
||||
idmap->idmap_group_hash.h_type = IDMAP_TYPE_GROUP;
|
||||
|
||||
clp->cl_idmap = idmap;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
nfs_idmap_delete(struct nfs4_client *clp)
|
||||
nfs_idmap_delete(struct nfs_client *clp)
|
||||
{
|
||||
struct idmap *idmap = clp->cl_idmap;
|
||||
|
||||
@ -477,27 +490,27 @@ static unsigned int fnvhash32(const void *buf, size_t buflen)
|
||||
return (hash);
|
||||
}
|
||||
|
||||
int nfs_map_name_to_uid(struct nfs4_client *clp, const char *name, size_t namelen, __u32 *uid)
|
||||
int nfs_map_name_to_uid(struct nfs_client *clp, const char *name, size_t namelen, __u32 *uid)
|
||||
{
|
||||
struct idmap *idmap = clp->cl_idmap;
|
||||
|
||||
return nfs_idmap_id(idmap, &idmap->idmap_user_hash, name, namelen, uid);
|
||||
}
|
||||
|
||||
int nfs_map_group_to_gid(struct nfs4_client *clp, const char *name, size_t namelen, __u32 *uid)
|
||||
int nfs_map_group_to_gid(struct nfs_client *clp, const char *name, size_t namelen, __u32 *uid)
|
||||
{
|
||||
struct idmap *idmap = clp->cl_idmap;
|
||||
|
||||
return nfs_idmap_id(idmap, &idmap->idmap_group_hash, name, namelen, uid);
|
||||
}
|
||||
|
||||
int nfs_map_uid_to_name(struct nfs4_client *clp, __u32 uid, char *buf)
|
||||
int nfs_map_uid_to_name(struct nfs_client *clp, __u32 uid, char *buf)
|
||||
{
|
||||
struct idmap *idmap = clp->cl_idmap;
|
||||
|
||||
return nfs_idmap_name(idmap, &idmap->idmap_user_hash, uid, buf);
|
||||
}
|
||||
int nfs_map_gid_to_group(struct nfs4_client *clp, __u32 uid, char *buf)
|
||||
int nfs_map_gid_to_group(struct nfs_client *clp, __u32 uid, char *buf)
|
||||
{
|
||||
struct idmap *idmap = clp->cl_idmap;
|
||||
|
||||
|
@ -76,19 +76,14 @@ int nfs_write_inode(struct inode *inode, int sync)
|
||||
|
||||
void nfs_clear_inode(struct inode *inode)
|
||||
{
|
||||
struct nfs_inode *nfsi = NFS_I(inode);
|
||||
struct rpc_cred *cred;
|
||||
|
||||
/*
|
||||
* The following should never happen...
|
||||
*/
|
||||
BUG_ON(nfs_have_writebacks(inode));
|
||||
BUG_ON (!list_empty(&nfsi->open_files));
|
||||
BUG_ON(!list_empty(&NFS_I(inode)->open_files));
|
||||
BUG_ON(atomic_read(&NFS_I(inode)->data_updates) != 0);
|
||||
nfs_zap_acl_cache(inode);
|
||||
cred = nfsi->cache_access.cred;
|
||||
if (cred)
|
||||
put_rpccred(cred);
|
||||
BUG_ON(atomic_read(&nfsi->data_updates) != 0);
|
||||
nfs_access_zap_cache(inode);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -242,13 +237,13 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
|
||||
/* Why so? Because we want revalidate for devices/FIFOs, and
|
||||
* that's precisely what we have in nfs_file_inode_operations.
|
||||
*/
|
||||
inode->i_op = NFS_SB(sb)->rpc_ops->file_inode_ops;
|
||||
inode->i_op = NFS_SB(sb)->nfs_client->rpc_ops->file_inode_ops;
|
||||
if (S_ISREG(inode->i_mode)) {
|
||||
inode->i_fop = &nfs_file_operations;
|
||||
inode->i_data.a_ops = &nfs_file_aops;
|
||||
inode->i_data.backing_dev_info = &NFS_SB(sb)->backing_dev_info;
|
||||
} else if (S_ISDIR(inode->i_mode)) {
|
||||
inode->i_op = NFS_SB(sb)->rpc_ops->dir_inode_ops;
|
||||
inode->i_op = NFS_SB(sb)->nfs_client->rpc_ops->dir_inode_ops;
|
||||
inode->i_fop = &nfs_dir_operations;
|
||||
if (nfs_server_capable(inode, NFS_CAP_READDIRPLUS)
|
||||
&& fattr->size <= NFS_LIMIT_READDIRPLUS)
|
||||
@ -290,7 +285,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
|
||||
nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
|
||||
nfsi->attrtimeo_timestamp = jiffies;
|
||||
memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf));
|
||||
nfsi->cache_access.cred = NULL;
|
||||
nfsi->access_cache = RB_ROOT;
|
||||
|
||||
unlock_new_inode(inode);
|
||||
} else
|
||||
@ -722,13 +717,11 @@ void nfs_end_data_update(struct inode *inode)
|
||||
{
|
||||
struct nfs_inode *nfsi = NFS_I(inode);
|
||||
|
||||
if (!nfs_have_delegation(inode, FMODE_READ)) {
|
||||
/* Directories and symlinks: invalidate page cache */
|
||||
if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) {
|
||||
spin_lock(&inode->i_lock);
|
||||
nfsi->cache_validity |= NFS_INO_INVALID_DATA;
|
||||
spin_unlock(&inode->i_lock);
|
||||
}
|
||||
/* Directories: invalidate page cache */
|
||||
if (S_ISDIR(inode->i_mode)) {
|
||||
spin_lock(&inode->i_lock);
|
||||
nfsi->cache_validity |= NFS_INO_INVALID_DATA;
|
||||
spin_unlock(&inode->i_lock);
|
||||
}
|
||||
nfsi->cache_change_attribute = jiffies;
|
||||
atomic_dec(&nfsi->data_updates);
|
||||
@ -847,6 +840,12 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
|
||||
*
|
||||
* After an operation that has changed the inode metadata, mark the
|
||||
* attribute cache as being invalid, then try to update it.
|
||||
*
|
||||
* NB: if the server didn't return any post op attributes, this
|
||||
* function will force the retrieval of attributes before the next
|
||||
* NFS request. Thus it should be used only for operations that
|
||||
* are expected to change one or more attributes, to avoid
|
||||
* unnecessary NFS requests and trips through nfs_update_inode().
|
||||
*/
|
||||
int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr)
|
||||
{
|
||||
@ -1025,7 +1024,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
|
||||
out_fileid:
|
||||
printk(KERN_ERR "NFS: server %s error: fileid changed\n"
|
||||
"fsid %s: expected fileid 0x%Lx, got 0x%Lx\n",
|
||||
NFS_SERVER(inode)->hostname, inode->i_sb->s_id,
|
||||
NFS_SERVER(inode)->nfs_client->cl_hostname, inode->i_sb->s_id,
|
||||
(long long)nfsi->fileid, (long long)fattr->fileid);
|
||||
goto out_err;
|
||||
}
|
||||
@ -1109,6 +1108,8 @@ static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
|
||||
INIT_LIST_HEAD(&nfsi->dirty);
|
||||
INIT_LIST_HEAD(&nfsi->commit);
|
||||
INIT_LIST_HEAD(&nfsi->open_files);
|
||||
INIT_LIST_HEAD(&nfsi->access_cache_entry_lru);
|
||||
INIT_LIST_HEAD(&nfsi->access_cache_inode_lru);
|
||||
INIT_RADIX_TREE(&nfsi->nfs_page_tree, GFP_ATOMIC);
|
||||
atomic_set(&nfsi->data_updates, 0);
|
||||
nfsi->ndirty = 0;
|
||||
@ -1144,6 +1145,10 @@ static int __init init_nfs_fs(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = nfs_fs_proc_init();
|
||||
if (err)
|
||||
goto out5;
|
||||
|
||||
err = nfs_init_nfspagecache();
|
||||
if (err)
|
||||
goto out4;
|
||||
@ -1184,6 +1189,8 @@ out2:
|
||||
out3:
|
||||
nfs_destroy_nfspagecache();
|
||||
out4:
|
||||
nfs_fs_proc_exit();
|
||||
out5:
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -1198,6 +1205,7 @@ static void __exit exit_nfs_fs(void)
|
||||
rpc_proc_unregister("nfs");
|
||||
#endif
|
||||
unregister_nfs_fs();
|
||||
nfs_fs_proc_exit();
|
||||
}
|
||||
|
||||
/* Not quite true; I just maintain it */
|
||||
|
@ -4,6 +4,18 @@
|
||||
|
||||
#include <linux/mount.h>
|
||||
|
||||
struct nfs_string;
|
||||
struct nfs_mount_data;
|
||||
struct nfs4_mount_data;
|
||||
|
||||
/* Maximum number of readahead requests
|
||||
* FIXME: this should really be a sysctl so that users may tune it to suit
|
||||
* their needs. People that do NFS over a slow network, might for
|
||||
* instance want to reduce it to something closer to 1 for improved
|
||||
* interactive response.
|
||||
*/
|
||||
#define NFS_MAX_READAHEAD (RPC_DEF_SLOT_TABLE - 1)
|
||||
|
||||
struct nfs_clone_mount {
|
||||
const struct super_block *sb;
|
||||
const struct dentry *dentry;
|
||||
@ -15,7 +27,40 @@ struct nfs_clone_mount {
|
||||
rpc_authflavor_t authflavor;
|
||||
};
|
||||
|
||||
/* namespace-nfs4.c */
|
||||
/* client.c */
|
||||
extern struct rpc_program nfs_program;
|
||||
|
||||
extern void nfs_put_client(struct nfs_client *);
|
||||
extern struct nfs_client *nfs_find_client(const struct sockaddr_in *, int);
|
||||
extern struct nfs_server *nfs_create_server(const struct nfs_mount_data *,
|
||||
struct nfs_fh *);
|
||||
extern struct nfs_server *nfs4_create_server(const struct nfs4_mount_data *,
|
||||
const char *,
|
||||
const struct sockaddr_in *,
|
||||
const char *,
|
||||
const char *,
|
||||
rpc_authflavor_t,
|
||||
struct nfs_fh *);
|
||||
extern struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *,
|
||||
struct nfs_fh *);
|
||||
extern void nfs_free_server(struct nfs_server *server);
|
||||
extern struct nfs_server *nfs_clone_server(struct nfs_server *,
|
||||
struct nfs_fh *,
|
||||
struct nfs_fattr *);
|
||||
#ifdef CONFIG_PROC_FS
|
||||
extern int __init nfs_fs_proc_init(void);
|
||||
extern void nfs_fs_proc_exit(void);
|
||||
#else
|
||||
static inline int nfs_fs_proc_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void nfs_fs_proc_exit(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
/* nfs4namespace.c */
|
||||
#ifdef CONFIG_NFS_V4
|
||||
extern struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentry *dentry);
|
||||
#else
|
||||
@ -46,6 +91,7 @@ extern void nfs_destroy_directcache(void);
|
||||
#endif
|
||||
|
||||
/* nfs2xdr.c */
|
||||
extern int nfs_stat_to_errno(int);
|
||||
extern struct rpc_procinfo nfs_procedures[];
|
||||
extern u32 * nfs_decode_dirent(u32 *, struct nfs_entry *, int);
|
||||
|
||||
@ -54,8 +100,9 @@ extern struct rpc_procinfo nfs3_procedures[];
|
||||
extern u32 *nfs3_decode_dirent(u32 *, struct nfs_entry *, int);
|
||||
|
||||
/* nfs4xdr.c */
|
||||
extern int nfs_stat_to_errno(int);
|
||||
#ifdef CONFIG_NFS_V4
|
||||
extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus);
|
||||
#endif
|
||||
|
||||
/* nfs4proc.c */
|
||||
#ifdef CONFIG_NFS_V4
|
||||
@ -66,6 +113,9 @@ extern int nfs4_proc_fs_locations(struct inode *dir, struct dentry *dentry,
|
||||
struct page *page);
|
||||
#endif
|
||||
|
||||
/* dir.c */
|
||||
extern int nfs_access_cache_shrinker(int nr_to_scan, gfp_t gfp_mask);
|
||||
|
||||
/* inode.c */
|
||||
extern struct inode *nfs_alloc_inode(struct super_block *sb);
|
||||
extern void nfs_destroy_inode(struct inode *);
|
||||
@ -76,10 +126,10 @@ extern void nfs4_clear_inode(struct inode *);
|
||||
#endif
|
||||
|
||||
/* super.c */
|
||||
extern struct file_system_type nfs_referral_nfs4_fs_type;
|
||||
extern struct file_system_type clone_nfs_fs_type;
|
||||
extern struct file_system_type nfs_xdev_fs_type;
|
||||
#ifdef CONFIG_NFS_V4
|
||||
extern struct file_system_type clone_nfs4_fs_type;
|
||||
extern struct file_system_type nfs4_xdev_fs_type;
|
||||
extern struct file_system_type nfs4_referral_fs_type;
|
||||
#endif
|
||||
|
||||
extern struct rpc_stat nfs_rpcstat;
|
||||
@ -88,30 +138,30 @@ extern int __init register_nfs_fs(void);
|
||||
extern void __exit unregister_nfs_fs(void);
|
||||
|
||||
/* namespace.c */
|
||||
extern char *nfs_path(const char *base, const struct dentry *dentry,
|
||||
extern char *nfs_path(const char *base,
|
||||
const struct dentry *droot,
|
||||
const struct dentry *dentry,
|
||||
char *buffer, ssize_t buflen);
|
||||
|
||||
/*
|
||||
* Determine the mount path as a string
|
||||
*/
|
||||
static inline char *
|
||||
nfs4_path(const struct dentry *dentry, char *buffer, ssize_t buflen)
|
||||
{
|
||||
/* getroot.c */
|
||||
extern struct dentry *nfs_get_root(struct super_block *, struct nfs_fh *);
|
||||
#ifdef CONFIG_NFS_V4
|
||||
return nfs_path(NFS_SB(dentry->d_sb)->mnt_path, dentry, buffer, buflen);
|
||||
#else
|
||||
return NULL;
|
||||
extern struct dentry *nfs4_get_root(struct super_block *, struct nfs_fh *);
|
||||
|
||||
extern int nfs4_path_walk(struct nfs_server *server,
|
||||
struct nfs_fh *mntfh,
|
||||
const char *path);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine the device name as a string
|
||||
*/
|
||||
static inline char *nfs_devname(const struct vfsmount *mnt_parent,
|
||||
const struct dentry *dentry,
|
||||
char *buffer, ssize_t buflen)
|
||||
const struct dentry *dentry,
|
||||
char *buffer, ssize_t buflen)
|
||||
{
|
||||
return nfs_path(mnt_parent->mnt_devname, dentry, buffer, buflen);
|
||||
return nfs_path(mnt_parent->mnt_devname, mnt_parent->mnt_root,
|
||||
dentry, buffer, buflen);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -167,20 +217,3 @@ void nfs_super_set_maxbytes(struct super_block *sb, __u64 maxfilesize)
|
||||
if (sb->s_maxbytes > MAX_LFS_FILESIZE || sb->s_maxbytes <= 0)
|
||||
sb->s_maxbytes = MAX_LFS_FILESIZE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the string represents a "valid" IPv4 address
|
||||
*/
|
||||
static inline int valid_ipaddr4(const char *buf)
|
||||
{
|
||||
int rc, count, in[4];
|
||||
|
||||
rc = sscanf(buf, "%d.%d.%d.%d", &in[0], &in[1], &in[2], &in[3]);
|
||||
if (rc != 4)
|
||||
return -EINVAL;
|
||||
for (count = 0; count < 4; count++) {
|
||||
if (in[count] > 255)
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -14,7 +14,6 @@
|
||||
#include <linux/net.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/sunrpc/clnt.h>
|
||||
#include <linux/sunrpc/xprt.h>
|
||||
#include <linux/sunrpc/sched.h>
|
||||
#include <linux/nfs_fs.h>
|
||||
|
||||
@ -77,22 +76,19 @@ static struct rpc_clnt *
|
||||
mnt_create(char *hostname, struct sockaddr_in *srvaddr, int version,
|
||||
int protocol)
|
||||
{
|
||||
struct rpc_xprt *xprt;
|
||||
struct rpc_clnt *clnt;
|
||||
struct rpc_create_args args = {
|
||||
.protocol = protocol,
|
||||
.address = (struct sockaddr *)srvaddr,
|
||||
.addrsize = sizeof(*srvaddr),
|
||||
.servername = hostname,
|
||||
.program = &mnt_program,
|
||||
.version = version,
|
||||
.authflavor = RPC_AUTH_UNIX,
|
||||
.flags = (RPC_CLNT_CREATE_ONESHOT |
|
||||
RPC_CLNT_CREATE_INTR),
|
||||
};
|
||||
|
||||
xprt = xprt_create_proto(protocol, srvaddr, NULL);
|
||||
if (IS_ERR(xprt))
|
||||
return (struct rpc_clnt *)xprt;
|
||||
|
||||
clnt = rpc_create_client(xprt, hostname,
|
||||
&mnt_program, version,
|
||||
RPC_AUTH_UNIX);
|
||||
if (!IS_ERR(clnt)) {
|
||||
clnt->cl_softrtry = 1;
|
||||
clnt->cl_oneshot = 1;
|
||||
clnt->cl_intr = 1;
|
||||
}
|
||||
return clnt;
|
||||
return rpc_create(&args);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -2,6 +2,7 @@
|
||||
* linux/fs/nfs/namespace.c
|
||||
*
|
||||
* Copyright (C) 2005 Trond Myklebust <Trond.Myklebust@netapp.com>
|
||||
* - Modified by David Howells <dhowells@redhat.com>
|
||||
*
|
||||
* NFS namespace
|
||||
*/
|
||||
@ -28,6 +29,7 @@ int nfs_mountpoint_expiry_timeout = 500 * HZ;
|
||||
/*
|
||||
* nfs_path - reconstruct the path given an arbitrary dentry
|
||||
* @base - arbitrary string to prepend to the path
|
||||
* @droot - pointer to root dentry for mountpoint
|
||||
* @dentry - pointer to dentry
|
||||
* @buffer - result buffer
|
||||
* @buflen - length of buffer
|
||||
@ -38,7 +40,9 @@ int nfs_mountpoint_expiry_timeout = 500 * HZ;
|
||||
* This is mainly for use in figuring out the path on the
|
||||
* server side when automounting on top of an existing partition.
|
||||
*/
|
||||
char *nfs_path(const char *base, const struct dentry *dentry,
|
||||
char *nfs_path(const char *base,
|
||||
const struct dentry *droot,
|
||||
const struct dentry *dentry,
|
||||
char *buffer, ssize_t buflen)
|
||||
{
|
||||
char *end = buffer+buflen;
|
||||
@ -47,7 +51,7 @@ char *nfs_path(const char *base, const struct dentry *dentry,
|
||||
*--end = '\0';
|
||||
buflen--;
|
||||
spin_lock(&dcache_lock);
|
||||
while (!IS_ROOT(dentry)) {
|
||||
while (!IS_ROOT(dentry) && dentry != droot) {
|
||||
namelen = dentry->d_name.len;
|
||||
buflen -= namelen + 1;
|
||||
if (buflen < 0)
|
||||
@ -96,15 +100,18 @@ static void * nfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
|
||||
struct nfs_fattr fattr;
|
||||
int err;
|
||||
|
||||
dprintk("--> nfs_follow_mountpoint()\n");
|
||||
|
||||
BUG_ON(IS_ROOT(dentry));
|
||||
dprintk("%s: enter\n", __FUNCTION__);
|
||||
dput(nd->dentry);
|
||||
nd->dentry = dget(dentry);
|
||||
if (d_mountpoint(nd->dentry))
|
||||
goto out_follow;
|
||||
|
||||
/* Look it up again */
|
||||
parent = dget_parent(nd->dentry);
|
||||
err = server->rpc_ops->lookup(parent->d_inode, &nd->dentry->d_name, &fh, &fattr);
|
||||
err = server->nfs_client->rpc_ops->lookup(parent->d_inode,
|
||||
&nd->dentry->d_name,
|
||||
&fh, &fattr);
|
||||
dput(parent);
|
||||
if (err != 0)
|
||||
goto out_err;
|
||||
@ -132,6 +139,8 @@ static void * nfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
|
||||
schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout);
|
||||
out:
|
||||
dprintk("%s: done, returned %d\n", __FUNCTION__, err);
|
||||
|
||||
dprintk("<-- nfs_follow_mountpoint() = %d\n", err);
|
||||
return ERR_PTR(err);
|
||||
out_err:
|
||||
path_release(nd);
|
||||
@ -172,22 +181,23 @@ void nfs_release_automount_timer(void)
|
||||
/*
|
||||
* Clone a mountpoint of the appropriate type
|
||||
*/
|
||||
static struct vfsmount *nfs_do_clone_mount(struct nfs_server *server, char *devname,
|
||||
static struct vfsmount *nfs_do_clone_mount(struct nfs_server *server,
|
||||
const char *devname,
|
||||
struct nfs_clone_mount *mountdata)
|
||||
{
|
||||
#ifdef CONFIG_NFS_V4
|
||||
struct vfsmount *mnt = NULL;
|
||||
switch (server->rpc_ops->version) {
|
||||
switch (server->nfs_client->cl_nfsversion) {
|
||||
case 2:
|
||||
case 3:
|
||||
mnt = vfs_kern_mount(&clone_nfs_fs_type, 0, devname, mountdata);
|
||||
mnt = vfs_kern_mount(&nfs_xdev_fs_type, 0, devname, mountdata);
|
||||
break;
|
||||
case 4:
|
||||
mnt = vfs_kern_mount(&clone_nfs4_fs_type, 0, devname, mountdata);
|
||||
mnt = vfs_kern_mount(&nfs4_xdev_fs_type, 0, devname, mountdata);
|
||||
}
|
||||
return mnt;
|
||||
#else
|
||||
return vfs_kern_mount(&clone_nfs_fs_type, 0, devname, mountdata);
|
||||
return vfs_kern_mount(&nfs_xdev_fs_type, 0, devname, mountdata);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -213,6 +223,8 @@ struct vfsmount *nfs_do_submount(const struct vfsmount *mnt_parent,
|
||||
char *page = (char *) __get_free_page(GFP_USER);
|
||||
char *devname;
|
||||
|
||||
dprintk("--> nfs_do_submount()\n");
|
||||
|
||||
dprintk("%s: submounting on %s/%s\n", __FUNCTION__,
|
||||
dentry->d_parent->d_name.name,
|
||||
dentry->d_name.name);
|
||||
@ -227,5 +239,7 @@ free_page:
|
||||
free_page((unsigned long)page);
|
||||
out:
|
||||
dprintk("%s: done\n", __FUNCTION__);
|
||||
|
||||
dprintk("<-- nfs_do_submount() = %p\n", mnt);
|
||||
return mnt;
|
||||
}
|
||||
|
@ -51,7 +51,7 @@
|
||||
#define NFS_createargs_sz (NFS_diropargs_sz+NFS_sattr_sz)
|
||||
#define NFS_renameargs_sz (NFS_diropargs_sz+NFS_diropargs_sz)
|
||||
#define NFS_linkargs_sz (NFS_fhandle_sz+NFS_diropargs_sz)
|
||||
#define NFS_symlinkargs_sz (NFS_diropargs_sz+NFS_path_sz+NFS_sattr_sz)
|
||||
#define NFS_symlinkargs_sz (NFS_diropargs_sz+1+NFS_sattr_sz)
|
||||
#define NFS_readdirargs_sz (NFS_fhandle_sz+2)
|
||||
|
||||
#define NFS_attrstat_sz (1+NFS_fattr_sz)
|
||||
@ -351,11 +351,26 @@ nfs_xdr_linkargs(struct rpc_rqst *req, u32 *p, struct nfs_linkargs *args)
|
||||
static int
|
||||
nfs_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_symlinkargs *args)
|
||||
{
|
||||
struct xdr_buf *sndbuf = &req->rq_snd_buf;
|
||||
size_t pad;
|
||||
|
||||
p = xdr_encode_fhandle(p, args->fromfh);
|
||||
p = xdr_encode_array(p, args->fromname, args->fromlen);
|
||||
p = xdr_encode_array(p, args->topath, args->tolen);
|
||||
*p++ = htonl(args->pathlen);
|
||||
sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
|
||||
|
||||
xdr_encode_pages(sndbuf, args->pages, 0, args->pathlen);
|
||||
|
||||
/*
|
||||
* xdr_encode_pages may have added a few bytes to ensure the
|
||||
* pathname ends on a 4-byte boundary. Start encoding the
|
||||
* attributes after the pad bytes.
|
||||
*/
|
||||
pad = sndbuf->tail->iov_len;
|
||||
if (pad > 0)
|
||||
p++;
|
||||
p = xdr_encode_sattr(p, args->sattr);
|
||||
req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
|
||||
sndbuf->len += xdr_adjust_iovec(sndbuf->tail, p) - pad;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -81,7 +81,7 @@ do_proc_get_root(struct rpc_clnt *client, struct nfs_fh *fhandle,
|
||||
}
|
||||
|
||||
/*
|
||||
* Bare-bones access to getattr: this is for nfs_read_super.
|
||||
* Bare-bones access to getattr: this is for nfs_get_root/nfs_get_sb
|
||||
*/
|
||||
static int
|
||||
nfs3_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
|
||||
@ -90,8 +90,8 @@ nfs3_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
|
||||
int status;
|
||||
|
||||
status = do_proc_get_root(server->client, fhandle, info);
|
||||
if (status && server->client_sys != server->client)
|
||||
status = do_proc_get_root(server->client_sys, fhandle, info);
|
||||
if (status && server->nfs_client->cl_rpcclient != server->client)
|
||||
status = do_proc_get_root(server->nfs_client->cl_rpcclient, fhandle, info);
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -544,23 +544,23 @@ nfs3_proc_link(struct inode *inode, struct inode *dir, struct qstr *name)
|
||||
}
|
||||
|
||||
static int
|
||||
nfs3_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path,
|
||||
struct iattr *sattr, struct nfs_fh *fhandle,
|
||||
struct nfs_fattr *fattr)
|
||||
nfs3_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page,
|
||||
unsigned int len, struct iattr *sattr)
|
||||
{
|
||||
struct nfs_fattr dir_attr;
|
||||
struct nfs_fh fhandle;
|
||||
struct nfs_fattr fattr, dir_attr;
|
||||
struct nfs3_symlinkargs arg = {
|
||||
.fromfh = NFS_FH(dir),
|
||||
.fromname = name->name,
|
||||
.fromlen = name->len,
|
||||
.topath = path->name,
|
||||
.tolen = path->len,
|
||||
.fromname = dentry->d_name.name,
|
||||
.fromlen = dentry->d_name.len,
|
||||
.pages = &page,
|
||||
.pathlen = len,
|
||||
.sattr = sattr
|
||||
};
|
||||
struct nfs3_diropres res = {
|
||||
.dir_attr = &dir_attr,
|
||||
.fh = fhandle,
|
||||
.fattr = fattr
|
||||
.fh = &fhandle,
|
||||
.fattr = &fattr
|
||||
};
|
||||
struct rpc_message msg = {
|
||||
.rpc_proc = &nfs3_procedures[NFS3PROC_SYMLINK],
|
||||
@ -569,13 +569,19 @@ nfs3_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path,
|
||||
};
|
||||
int status;
|
||||
|
||||
if (path->len > NFS3_MAXPATHLEN)
|
||||
if (len > NFS3_MAXPATHLEN)
|
||||
return -ENAMETOOLONG;
|
||||
dprintk("NFS call symlink %s -> %s\n", name->name, path->name);
|
||||
|
||||
dprintk("NFS call symlink %s\n", dentry->d_name.name);
|
||||
|
||||
nfs_fattr_init(&dir_attr);
|
||||
nfs_fattr_init(fattr);
|
||||
nfs_fattr_init(&fattr);
|
||||
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
|
||||
nfs_post_op_update_inode(dir, &dir_attr);
|
||||
if (status != 0)
|
||||
goto out;
|
||||
status = nfs_instantiate(dentry, &fhandle, &fattr);
|
||||
out:
|
||||
dprintk("NFS reply symlink: %d\n", status);
|
||||
return status;
|
||||
}
|
||||
@ -785,7 +791,7 @@ nfs3_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle,
|
||||
|
||||
dprintk("NFS call fsinfo\n");
|
||||
nfs_fattr_init(info->fattr);
|
||||
status = rpc_call_sync(server->client_sys, &msg, 0);
|
||||
status = rpc_call_sync(server->nfs_client->cl_rpcclient, &msg, 0);
|
||||
dprintk("NFS reply fsinfo: %d\n", status);
|
||||
return status;
|
||||
}
|
||||
@ -886,7 +892,7 @@ nfs3_proc_lock(struct file *filp, int cmd, struct file_lock *fl)
|
||||
return nlmclnt_proc(filp->f_dentry->d_inode, cmd, fl);
|
||||
}
|
||||
|
||||
struct nfs_rpc_ops nfs_v3_clientops = {
|
||||
const struct nfs_rpc_ops nfs_v3_clientops = {
|
||||
.version = 3, /* protocol version */
|
||||
.dentry_ops = &nfs_dentry_operations,
|
||||
.dir_inode_ops = &nfs3_dir_inode_operations,
|
||||
|
@ -56,7 +56,7 @@
|
||||
#define NFS3_writeargs_sz (NFS3_fh_sz+5)
|
||||
#define NFS3_createargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz)
|
||||
#define NFS3_mkdirargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz)
|
||||
#define NFS3_symlinkargs_sz (NFS3_diropargs_sz+NFS3_path_sz+NFS3_sattr_sz)
|
||||
#define NFS3_symlinkargs_sz (NFS3_diropargs_sz+1+NFS3_sattr_sz)
|
||||
#define NFS3_mknodargs_sz (NFS3_diropargs_sz+2+NFS3_sattr_sz)
|
||||
#define NFS3_renameargs_sz (NFS3_diropargs_sz+NFS3_diropargs_sz)
|
||||
#define NFS3_linkargs_sz (NFS3_fh_sz+NFS3_diropargs_sz)
|
||||
@ -398,8 +398,11 @@ nfs3_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_symlinkargs *args
|
||||
p = xdr_encode_fhandle(p, args->fromfh);
|
||||
p = xdr_encode_array(p, args->fromname, args->fromlen);
|
||||
p = xdr_encode_sattr(p, args->sattr);
|
||||
p = xdr_encode_array(p, args->topath, args->tolen);
|
||||
*p++ = htonl(args->pathlen);
|
||||
req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
|
||||
|
||||
/* Copy the page */
|
||||
xdr_encode_pages(&req->rq_snd_buf, args->pages, 0, args->pathlen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -42,55 +42,6 @@ enum nfs4_client_state {
|
||||
NFS4CLNT_LEASE_EXPIRED,
|
||||
};
|
||||
|
||||
/*
|
||||
* The nfs4_client identifies our client state to the server.
|
||||
*/
|
||||
struct nfs4_client {
|
||||
struct list_head cl_servers; /* Global list of servers */
|
||||
struct in_addr cl_addr; /* Server identifier */
|
||||
u64 cl_clientid; /* constant */
|
||||
nfs4_verifier cl_confirm;
|
||||
unsigned long cl_state;
|
||||
|
||||
u32 cl_lockowner_id;
|
||||
|
||||
/*
|
||||
* The following rwsem ensures exclusive access to the server
|
||||
* while we recover the state following a lease expiration.
|
||||
*/
|
||||
struct rw_semaphore cl_sem;
|
||||
|
||||
struct list_head cl_delegations;
|
||||
struct list_head cl_state_owners;
|
||||
struct list_head cl_unused;
|
||||
int cl_nunused;
|
||||
spinlock_t cl_lock;
|
||||
atomic_t cl_count;
|
||||
|
||||
struct rpc_clnt * cl_rpcclient;
|
||||
|
||||
struct list_head cl_superblocks; /* List of nfs_server structs */
|
||||
|
||||
unsigned long cl_lease_time;
|
||||
unsigned long cl_last_renewal;
|
||||
struct work_struct cl_renewd;
|
||||
struct work_struct cl_recoverd;
|
||||
|
||||
struct rpc_wait_queue cl_rpcwaitq;
|
||||
|
||||
/* used for the setclientid verifier */
|
||||
struct timespec cl_boot_time;
|
||||
|
||||
/* idmapper */
|
||||
struct idmap * cl_idmap;
|
||||
|
||||
/* Our own IP address, as a null-terminated string.
|
||||
* This is used to generate the clientid, and the callback address.
|
||||
*/
|
||||
char cl_ipaddr[16];
|
||||
unsigned char cl_id_uniquifier;
|
||||
};
|
||||
|
||||
/*
|
||||
* struct rpc_sequence ensures that RPC calls are sent in the exact
|
||||
* order that they appear on the list.
|
||||
@ -127,7 +78,7 @@ static inline void nfs_confirm_seqid(struct nfs_seqid_counter *seqid, int status
|
||||
struct nfs4_state_owner {
|
||||
spinlock_t so_lock;
|
||||
struct list_head so_list; /* per-clientid list of state_owners */
|
||||
struct nfs4_client *so_client;
|
||||
struct nfs_client *so_client;
|
||||
u32 so_id; /* 32-bit identifier, unique */
|
||||
atomic_t so_count;
|
||||
|
||||
@ -210,10 +161,10 @@ extern ssize_t nfs4_listxattr(struct dentry *, char *, size_t);
|
||||
|
||||
/* nfs4proc.c */
|
||||
extern int nfs4_map_errors(int err);
|
||||
extern int nfs4_proc_setclientid(struct nfs4_client *, u32, unsigned short, struct rpc_cred *);
|
||||
extern int nfs4_proc_setclientid_confirm(struct nfs4_client *, struct rpc_cred *);
|
||||
extern int nfs4_proc_async_renew(struct nfs4_client *, struct rpc_cred *);
|
||||
extern int nfs4_proc_renew(struct nfs4_client *, struct rpc_cred *);
|
||||
extern int nfs4_proc_setclientid(struct nfs_client *, u32, unsigned short, struct rpc_cred *);
|
||||
extern int nfs4_proc_setclientid_confirm(struct nfs_client *, struct rpc_cred *);
|
||||
extern int nfs4_proc_async_renew(struct nfs_client *, struct rpc_cred *);
|
||||
extern int nfs4_proc_renew(struct nfs_client *, struct rpc_cred *);
|
||||
extern int nfs4_do_close(struct inode *inode, struct nfs4_state *state);
|
||||
extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *);
|
||||
extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *);
|
||||
@ -231,19 +182,14 @@ extern const u32 nfs4_fsinfo_bitmap[2];
|
||||
extern const u32 nfs4_fs_locations_bitmap[2];
|
||||
|
||||
/* nfs4renewd.c */
|
||||
extern void nfs4_schedule_state_renewal(struct nfs4_client *);
|
||||
extern void nfs4_schedule_state_renewal(struct nfs_client *);
|
||||
extern void nfs4_renewd_prepare_shutdown(struct nfs_server *);
|
||||
extern void nfs4_kill_renewd(struct nfs4_client *);
|
||||
extern void nfs4_kill_renewd(struct nfs_client *);
|
||||
extern void nfs4_renew_state(void *);
|
||||
|
||||
/* nfs4state.c */
|
||||
extern void init_nfsv4_state(struct nfs_server *);
|
||||
extern void destroy_nfsv4_state(struct nfs_server *);
|
||||
extern struct nfs4_client *nfs4_get_client(struct in_addr *);
|
||||
extern void nfs4_put_client(struct nfs4_client *clp);
|
||||
extern struct nfs4_client *nfs4_find_client(struct in_addr *);
|
||||
struct rpc_cred *nfs4_get_renew_cred(struct nfs4_client *clp);
|
||||
extern u32 nfs4_alloc_lockowner_id(struct nfs4_client *);
|
||||
struct rpc_cred *nfs4_get_renew_cred(struct nfs_client *clp);
|
||||
extern u32 nfs4_alloc_lockowner_id(struct nfs_client *);
|
||||
|
||||
extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *);
|
||||
extern void nfs4_put_state_owner(struct nfs4_state_owner *);
|
||||
@ -252,7 +198,7 @@ extern struct nfs4_state * nfs4_get_open_state(struct inode *, struct nfs4_state
|
||||
extern void nfs4_put_open_state(struct nfs4_state *);
|
||||
extern void nfs4_close_state(struct nfs4_state *, mode_t);
|
||||
extern void nfs4_state_set_mode_locked(struct nfs4_state *, mode_t);
|
||||
extern void nfs4_schedule_state_recovery(struct nfs4_client *);
|
||||
extern void nfs4_schedule_state_recovery(struct nfs_client *);
|
||||
extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp);
|
||||
extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl);
|
||||
extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t);
|
||||
@ -276,10 +222,6 @@ extern struct svc_version nfs4_callback_version1;
|
||||
|
||||
#else
|
||||
|
||||
#define init_nfsv4_state(server) do { } while (0)
|
||||
#define destroy_nfsv4_state(server) do { } while (0)
|
||||
#define nfs4_put_state_owner(inode, owner) do { } while (0)
|
||||
#define nfs4_put_open_state(state) do { } while (0)
|
||||
#define nfs4_close_state(a, b) do { } while (0)
|
||||
|
||||
#endif /* CONFIG_NFS_V4 */
|
||||
|
@ -2,6 +2,7 @@
|
||||
* linux/fs/nfs/nfs4namespace.c
|
||||
*
|
||||
* Copyright (C) 2005 Trond Myklebust <Trond.Myklebust@netapp.com>
|
||||
* - Modified by David Howells <dhowells@redhat.com>
|
||||
*
|
||||
* NFSv4 namespace
|
||||
*/
|
||||
@ -23,7 +24,7 @@
|
||||
/*
|
||||
* Check if fs_root is valid
|
||||
*/
|
||||
static inline char *nfs4_pathname_string(struct nfs4_pathname *pathname,
|
||||
static inline char *nfs4_pathname_string(const struct nfs4_pathname *pathname,
|
||||
char *buffer, ssize_t buflen)
|
||||
{
|
||||
char *end = buffer + buflen;
|
||||
@ -34,7 +35,7 @@ static inline char *nfs4_pathname_string(struct nfs4_pathname *pathname,
|
||||
|
||||
n = pathname->ncomponents;
|
||||
while (--n >= 0) {
|
||||
struct nfs4_string *component = &pathname->components[n];
|
||||
const struct nfs4_string *component = &pathname->components[n];
|
||||
buflen -= component->len + 1;
|
||||
if (buflen < 0)
|
||||
goto Elong;
|
||||
@ -47,6 +48,68 @@ Elong:
|
||||
return ERR_PTR(-ENAMETOOLONG);
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine the mount path as a string
|
||||
*/
|
||||
static char *nfs4_path(const struct vfsmount *mnt_parent,
|
||||
const struct dentry *dentry,
|
||||
char *buffer, ssize_t buflen)
|
||||
{
|
||||
const char *srvpath;
|
||||
|
||||
srvpath = strchr(mnt_parent->mnt_devname, ':');
|
||||
if (srvpath)
|
||||
srvpath++;
|
||||
else
|
||||
srvpath = mnt_parent->mnt_devname;
|
||||
|
||||
return nfs_path(srvpath, mnt_parent->mnt_root, dentry, buffer, buflen);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that fs_locations::fs_root [RFC3530 6.3] is a prefix for what we
|
||||
* believe to be the server path to this dentry
|
||||
*/
|
||||
static int nfs4_validate_fspath(const struct vfsmount *mnt_parent,
|
||||
const struct dentry *dentry,
|
||||
const struct nfs4_fs_locations *locations,
|
||||
char *page, char *page2)
|
||||
{
|
||||
const char *path, *fs_path;
|
||||
|
||||
path = nfs4_path(mnt_parent, dentry, page, PAGE_SIZE);
|
||||
if (IS_ERR(path))
|
||||
return PTR_ERR(path);
|
||||
|
||||
fs_path = nfs4_pathname_string(&locations->fs_path, page2, PAGE_SIZE);
|
||||
if (IS_ERR(fs_path))
|
||||
return PTR_ERR(fs_path);
|
||||
|
||||
if (strncmp(path, fs_path, strlen(fs_path)) != 0) {
|
||||
dprintk("%s: path %s does not begin with fsroot %s\n",
|
||||
__FUNCTION__, path, fs_path);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the string represents a "valid" IPv4 address
|
||||
*/
|
||||
static inline int valid_ipaddr4(const char *buf)
|
||||
{
|
||||
int rc, count, in[4];
|
||||
|
||||
rc = sscanf(buf, "%d.%d.%d.%d", &in[0], &in[1], &in[2], &in[3]);
|
||||
if (rc != 4)
|
||||
return -EINVAL;
|
||||
for (count = 0; count < 4; count++) {
|
||||
if (in[count] > 255)
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* nfs_follow_referral - set up mountpoint when hitting a referral on moved error
|
||||
@ -60,7 +123,7 @@ Elong:
|
||||
*/
|
||||
static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent,
|
||||
const struct dentry *dentry,
|
||||
struct nfs4_fs_locations *locations)
|
||||
const struct nfs4_fs_locations *locations)
|
||||
{
|
||||
struct vfsmount *mnt = ERR_PTR(-ENOENT);
|
||||
struct nfs_clone_mount mountdata = {
|
||||
@ -68,10 +131,9 @@ static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent,
|
||||
.dentry = dentry,
|
||||
.authflavor = NFS_SB(mnt_parent->mnt_sb)->client->cl_auth->au_flavor,
|
||||
};
|
||||
char *page, *page2;
|
||||
char *path, *fs_path;
|
||||
char *page = NULL, *page2 = NULL;
|
||||
char *devname;
|
||||
int loc, s;
|
||||
int loc, s, error;
|
||||
|
||||
if (locations == NULL || locations->nlocations <= 0)
|
||||
goto out;
|
||||
@ -79,36 +141,30 @@ static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent,
|
||||
dprintk("%s: referral at %s/%s\n", __FUNCTION__,
|
||||
dentry->d_parent->d_name.name, dentry->d_name.name);
|
||||
|
||||
/* Ensure fs path is a prefix of current dentry path */
|
||||
page = (char *) __get_free_page(GFP_USER);
|
||||
if (page == NULL)
|
||||
if (!page)
|
||||
goto out;
|
||||
|
||||
page2 = (char *) __get_free_page(GFP_USER);
|
||||
if (page2 == NULL)
|
||||
if (!page2)
|
||||
goto out;
|
||||
|
||||
path = nfs4_path(dentry, page, PAGE_SIZE);
|
||||
if (IS_ERR(path))
|
||||
goto out_free;
|
||||
|
||||
fs_path = nfs4_pathname_string(&locations->fs_path, page2, PAGE_SIZE);
|
||||
if (IS_ERR(fs_path))
|
||||
goto out_free;
|
||||
|
||||
if (strncmp(path, fs_path, strlen(fs_path)) != 0) {
|
||||
dprintk("%s: path %s does not begin with fsroot %s\n", __FUNCTION__, path, fs_path);
|
||||
goto out_free;
|
||||
/* Ensure fs path is a prefix of current dentry path */
|
||||
error = nfs4_validate_fspath(mnt_parent, dentry, locations, page, page2);
|
||||
if (error < 0) {
|
||||
mnt = ERR_PTR(error);
|
||||
goto out;
|
||||
}
|
||||
|
||||
devname = nfs_devname(mnt_parent, dentry, page, PAGE_SIZE);
|
||||
if (IS_ERR(devname)) {
|
||||
mnt = (struct vfsmount *)devname;
|
||||
goto out_free;
|
||||
goto out;
|
||||
}
|
||||
|
||||
loc = 0;
|
||||
while (loc < locations->nlocations && IS_ERR(mnt)) {
|
||||
struct nfs4_fs_location *location = &locations->locations[loc];
|
||||
const struct nfs4_fs_location *location = &locations->locations[loc];
|
||||
char *mnt_path;
|
||||
|
||||
if (location == NULL || location->nservers <= 0 ||
|
||||
@ -140,7 +196,7 @@ static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent,
|
||||
addr.sin_port = htons(NFS_PORT);
|
||||
mountdata.addr = &addr;
|
||||
|
||||
mnt = vfs_kern_mount(&nfs_referral_nfs4_fs_type, 0, devname, &mountdata);
|
||||
mnt = vfs_kern_mount(&nfs4_referral_fs_type, 0, devname, &mountdata);
|
||||
if (!IS_ERR(mnt)) {
|
||||
break;
|
||||
}
|
||||
@ -149,10 +205,9 @@ static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent,
|
||||
loc++;
|
||||
}
|
||||
|
||||
out_free:
|
||||
free_page((unsigned long)page);
|
||||
free_page((unsigned long)page2);
|
||||
out:
|
||||
free_page((unsigned long) page);
|
||||
free_page((unsigned long) page2);
|
||||
dprintk("%s: done\n", __FUNCTION__);
|
||||
return mnt;
|
||||
}
|
||||
@ -165,7 +220,7 @@ out:
|
||||
*/
|
||||
struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentry *dentry)
|
||||
{
|
||||
struct vfsmount *mnt = ERR_PTR(-ENOENT);
|
||||
struct vfsmount *mnt = ERR_PTR(-ENOMEM);
|
||||
struct dentry *parent;
|
||||
struct nfs4_fs_locations *fs_locations = NULL;
|
||||
struct page *page;
|
||||
@ -183,11 +238,16 @@ struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentr
|
||||
goto out_free;
|
||||
|
||||
/* Get locations */
|
||||
mnt = ERR_PTR(-ENOENT);
|
||||
|
||||
parent = dget_parent(dentry);
|
||||
dprintk("%s: getting locations for %s/%s\n", __FUNCTION__, parent->d_name.name, dentry->d_name.name);
|
||||
dprintk("%s: getting locations for %s/%s\n",
|
||||
__FUNCTION__, parent->d_name.name, dentry->d_name.name);
|
||||
|
||||
err = nfs4_proc_fs_locations(parent->d_inode, dentry, fs_locations, page);
|
||||
dput(parent);
|
||||
if (err != 0 || fs_locations->nlocations <= 0 ||
|
||||
if (err != 0 ||
|
||||
fs_locations->nlocations <= 0 ||
|
||||
fs_locations->fs_path.ncomponents <= 0)
|
||||
goto out_free;
|
||||
|
||||
|
@ -55,7 +55,7 @@
|
||||
|
||||
#define NFSDBG_FACILITY NFSDBG_PROC
|
||||
|
||||
#define NFS4_POLL_RETRY_MIN (1*HZ)
|
||||
#define NFS4_POLL_RETRY_MIN (HZ/10)
|
||||
#define NFS4_POLL_RETRY_MAX (15*HZ)
|
||||
|
||||
struct nfs4_opendata;
|
||||
@ -64,7 +64,7 @@ static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinf
|
||||
static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *);
|
||||
static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry);
|
||||
static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception);
|
||||
static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs4_client *clp);
|
||||
static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs_client *clp);
|
||||
|
||||
/* Prevent leaks of NFSv4 errors into userland */
|
||||
int nfs4_map_errors(int err)
|
||||
@ -195,7 +195,7 @@ static void nfs4_setup_readdir(u64 cookie, u32 *verifier, struct dentry *dentry,
|
||||
|
||||
static void renew_lease(const struct nfs_server *server, unsigned long timestamp)
|
||||
{
|
||||
struct nfs4_client *clp = server->nfs4_state;
|
||||
struct nfs_client *clp = server->nfs_client;
|
||||
spin_lock(&clp->cl_lock);
|
||||
if (time_before(clp->cl_last_renewal,timestamp))
|
||||
clp->cl_last_renewal = timestamp;
|
||||
@ -252,7 +252,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
|
||||
atomic_inc(&sp->so_count);
|
||||
p->o_arg.fh = NFS_FH(dir);
|
||||
p->o_arg.open_flags = flags,
|
||||
p->o_arg.clientid = server->nfs4_state->cl_clientid;
|
||||
p->o_arg.clientid = server->nfs_client->cl_clientid;
|
||||
p->o_arg.id = sp->so_id;
|
||||
p->o_arg.name = &dentry->d_name;
|
||||
p->o_arg.server = server;
|
||||
@ -550,7 +550,7 @@ int nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state)
|
||||
case -NFS4ERR_STALE_STATEID:
|
||||
case -NFS4ERR_EXPIRED:
|
||||
/* Don't recall a delegation if it was lost */
|
||||
nfs4_schedule_state_recovery(server->nfs4_state);
|
||||
nfs4_schedule_state_recovery(server->nfs_client);
|
||||
return err;
|
||||
}
|
||||
err = nfs4_handle_exception(server, err, &exception);
|
||||
@ -758,7 +758,7 @@ static int _nfs4_proc_open(struct nfs4_opendata *data)
|
||||
}
|
||||
nfs_confirm_seqid(&data->owner->so_seqid, 0);
|
||||
if (!(o_res->f_attr->valid & NFS_ATTR_FATTR))
|
||||
return server->rpc_ops->getattr(server, &o_res->fh, o_res->f_attr);
|
||||
return server->nfs_client->rpc_ops->getattr(server, &o_res->fh, o_res->f_attr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -792,11 +792,18 @@ out:
|
||||
|
||||
int nfs4_recover_expired_lease(struct nfs_server *server)
|
||||
{
|
||||
struct nfs4_client *clp = server->nfs4_state;
|
||||
struct nfs_client *clp = server->nfs_client;
|
||||
int ret;
|
||||
|
||||
if (test_and_clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state))
|
||||
for (;;) {
|
||||
ret = nfs4_wait_clnt_recover(server->client, clp);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
if (!test_and_clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state))
|
||||
break;
|
||||
nfs4_schedule_state_recovery(clp);
|
||||
return nfs4_wait_clnt_recover(server->client, clp);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -867,7 +874,7 @@ static int _nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred
|
||||
{
|
||||
struct nfs_delegation *delegation;
|
||||
struct nfs_server *server = NFS_SERVER(inode);
|
||||
struct nfs4_client *clp = server->nfs4_state;
|
||||
struct nfs_client *clp = server->nfs_client;
|
||||
struct nfs_inode *nfsi = NFS_I(inode);
|
||||
struct nfs4_state_owner *sp = NULL;
|
||||
struct nfs4_state *state = NULL;
|
||||
@ -953,7 +960,7 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, st
|
||||
struct nfs4_state_owner *sp;
|
||||
struct nfs4_state *state = NULL;
|
||||
struct nfs_server *server = NFS_SERVER(dir);
|
||||
struct nfs4_client *clp = server->nfs4_state;
|
||||
struct nfs_client *clp = server->nfs_client;
|
||||
struct nfs4_opendata *opendata;
|
||||
int status;
|
||||
|
||||
@ -1133,7 +1140,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
|
||||
break;
|
||||
case -NFS4ERR_STALE_STATEID:
|
||||
case -NFS4ERR_EXPIRED:
|
||||
nfs4_schedule_state_recovery(server->nfs4_state);
|
||||
nfs4_schedule_state_recovery(server->nfs_client);
|
||||
break;
|
||||
default:
|
||||
if (nfs4_async_handle_error(task, server) == -EAGAIN) {
|
||||
@ -1268,7 +1275,7 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
|
||||
BUG_ON(nd->intent.open.flags & O_CREAT);
|
||||
}
|
||||
|
||||
cred = rpcauth_lookupcred(NFS_SERVER(dir)->client->cl_auth, 0);
|
||||
cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0);
|
||||
if (IS_ERR(cred))
|
||||
return (struct dentry *)cred;
|
||||
state = nfs4_do_open(dir, dentry, nd->intent.open.flags, &attr, cred);
|
||||
@ -1291,7 +1298,7 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, st
|
||||
struct rpc_cred *cred;
|
||||
struct nfs4_state *state;
|
||||
|
||||
cred = rpcauth_lookupcred(NFS_SERVER(dir)->client->cl_auth, 0);
|
||||
cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0);
|
||||
if (IS_ERR(cred))
|
||||
return PTR_ERR(cred);
|
||||
state = nfs4_open_delegated(dentry->d_inode, openflags, cred);
|
||||
@ -1393,70 +1400,19 @@ static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* get the file handle for the "/" directory on the server
|
||||
*/
|
||||
static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
|
||||
struct nfs_fsinfo *info)
|
||||
struct nfs_fsinfo *info)
|
||||
{
|
||||
struct nfs_fattr * fattr = info->fattr;
|
||||
unsigned char * p;
|
||||
struct qstr q;
|
||||
struct nfs4_lookup_arg args = {
|
||||
.dir_fh = fhandle,
|
||||
.name = &q,
|
||||
.bitmask = nfs4_fattr_bitmap,
|
||||
};
|
||||
struct nfs4_lookup_res res = {
|
||||
.server = server,
|
||||
.fattr = fattr,
|
||||
.fh = fhandle,
|
||||
};
|
||||
struct rpc_message msg = {
|
||||
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOOKUP],
|
||||
.rpc_argp = &args,
|
||||
.rpc_resp = &res,
|
||||
};
|
||||
int status;
|
||||
|
||||
/*
|
||||
* Now we do a separate LOOKUP for each component of the mount path.
|
||||
* The LOOKUPs are done separately so that we can conveniently
|
||||
* catch an ERR_WRONGSEC if it occurs along the way...
|
||||
*/
|
||||
status = nfs4_lookup_root(server, fhandle, info);
|
||||
if (status)
|
||||
goto out;
|
||||
|
||||
p = server->mnt_path;
|
||||
for (;;) {
|
||||
struct nfs4_exception exception = { };
|
||||
|
||||
while (*p == '/')
|
||||
p++;
|
||||
if (!*p)
|
||||
break;
|
||||
q.name = p;
|
||||
while (*p && (*p != '/'))
|
||||
p++;
|
||||
q.len = p - q.name;
|
||||
|
||||
do {
|
||||
nfs_fattr_init(fattr);
|
||||
status = nfs4_handle_exception(server,
|
||||
rpc_call_sync(server->client, &msg, 0),
|
||||
&exception);
|
||||
} while (exception.retry);
|
||||
if (status == 0)
|
||||
continue;
|
||||
if (status == -ENOENT) {
|
||||
printk(KERN_NOTICE "NFS: mount path %s does not exist!\n", server->mnt_path);
|
||||
printk(KERN_NOTICE "NFS: suggestion: try mounting '/' instead.\n");
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (status == 0)
|
||||
status = nfs4_server_capabilities(server, fhandle);
|
||||
if (status == 0)
|
||||
status = nfs4_do_fsinfo(server, fhandle, info);
|
||||
out:
|
||||
return nfs4_map_errors(status);
|
||||
}
|
||||
|
||||
@ -1565,7 +1521,7 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
|
||||
|
||||
nfs_fattr_init(fattr);
|
||||
|
||||
cred = rpcauth_lookupcred(NFS_SERVER(inode)->client->cl_auth, 0);
|
||||
cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0);
|
||||
if (IS_ERR(cred))
|
||||
return PTR_ERR(cred);
|
||||
|
||||
@ -1583,6 +1539,52 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
|
||||
return status;
|
||||
}
|
||||
|
||||
static int _nfs4_proc_lookupfh(struct nfs_server *server, struct nfs_fh *dirfh,
|
||||
struct qstr *name, struct nfs_fh *fhandle,
|
||||
struct nfs_fattr *fattr)
|
||||
{
|
||||
int status;
|
||||
struct nfs4_lookup_arg args = {
|
||||
.bitmask = server->attr_bitmask,
|
||||
.dir_fh = dirfh,
|
||||
.name = name,
|
||||
};
|
||||
struct nfs4_lookup_res res = {
|
||||
.server = server,
|
||||
.fattr = fattr,
|
||||
.fh = fhandle,
|
||||
};
|
||||
struct rpc_message msg = {
|
||||
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOOKUP],
|
||||
.rpc_argp = &args,
|
||||
.rpc_resp = &res,
|
||||
};
|
||||
|
||||
nfs_fattr_init(fattr);
|
||||
|
||||
dprintk("NFS call lookupfh %s\n", name->name);
|
||||
status = rpc_call_sync(server->client, &msg, 0);
|
||||
dprintk("NFS reply lookupfh: %d\n", status);
|
||||
if (status == -NFS4ERR_MOVED)
|
||||
status = -EREMOTE;
|
||||
return status;
|
||||
}
|
||||
|
||||
static int nfs4_proc_lookupfh(struct nfs_server *server, struct nfs_fh *dirfh,
|
||||
struct qstr *name, struct nfs_fh *fhandle,
|
||||
struct nfs_fattr *fattr)
|
||||
{
|
||||
struct nfs4_exception exception = { };
|
||||
int err;
|
||||
do {
|
||||
err = nfs4_handle_exception(server,
|
||||
_nfs4_proc_lookupfh(server, dirfh, name,
|
||||
fhandle, fattr),
|
||||
&exception);
|
||||
} while (exception.retry);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int _nfs4_proc_lookup(struct inode *dir, struct qstr *name,
|
||||
struct nfs_fh *fhandle, struct nfs_fattr *fattr)
|
||||
{
|
||||
@ -1881,7 +1883,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
|
||||
struct rpc_cred *cred;
|
||||
int status = 0;
|
||||
|
||||
cred = rpcauth_lookupcred(NFS_SERVER(dir)->client->cl_auth, 0);
|
||||
cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0);
|
||||
if (IS_ERR(cred)) {
|
||||
status = PTR_ERR(cred);
|
||||
goto out;
|
||||
@ -2089,24 +2091,24 @@ static int nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *n
|
||||
return err;
|
||||
}
|
||||
|
||||
static int _nfs4_proc_symlink(struct inode *dir, struct qstr *name,
|
||||
struct qstr *path, struct iattr *sattr, struct nfs_fh *fhandle,
|
||||
struct nfs_fattr *fattr)
|
||||
static int _nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
|
||||
struct page *page, unsigned int len, struct iattr *sattr)
|
||||
{
|
||||
struct nfs_server *server = NFS_SERVER(dir);
|
||||
struct nfs_fattr dir_fattr;
|
||||
struct nfs_fh fhandle;
|
||||
struct nfs_fattr fattr, dir_fattr;
|
||||
struct nfs4_create_arg arg = {
|
||||
.dir_fh = NFS_FH(dir),
|
||||
.server = server,
|
||||
.name = name,
|
||||
.name = &dentry->d_name,
|
||||
.attrs = sattr,
|
||||
.ftype = NF4LNK,
|
||||
.bitmask = server->attr_bitmask,
|
||||
};
|
||||
struct nfs4_create_res res = {
|
||||
.server = server,
|
||||
.fh = fhandle,
|
||||
.fattr = fattr,
|
||||
.fh = &fhandle,
|
||||
.fattr = &fattr,
|
||||
.dir_fattr = &dir_fattr,
|
||||
};
|
||||
struct rpc_message msg = {
|
||||
@ -2116,29 +2118,32 @@ static int _nfs4_proc_symlink(struct inode *dir, struct qstr *name,
|
||||
};
|
||||
int status;
|
||||
|
||||
if (path->len > NFS4_MAXPATHLEN)
|
||||
if (len > NFS4_MAXPATHLEN)
|
||||
return -ENAMETOOLONG;
|
||||
arg.u.symlink = path;
|
||||
nfs_fattr_init(fattr);
|
||||
|
||||
arg.u.symlink.pages = &page;
|
||||
arg.u.symlink.len = len;
|
||||
nfs_fattr_init(&fattr);
|
||||
nfs_fattr_init(&dir_fattr);
|
||||
|
||||
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
|
||||
if (!status)
|
||||
if (!status) {
|
||||
update_changeattr(dir, &res.dir_cinfo);
|
||||
nfs_post_op_update_inode(dir, res.dir_fattr);
|
||||
nfs_post_op_update_inode(dir, res.dir_fattr);
|
||||
status = nfs_instantiate(dentry, &fhandle, &fattr);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
static int nfs4_proc_symlink(struct inode *dir, struct qstr *name,
|
||||
struct qstr *path, struct iattr *sattr, struct nfs_fh *fhandle,
|
||||
struct nfs_fattr *fattr)
|
||||
static int nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
|
||||
struct page *page, unsigned int len, struct iattr *sattr)
|
||||
{
|
||||
struct nfs4_exception exception = { };
|
||||
int err;
|
||||
do {
|
||||
err = nfs4_handle_exception(NFS_SERVER(dir),
|
||||
_nfs4_proc_symlink(dir, name, path, sattr,
|
||||
fhandle, fattr),
|
||||
_nfs4_proc_symlink(dir, dentry, page,
|
||||
len, sattr),
|
||||
&exception);
|
||||
} while (exception.retry);
|
||||
return err;
|
||||
@ -2521,7 +2526,7 @@ static void nfs4_proc_commit_setup(struct nfs_write_data *data, int how)
|
||||
*/
|
||||
static void nfs4_renew_done(struct rpc_task *task, void *data)
|
||||
{
|
||||
struct nfs4_client *clp = (struct nfs4_client *)task->tk_msg.rpc_argp;
|
||||
struct nfs_client *clp = (struct nfs_client *)task->tk_msg.rpc_argp;
|
||||
unsigned long timestamp = (unsigned long)data;
|
||||
|
||||
if (task->tk_status < 0) {
|
||||
@ -2543,7 +2548,7 @@ static const struct rpc_call_ops nfs4_renew_ops = {
|
||||
.rpc_call_done = nfs4_renew_done,
|
||||
};
|
||||
|
||||
int nfs4_proc_async_renew(struct nfs4_client *clp, struct rpc_cred *cred)
|
||||
int nfs4_proc_async_renew(struct nfs_client *clp, struct rpc_cred *cred)
|
||||
{
|
||||
struct rpc_message msg = {
|
||||
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENEW],
|
||||
@ -2555,7 +2560,7 @@ int nfs4_proc_async_renew(struct nfs4_client *clp, struct rpc_cred *cred)
|
||||
&nfs4_renew_ops, (void *)jiffies);
|
||||
}
|
||||
|
||||
int nfs4_proc_renew(struct nfs4_client *clp, struct rpc_cred *cred)
|
||||
int nfs4_proc_renew(struct nfs_client *clp, struct rpc_cred *cred)
|
||||
{
|
||||
struct rpc_message msg = {
|
||||
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENEW],
|
||||
@ -2770,7 +2775,7 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl
|
||||
return -EOPNOTSUPP;
|
||||
nfs_inode_return_delegation(inode);
|
||||
buf_to_pages(buf, buflen, arg.acl_pages, &arg.acl_pgbase);
|
||||
ret = rpc_call_sync(NFS_SERVER(inode)->client, &msg, 0);
|
||||
ret = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
|
||||
if (ret == 0)
|
||||
nfs4_write_cached_acl(inode, buf, buflen);
|
||||
return ret;
|
||||
@ -2791,7 +2796,7 @@ static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen
|
||||
static int
|
||||
nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server)
|
||||
{
|
||||
struct nfs4_client *clp = server->nfs4_state;
|
||||
struct nfs_client *clp = server->nfs_client;
|
||||
|
||||
if (!clp || task->tk_status >= 0)
|
||||
return 0;
|
||||
@ -2828,7 +2833,7 @@ static int nfs4_wait_bit_interruptible(void *word)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs4_client *clp)
|
||||
static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs_client *clp)
|
||||
{
|
||||
sigset_t oldset;
|
||||
int res;
|
||||
@ -2871,7 +2876,7 @@ static int nfs4_delay(struct rpc_clnt *clnt, long *timeout)
|
||||
*/
|
||||
int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception)
|
||||
{
|
||||
struct nfs4_client *clp = server->nfs4_state;
|
||||
struct nfs_client *clp = server->nfs_client;
|
||||
int ret = errorcode;
|
||||
|
||||
exception->retry = 0;
|
||||
@ -2886,6 +2891,7 @@ int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct
|
||||
if (ret == 0)
|
||||
exception->retry = 1;
|
||||
break;
|
||||
case -NFS4ERR_FILE_OPEN:
|
||||
case -NFS4ERR_GRACE:
|
||||
case -NFS4ERR_DELAY:
|
||||
ret = nfs4_delay(server->client, &exception->timeout);
|
||||
@ -2898,7 +2904,7 @@ int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct
|
||||
return nfs4_map_errors(ret);
|
||||
}
|
||||
|
||||
int nfs4_proc_setclientid(struct nfs4_client *clp, u32 program, unsigned short port, struct rpc_cred *cred)
|
||||
int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, unsigned short port, struct rpc_cred *cred)
|
||||
{
|
||||
nfs4_verifier sc_verifier;
|
||||
struct nfs4_setclientid setclientid = {
|
||||
@ -2922,7 +2928,7 @@ int nfs4_proc_setclientid(struct nfs4_client *clp, u32 program, unsigned short p
|
||||
for(;;) {
|
||||
setclientid.sc_name_len = scnprintf(setclientid.sc_name,
|
||||
sizeof(setclientid.sc_name), "%s/%u.%u.%u.%u %s %u",
|
||||
clp->cl_ipaddr, NIPQUAD(clp->cl_addr.s_addr),
|
||||
clp->cl_ipaddr, NIPQUAD(clp->cl_addr.sin_addr),
|
||||
cred->cr_ops->cr_name,
|
||||
clp->cl_id_uniquifier);
|
||||
setclientid.sc_netid_len = scnprintf(setclientid.sc_netid,
|
||||
@ -2945,7 +2951,7 @@ int nfs4_proc_setclientid(struct nfs4_client *clp, u32 program, unsigned short p
|
||||
return status;
|
||||
}
|
||||
|
||||
static int _nfs4_proc_setclientid_confirm(struct nfs4_client *clp, struct rpc_cred *cred)
|
||||
static int _nfs4_proc_setclientid_confirm(struct nfs_client *clp, struct rpc_cred *cred)
|
||||
{
|
||||
struct nfs_fsinfo fsinfo;
|
||||
struct rpc_message msg = {
|
||||
@ -2969,7 +2975,7 @@ static int _nfs4_proc_setclientid_confirm(struct nfs4_client *clp, struct rpc_cr
|
||||
return status;
|
||||
}
|
||||
|
||||
int nfs4_proc_setclientid_confirm(struct nfs4_client *clp, struct rpc_cred *cred)
|
||||
int nfs4_proc_setclientid_confirm(struct nfs_client *clp, struct rpc_cred *cred)
|
||||
{
|
||||
long timeout;
|
||||
int err;
|
||||
@ -3077,7 +3083,7 @@ int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4
|
||||
switch (err) {
|
||||
case -NFS4ERR_STALE_STATEID:
|
||||
case -NFS4ERR_EXPIRED:
|
||||
nfs4_schedule_state_recovery(server->nfs4_state);
|
||||
nfs4_schedule_state_recovery(server->nfs_client);
|
||||
case 0:
|
||||
return 0;
|
||||
}
|
||||
@ -3106,7 +3112,7 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock
|
||||
{
|
||||
struct inode *inode = state->inode;
|
||||
struct nfs_server *server = NFS_SERVER(inode);
|
||||
struct nfs4_client *clp = server->nfs4_state;
|
||||
struct nfs_client *clp = server->nfs_client;
|
||||
struct nfs_lockt_args arg = {
|
||||
.fh = NFS_FH(inode),
|
||||
.fl = request,
|
||||
@ -3231,7 +3237,7 @@ static void nfs4_locku_done(struct rpc_task *task, void *data)
|
||||
break;
|
||||
case -NFS4ERR_STALE_STATEID:
|
||||
case -NFS4ERR_EXPIRED:
|
||||
nfs4_schedule_state_recovery(calldata->server->nfs4_state);
|
||||
nfs4_schedule_state_recovery(calldata->server->nfs_client);
|
||||
break;
|
||||
default:
|
||||
if (nfs4_async_handle_error(task, calldata->server) == -EAGAIN) {
|
||||
@ -3343,7 +3349,7 @@ static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl,
|
||||
if (p->arg.lock_seqid == NULL)
|
||||
goto out_free;
|
||||
p->arg.lock_stateid = &lsp->ls_stateid;
|
||||
p->arg.lock_owner.clientid = server->nfs4_state->cl_clientid;
|
||||
p->arg.lock_owner.clientid = server->nfs_client->cl_clientid;
|
||||
p->arg.lock_owner.id = lsp->ls_id;
|
||||
p->lsp = lsp;
|
||||
atomic_inc(&lsp->ls_count);
|
||||
@ -3513,7 +3519,7 @@ static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request
|
||||
|
||||
static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)
|
||||
{
|
||||
struct nfs4_client *clp = state->owner->so_client;
|
||||
struct nfs_client *clp = state->owner->so_client;
|
||||
unsigned char fl_flags = request->fl_flags;
|
||||
int status;
|
||||
|
||||
@ -3715,7 +3721,7 @@ static struct inode_operations nfs4_file_inode_operations = {
|
||||
.listxattr = nfs4_listxattr,
|
||||
};
|
||||
|
||||
struct nfs_rpc_ops nfs_v4_clientops = {
|
||||
const struct nfs_rpc_ops nfs_v4_clientops = {
|
||||
.version = 4, /* protocol version */
|
||||
.dentry_ops = &nfs4_dentry_operations,
|
||||
.dir_inode_ops = &nfs4_dir_inode_operations,
|
||||
@ -3723,6 +3729,7 @@ struct nfs_rpc_ops nfs_v4_clientops = {
|
||||
.getroot = nfs4_proc_get_root,
|
||||
.getattr = nfs4_proc_getattr,
|
||||
.setattr = nfs4_proc_setattr,
|
||||
.lookupfh = nfs4_proc_lookupfh,
|
||||
.lookup = nfs4_proc_lookup,
|
||||
.access = nfs4_proc_access,
|
||||
.readlink = nfs4_proc_readlink,
|
||||
@ -3743,6 +3750,7 @@ struct nfs_rpc_ops nfs_v4_clientops = {
|
||||
.statfs = nfs4_proc_statfs,
|
||||
.fsinfo = nfs4_proc_fsinfo,
|
||||
.pathconf = nfs4_proc_pathconf,
|
||||
.set_capabilities = nfs4_server_capabilities,
|
||||
.decode_dirent = nfs4_decode_dirent,
|
||||
.read_setup = nfs4_proc_read_setup,
|
||||
.read_done = nfs4_read_done,
|
||||
|
@ -61,7 +61,7 @@
|
||||
void
|
||||
nfs4_renew_state(void *data)
|
||||
{
|
||||
struct nfs4_client *clp = (struct nfs4_client *)data;
|
||||
struct nfs_client *clp = (struct nfs_client *)data;
|
||||
struct rpc_cred *cred;
|
||||
long lease, timeout;
|
||||
unsigned long last, now;
|
||||
@ -108,7 +108,7 @@ out:
|
||||
|
||||
/* Must be called with clp->cl_sem locked for writes */
|
||||
void
|
||||
nfs4_schedule_state_renewal(struct nfs4_client *clp)
|
||||
nfs4_schedule_state_renewal(struct nfs_client *clp)
|
||||
{
|
||||
long timeout;
|
||||
|
||||
@ -121,32 +121,20 @@ nfs4_schedule_state_renewal(struct nfs4_client *clp)
|
||||
__FUNCTION__, (timeout + HZ - 1) / HZ);
|
||||
cancel_delayed_work(&clp->cl_renewd);
|
||||
schedule_delayed_work(&clp->cl_renewd, timeout);
|
||||
set_bit(NFS_CS_RENEWD, &clp->cl_res_state);
|
||||
spin_unlock(&clp->cl_lock);
|
||||
}
|
||||
|
||||
void
|
||||
nfs4_renewd_prepare_shutdown(struct nfs_server *server)
|
||||
{
|
||||
struct nfs4_client *clp = server->nfs4_state;
|
||||
|
||||
if (!clp)
|
||||
return;
|
||||
flush_scheduled_work();
|
||||
down_write(&clp->cl_sem);
|
||||
if (!list_empty(&server->nfs4_siblings))
|
||||
list_del_init(&server->nfs4_siblings);
|
||||
up_write(&clp->cl_sem);
|
||||
}
|
||||
|
||||
/* Must be called with clp->cl_sem locked for writes */
|
||||
void
|
||||
nfs4_kill_renewd(struct nfs4_client *clp)
|
||||
nfs4_kill_renewd(struct nfs_client *clp)
|
||||
{
|
||||
down_read(&clp->cl_sem);
|
||||
if (!list_empty(&clp->cl_superblocks)) {
|
||||
up_read(&clp->cl_sem);
|
||||
return;
|
||||
}
|
||||
cancel_delayed_work(&clp->cl_renewd);
|
||||
up_read(&clp->cl_sem);
|
||||
flush_scheduled_work();
|
||||
|
@ -50,149 +50,15 @@
|
||||
#include "nfs4_fs.h"
|
||||
#include "callback.h"
|
||||
#include "delegation.h"
|
||||
#include "internal.h"
|
||||
|
||||
#define OPENOWNER_POOL_SIZE 8
|
||||
|
||||
const nfs4_stateid zero_stateid;
|
||||
|
||||
static DEFINE_SPINLOCK(state_spinlock);
|
||||
static LIST_HEAD(nfs4_clientid_list);
|
||||
|
||||
void
|
||||
init_nfsv4_state(struct nfs_server *server)
|
||||
{
|
||||
server->nfs4_state = NULL;
|
||||
INIT_LIST_HEAD(&server->nfs4_siblings);
|
||||
}
|
||||
|
||||
void
|
||||
destroy_nfsv4_state(struct nfs_server *server)
|
||||
{
|
||||
kfree(server->mnt_path);
|
||||
server->mnt_path = NULL;
|
||||
if (server->nfs4_state) {
|
||||
nfs4_put_client(server->nfs4_state);
|
||||
server->nfs4_state = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* nfs4_get_client(): returns an empty client structure
|
||||
* nfs4_put_client(): drops reference to client structure
|
||||
*
|
||||
* Since these are allocated/deallocated very rarely, we don't
|
||||
* bother putting them in a slab cache...
|
||||
*/
|
||||
static struct nfs4_client *
|
||||
nfs4_alloc_client(struct in_addr *addr)
|
||||
{
|
||||
struct nfs4_client *clp;
|
||||
|
||||
if (nfs_callback_up() < 0)
|
||||
return NULL;
|
||||
if ((clp = kzalloc(sizeof(*clp), GFP_KERNEL)) == NULL) {
|
||||
nfs_callback_down();
|
||||
return NULL;
|
||||
}
|
||||
memcpy(&clp->cl_addr, addr, sizeof(clp->cl_addr));
|
||||
init_rwsem(&clp->cl_sem);
|
||||
INIT_LIST_HEAD(&clp->cl_delegations);
|
||||
INIT_LIST_HEAD(&clp->cl_state_owners);
|
||||
INIT_LIST_HEAD(&clp->cl_unused);
|
||||
spin_lock_init(&clp->cl_lock);
|
||||
atomic_set(&clp->cl_count, 1);
|
||||
INIT_WORK(&clp->cl_renewd, nfs4_renew_state, clp);
|
||||
INIT_LIST_HEAD(&clp->cl_superblocks);
|
||||
rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS4 client");
|
||||
clp->cl_rpcclient = ERR_PTR(-EINVAL);
|
||||
clp->cl_boot_time = CURRENT_TIME;
|
||||
clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED;
|
||||
return clp;
|
||||
}
|
||||
|
||||
static void
|
||||
nfs4_free_client(struct nfs4_client *clp)
|
||||
{
|
||||
struct nfs4_state_owner *sp;
|
||||
|
||||
while (!list_empty(&clp->cl_unused)) {
|
||||
sp = list_entry(clp->cl_unused.next,
|
||||
struct nfs4_state_owner,
|
||||
so_list);
|
||||
list_del(&sp->so_list);
|
||||
kfree(sp);
|
||||
}
|
||||
BUG_ON(!list_empty(&clp->cl_state_owners));
|
||||
nfs_idmap_delete(clp);
|
||||
if (!IS_ERR(clp->cl_rpcclient))
|
||||
rpc_shutdown_client(clp->cl_rpcclient);
|
||||
kfree(clp);
|
||||
nfs_callback_down();
|
||||
}
|
||||
|
||||
static struct nfs4_client *__nfs4_find_client(struct in_addr *addr)
|
||||
{
|
||||
struct nfs4_client *clp;
|
||||
list_for_each_entry(clp, &nfs4_clientid_list, cl_servers) {
|
||||
if (memcmp(&clp->cl_addr, addr, sizeof(clp->cl_addr)) == 0) {
|
||||
atomic_inc(&clp->cl_count);
|
||||
return clp;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct nfs4_client *nfs4_find_client(struct in_addr *addr)
|
||||
{
|
||||
struct nfs4_client *clp;
|
||||
spin_lock(&state_spinlock);
|
||||
clp = __nfs4_find_client(addr);
|
||||
spin_unlock(&state_spinlock);
|
||||
return clp;
|
||||
}
|
||||
|
||||
struct nfs4_client *
|
||||
nfs4_get_client(struct in_addr *addr)
|
||||
{
|
||||
struct nfs4_client *clp, *new = NULL;
|
||||
|
||||
spin_lock(&state_spinlock);
|
||||
for (;;) {
|
||||
clp = __nfs4_find_client(addr);
|
||||
if (clp != NULL)
|
||||
break;
|
||||
clp = new;
|
||||
if (clp != NULL) {
|
||||
list_add(&clp->cl_servers, &nfs4_clientid_list);
|
||||
new = NULL;
|
||||
break;
|
||||
}
|
||||
spin_unlock(&state_spinlock);
|
||||
new = nfs4_alloc_client(addr);
|
||||
spin_lock(&state_spinlock);
|
||||
if (new == NULL)
|
||||
break;
|
||||
}
|
||||
spin_unlock(&state_spinlock);
|
||||
if (new)
|
||||
nfs4_free_client(new);
|
||||
return clp;
|
||||
}
|
||||
|
||||
void
|
||||
nfs4_put_client(struct nfs4_client *clp)
|
||||
{
|
||||
if (!atomic_dec_and_lock(&clp->cl_count, &state_spinlock))
|
||||
return;
|
||||
list_del(&clp->cl_servers);
|
||||
spin_unlock(&state_spinlock);
|
||||
BUG_ON(!list_empty(&clp->cl_superblocks));
|
||||
rpc_wake_up(&clp->cl_rpcwaitq);
|
||||
nfs4_kill_renewd(clp);
|
||||
nfs4_free_client(clp);
|
||||
}
|
||||
|
||||
static int nfs4_init_client(struct nfs4_client *clp, struct rpc_cred *cred)
|
||||
static int nfs4_init_client(struct nfs_client *clp, struct rpc_cred *cred)
|
||||
{
|
||||
int status = nfs4_proc_setclientid(clp, NFS4_CALLBACK,
|
||||
nfs_callback_tcpport, cred);
|
||||
@ -204,13 +70,13 @@ static int nfs4_init_client(struct nfs4_client *clp, struct rpc_cred *cred)
|
||||
}
|
||||
|
||||
u32
|
||||
nfs4_alloc_lockowner_id(struct nfs4_client *clp)
|
||||
nfs4_alloc_lockowner_id(struct nfs_client *clp)
|
||||
{
|
||||
return clp->cl_lockowner_id ++;
|
||||
}
|
||||
|
||||
static struct nfs4_state_owner *
|
||||
nfs4_client_grab_unused(struct nfs4_client *clp, struct rpc_cred *cred)
|
||||
nfs4_client_grab_unused(struct nfs_client *clp, struct rpc_cred *cred)
|
||||
{
|
||||
struct nfs4_state_owner *sp = NULL;
|
||||
|
||||
@ -224,7 +90,7 @@ nfs4_client_grab_unused(struct nfs4_client *clp, struct rpc_cred *cred)
|
||||
return sp;
|
||||
}
|
||||
|
||||
struct rpc_cred *nfs4_get_renew_cred(struct nfs4_client *clp)
|
||||
struct rpc_cred *nfs4_get_renew_cred(struct nfs_client *clp)
|
||||
{
|
||||
struct nfs4_state_owner *sp;
|
||||
struct rpc_cred *cred = NULL;
|
||||
@ -238,7 +104,7 @@ struct rpc_cred *nfs4_get_renew_cred(struct nfs4_client *clp)
|
||||
return cred;
|
||||
}
|
||||
|
||||
struct rpc_cred *nfs4_get_setclientid_cred(struct nfs4_client *clp)
|
||||
struct rpc_cred *nfs4_get_setclientid_cred(struct nfs_client *clp)
|
||||
{
|
||||
struct nfs4_state_owner *sp;
|
||||
|
||||
@ -251,7 +117,7 @@ struct rpc_cred *nfs4_get_setclientid_cred(struct nfs4_client *clp)
|
||||
}
|
||||
|
||||
static struct nfs4_state_owner *
|
||||
nfs4_find_state_owner(struct nfs4_client *clp, struct rpc_cred *cred)
|
||||
nfs4_find_state_owner(struct nfs_client *clp, struct rpc_cred *cred)
|
||||
{
|
||||
struct nfs4_state_owner *sp, *res = NULL;
|
||||
|
||||
@ -294,7 +160,7 @@ nfs4_alloc_state_owner(void)
|
||||
void
|
||||
nfs4_drop_state_owner(struct nfs4_state_owner *sp)
|
||||
{
|
||||
struct nfs4_client *clp = sp->so_client;
|
||||
struct nfs_client *clp = sp->so_client;
|
||||
spin_lock(&clp->cl_lock);
|
||||
list_del_init(&sp->so_list);
|
||||
spin_unlock(&clp->cl_lock);
|
||||
@ -306,7 +172,7 @@ nfs4_drop_state_owner(struct nfs4_state_owner *sp)
|
||||
*/
|
||||
struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, struct rpc_cred *cred)
|
||||
{
|
||||
struct nfs4_client *clp = server->nfs4_state;
|
||||
struct nfs_client *clp = server->nfs_client;
|
||||
struct nfs4_state_owner *sp, *new;
|
||||
|
||||
get_rpccred(cred);
|
||||
@ -337,7 +203,7 @@ struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, struct
|
||||
*/
|
||||
void nfs4_put_state_owner(struct nfs4_state_owner *sp)
|
||||
{
|
||||
struct nfs4_client *clp = sp->so_client;
|
||||
struct nfs_client *clp = sp->so_client;
|
||||
struct rpc_cred *cred = sp->so_cred;
|
||||
|
||||
if (!atomic_dec_and_lock(&sp->so_count, &clp->cl_lock))
|
||||
@ -540,7 +406,7 @@ __nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t fl_owner)
|
||||
static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, fl_owner_t fl_owner)
|
||||
{
|
||||
struct nfs4_lock_state *lsp;
|
||||
struct nfs4_client *clp = state->owner->so_client;
|
||||
struct nfs_client *clp = state->owner->so_client;
|
||||
|
||||
lsp = kzalloc(sizeof(*lsp), GFP_KERNEL);
|
||||
if (lsp == NULL)
|
||||
@ -752,7 +618,7 @@ out:
|
||||
|
||||
static int reclaimer(void *);
|
||||
|
||||
static inline void nfs4_clear_recover_bit(struct nfs4_client *clp)
|
||||
static inline void nfs4_clear_recover_bit(struct nfs_client *clp)
|
||||
{
|
||||
smp_mb__before_clear_bit();
|
||||
clear_bit(NFS4CLNT_STATE_RECOVER, &clp->cl_state);
|
||||
@ -764,25 +630,25 @@ static inline void nfs4_clear_recover_bit(struct nfs4_client *clp)
|
||||
/*
|
||||
* State recovery routine
|
||||
*/
|
||||
static void nfs4_recover_state(struct nfs4_client *clp)
|
||||
static void nfs4_recover_state(struct nfs_client *clp)
|
||||
{
|
||||
struct task_struct *task;
|
||||
|
||||
__module_get(THIS_MODULE);
|
||||
atomic_inc(&clp->cl_count);
|
||||
task = kthread_run(reclaimer, clp, "%u.%u.%u.%u-reclaim",
|
||||
NIPQUAD(clp->cl_addr));
|
||||
NIPQUAD(clp->cl_addr.sin_addr));
|
||||
if (!IS_ERR(task))
|
||||
return;
|
||||
nfs4_clear_recover_bit(clp);
|
||||
nfs4_put_client(clp);
|
||||
nfs_put_client(clp);
|
||||
module_put(THIS_MODULE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Schedule a state recovery attempt
|
||||
*/
|
||||
void nfs4_schedule_state_recovery(struct nfs4_client *clp)
|
||||
void nfs4_schedule_state_recovery(struct nfs_client *clp)
|
||||
{
|
||||
if (!clp)
|
||||
return;
|
||||
@ -879,7 +745,7 @@ out_err:
|
||||
return status;
|
||||
}
|
||||
|
||||
static void nfs4_state_mark_reclaim(struct nfs4_client *clp)
|
||||
static void nfs4_state_mark_reclaim(struct nfs_client *clp)
|
||||
{
|
||||
struct nfs4_state_owner *sp;
|
||||
struct nfs4_state *state;
|
||||
@ -903,7 +769,7 @@ static void nfs4_state_mark_reclaim(struct nfs4_client *clp)
|
||||
|
||||
static int reclaimer(void *ptr)
|
||||
{
|
||||
struct nfs4_client *clp = ptr;
|
||||
struct nfs_client *clp = ptr;
|
||||
struct nfs4_state_owner *sp;
|
||||
struct nfs4_state_recovery_ops *ops;
|
||||
struct rpc_cred *cred;
|
||||
@ -970,12 +836,12 @@ out:
|
||||
if (status == -NFS4ERR_CB_PATH_DOWN)
|
||||
nfs_handle_cb_pathdown(clp);
|
||||
nfs4_clear_recover_bit(clp);
|
||||
nfs4_put_client(clp);
|
||||
nfs_put_client(clp);
|
||||
module_put_and_exit(0);
|
||||
return 0;
|
||||
out_error:
|
||||
printk(KERN_WARNING "Error: state recovery failed on NFSv4 server %u.%u.%u.%u with error %d\n",
|
||||
NIPQUAD(clp->cl_addr.s_addr), -status);
|
||||
NIPQUAD(clp->cl_addr.sin_addr), -status);
|
||||
set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
|
||||
goto out;
|
||||
}
|
||||
|
@ -58,7 +58,7 @@
|
||||
/* Mapping from NFS error code to "errno" error code. */
|
||||
#define errno_NFSERR_IO EIO
|
||||
|
||||
static int nfs_stat_to_errno(int);
|
||||
static int nfs4_stat_to_errno(int);
|
||||
|
||||
/* NFSv4 COMPOUND tags are only wanted for debugging purposes */
|
||||
#ifdef DEBUG
|
||||
@ -128,7 +128,7 @@ static int nfs_stat_to_errno(int);
|
||||
#define decode_link_maxsz (op_decode_hdr_maxsz + 5)
|
||||
#define encode_symlink_maxsz (op_encode_hdr_maxsz + \
|
||||
1 + nfs4_name_maxsz + \
|
||||
nfs4_path_maxsz + \
|
||||
1 + \
|
||||
nfs4_fattr_maxsz)
|
||||
#define decode_symlink_maxsz (op_decode_hdr_maxsz + 8)
|
||||
#define encode_create_maxsz (op_encode_hdr_maxsz + \
|
||||
@ -529,7 +529,7 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s
|
||||
if (iap->ia_valid & ATTR_MODE)
|
||||
len += 4;
|
||||
if (iap->ia_valid & ATTR_UID) {
|
||||
owner_namelen = nfs_map_uid_to_name(server->nfs4_state, iap->ia_uid, owner_name);
|
||||
owner_namelen = nfs_map_uid_to_name(server->nfs_client, iap->ia_uid, owner_name);
|
||||
if (owner_namelen < 0) {
|
||||
printk(KERN_WARNING "nfs: couldn't resolve uid %d to string\n",
|
||||
iap->ia_uid);
|
||||
@ -541,7 +541,7 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s
|
||||
len += 4 + (XDR_QUADLEN(owner_namelen) << 2);
|
||||
}
|
||||
if (iap->ia_valid & ATTR_GID) {
|
||||
owner_grouplen = nfs_map_gid_to_group(server->nfs4_state, iap->ia_gid, owner_group);
|
||||
owner_grouplen = nfs_map_gid_to_group(server->nfs_client, iap->ia_gid, owner_group);
|
||||
if (owner_grouplen < 0) {
|
||||
printk(KERN_WARNING "nfs4: couldn't resolve gid %d to string\n",
|
||||
iap->ia_gid);
|
||||
@ -673,9 +673,9 @@ static int encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *c
|
||||
|
||||
switch (create->ftype) {
|
||||
case NF4LNK:
|
||||
RESERVE_SPACE(4 + create->u.symlink->len);
|
||||
WRITE32(create->u.symlink->len);
|
||||
WRITEMEM(create->u.symlink->name, create->u.symlink->len);
|
||||
RESERVE_SPACE(4);
|
||||
WRITE32(create->u.symlink.len);
|
||||
xdr_write_pages(xdr, create->u.symlink.pages, 0, create->u.symlink.len);
|
||||
break;
|
||||
|
||||
case NF4BLK: case NF4CHR:
|
||||
@ -1160,7 +1160,7 @@ static int encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, con
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int encode_renew(struct xdr_stream *xdr, const struct nfs4_client *client_stateid)
|
||||
static int encode_renew(struct xdr_stream *xdr, const struct nfs_client *client_stateid)
|
||||
{
|
||||
uint32_t *p;
|
||||
|
||||
@ -1246,7 +1246,7 @@ static int encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclien
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs4_client *client_state)
|
||||
static int encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs_client *client_state)
|
||||
{
|
||||
uint32_t *p;
|
||||
|
||||
@ -1945,7 +1945,7 @@ static int nfs4_xdr_enc_server_caps(struct rpc_rqst *req, uint32_t *p, const str
|
||||
/*
|
||||
* a RENEW request
|
||||
*/
|
||||
static int nfs4_xdr_enc_renew(struct rpc_rqst *req, uint32_t *p, struct nfs4_client *clp)
|
||||
static int nfs4_xdr_enc_renew(struct rpc_rqst *req, uint32_t *p, struct nfs_client *clp)
|
||||
{
|
||||
struct xdr_stream xdr;
|
||||
struct compound_hdr hdr = {
|
||||
@ -1975,7 +1975,7 @@ static int nfs4_xdr_enc_setclientid(struct rpc_rqst *req, uint32_t *p, struct nf
|
||||
/*
|
||||
* a SETCLIENTID_CONFIRM request
|
||||
*/
|
||||
static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, struct nfs4_client *clp)
|
||||
static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, struct nfs_client *clp)
|
||||
{
|
||||
struct xdr_stream xdr;
|
||||
struct compound_hdr hdr = {
|
||||
@ -2127,12 +2127,12 @@ static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected)
|
||||
}
|
||||
READ32(nfserr);
|
||||
if (nfserr != NFS_OK)
|
||||
return -nfs_stat_to_errno(nfserr);
|
||||
return -nfs4_stat_to_errno(nfserr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Dummy routine */
|
||||
static int decode_ace(struct xdr_stream *xdr, void *ace, struct nfs4_client *clp)
|
||||
static int decode_ace(struct xdr_stream *xdr, void *ace, struct nfs_client *clp)
|
||||
{
|
||||
uint32_t *p;
|
||||
unsigned int strlen;
|
||||
@ -2636,7 +2636,7 @@ static int decode_attr_nlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs4_client *clp, int32_t *uid)
|
||||
static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_client *clp, int32_t *uid)
|
||||
{
|
||||
uint32_t len, *p;
|
||||
|
||||
@ -2660,7 +2660,7 @@ static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nf
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs4_client *clp, int32_t *gid)
|
||||
static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_client *clp, int32_t *gid)
|
||||
{
|
||||
uint32_t len, *p;
|
||||
|
||||
@ -3051,9 +3051,9 @@ static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, cons
|
||||
fattr->mode |= fmode;
|
||||
if ((status = decode_attr_nlink(xdr, bitmap, &fattr->nlink)) != 0)
|
||||
goto xdr_error;
|
||||
if ((status = decode_attr_owner(xdr, bitmap, server->nfs4_state, &fattr->uid)) != 0)
|
||||
if ((status = decode_attr_owner(xdr, bitmap, server->nfs_client, &fattr->uid)) != 0)
|
||||
goto xdr_error;
|
||||
if ((status = decode_attr_group(xdr, bitmap, server->nfs4_state, &fattr->gid)) != 0)
|
||||
if ((status = decode_attr_group(xdr, bitmap, server->nfs_client, &fattr->gid)) != 0)
|
||||
goto xdr_error;
|
||||
if ((status = decode_attr_rdev(xdr, bitmap, &fattr->rdev)) != 0)
|
||||
goto xdr_error;
|
||||
@ -3254,7 +3254,7 @@ static int decode_delegation(struct xdr_stream *xdr, struct nfs_openres *res)
|
||||
if (decode_space_limit(xdr, &res->maxsize) < 0)
|
||||
return -EIO;
|
||||
}
|
||||
return decode_ace(xdr, NULL, res->server->nfs4_state);
|
||||
return decode_ace(xdr, NULL, res->server->nfs_client);
|
||||
}
|
||||
|
||||
static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res)
|
||||
@ -3565,7 +3565,7 @@ static int decode_setattr(struct xdr_stream *xdr, struct nfs_setattrres *res)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int decode_setclientid(struct xdr_stream *xdr, struct nfs4_client *clp)
|
||||
static int decode_setclientid(struct xdr_stream *xdr, struct nfs_client *clp)
|
||||
{
|
||||
uint32_t *p;
|
||||
uint32_t opnum;
|
||||
@ -3598,7 +3598,7 @@ static int decode_setclientid(struct xdr_stream *xdr, struct nfs4_client *clp)
|
||||
READ_BUF(len);
|
||||
return -NFSERR_CLID_INUSE;
|
||||
} else
|
||||
return -nfs_stat_to_errno(nfserr);
|
||||
return -nfs4_stat_to_errno(nfserr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -4256,7 +4256,7 @@ static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, uint32_t *p, struct nfs_fsi
|
||||
if (!status)
|
||||
status = decode_fsinfo(&xdr, fsinfo);
|
||||
if (!status)
|
||||
status = -nfs_stat_to_errno(hdr.status);
|
||||
status = -nfs4_stat_to_errno(hdr.status);
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -4335,7 +4335,7 @@ static int nfs4_xdr_dec_renew(struct rpc_rqst *rqstp, uint32_t *p, void *dummy)
|
||||
* a SETCLIENTID request
|
||||
*/
|
||||
static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, uint32_t *p,
|
||||
struct nfs4_client *clp)
|
||||
struct nfs_client *clp)
|
||||
{
|
||||
struct xdr_stream xdr;
|
||||
struct compound_hdr hdr;
|
||||
@ -4346,7 +4346,7 @@ static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, uint32_t *p,
|
||||
if (!status)
|
||||
status = decode_setclientid(&xdr, clp);
|
||||
if (!status)
|
||||
status = -nfs_stat_to_errno(hdr.status);
|
||||
status = -nfs4_stat_to_errno(hdr.status);
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -4368,7 +4368,7 @@ static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, s
|
||||
if (!status)
|
||||
status = decode_fsinfo(&xdr, fsinfo);
|
||||
if (!status)
|
||||
status = -nfs_stat_to_errno(hdr.status);
|
||||
status = -nfs4_stat_to_errno(hdr.status);
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -4521,7 +4521,7 @@ static struct {
|
||||
* This one is used jointly by NFSv2 and NFSv3.
|
||||
*/
|
||||
static int
|
||||
nfs_stat_to_errno(int stat)
|
||||
nfs4_stat_to_errno(int stat)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; nfs_errtbl[i].stat != -1; i++) {
|
||||
|
@ -66,14 +66,14 @@ nfs_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
|
||||
|
||||
dprintk("%s: call getattr\n", __FUNCTION__);
|
||||
nfs_fattr_init(fattr);
|
||||
status = rpc_call_sync(server->client_sys, &msg, 0);
|
||||
status = rpc_call_sync(server->nfs_client->cl_rpcclient, &msg, 0);
|
||||
dprintk("%s: reply getattr: %d\n", __FUNCTION__, status);
|
||||
if (status)
|
||||
return status;
|
||||
dprintk("%s: call statfs\n", __FUNCTION__);
|
||||
msg.rpc_proc = &nfs_procedures[NFSPROC_STATFS];
|
||||
msg.rpc_resp = &fsinfo;
|
||||
status = rpc_call_sync(server->client_sys, &msg, 0);
|
||||
status = rpc_call_sync(server->nfs_client->cl_rpcclient, &msg, 0);
|
||||
dprintk("%s: reply statfs: %d\n", __FUNCTION__, status);
|
||||
if (status)
|
||||
return status;
|
||||
@ -425,16 +425,17 @@ nfs_proc_link(struct inode *inode, struct inode *dir, struct qstr *name)
|
||||
}
|
||||
|
||||
static int
|
||||
nfs_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path,
|
||||
struct iattr *sattr, struct nfs_fh *fhandle,
|
||||
struct nfs_fattr *fattr)
|
||||
nfs_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page,
|
||||
unsigned int len, struct iattr *sattr)
|
||||
{
|
||||
struct nfs_fh fhandle;
|
||||
struct nfs_fattr fattr;
|
||||
struct nfs_symlinkargs arg = {
|
||||
.fromfh = NFS_FH(dir),
|
||||
.fromname = name->name,
|
||||
.fromlen = name->len,
|
||||
.topath = path->name,
|
||||
.tolen = path->len,
|
||||
.fromname = dentry->d_name.name,
|
||||
.fromlen = dentry->d_name.len,
|
||||
.pages = &page,
|
||||
.pathlen = len,
|
||||
.sattr = sattr
|
||||
};
|
||||
struct rpc_message msg = {
|
||||
@ -443,13 +444,25 @@ nfs_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path,
|
||||
};
|
||||
int status;
|
||||
|
||||
if (path->len > NFS2_MAXPATHLEN)
|
||||
if (len > NFS2_MAXPATHLEN)
|
||||
return -ENAMETOOLONG;
|
||||
dprintk("NFS call symlink %s -> %s\n", name->name, path->name);
|
||||
nfs_fattr_init(fattr);
|
||||
fhandle->size = 0;
|
||||
|
||||
dprintk("NFS call symlink %s\n", dentry->d_name.name);
|
||||
|
||||
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
|
||||
nfs_mark_for_revalidate(dir);
|
||||
|
||||
/*
|
||||
* V2 SYMLINK requests don't return any attributes. Setting the
|
||||
* filehandle size to zero indicates to nfs_instantiate that it
|
||||
* should fill in the data with a LOOKUP call on the wire.
|
||||
*/
|
||||
if (status == 0) {
|
||||
nfs_fattr_init(&fattr);
|
||||
fhandle.size = 0;
|
||||
status = nfs_instantiate(dentry, &fhandle, &fattr);
|
||||
}
|
||||
|
||||
dprintk("NFS reply symlink: %d\n", status);
|
||||
return status;
|
||||
}
|
||||
@ -671,7 +684,7 @@ nfs_proc_lock(struct file *filp, int cmd, struct file_lock *fl)
|
||||
}
|
||||
|
||||
|
||||
struct nfs_rpc_ops nfs_v2_clientops = {
|
||||
const struct nfs_rpc_ops nfs_v2_clientops = {
|
||||
.version = 2, /* protocol version */
|
||||
.dentry_ops = &nfs_dentry_operations,
|
||||
.dir_inode_ops = &nfs_dir_inode_operations,
|
||||
|
@ -171,7 +171,7 @@ static int nfs_readpage_sync(struct nfs_open_context *ctx, struct inode *inode,
|
||||
rdata->args.offset = page_offset(page) + rdata->args.pgbase;
|
||||
|
||||
dprintk("NFS: nfs_proc_read(%s, (%s/%Ld), %Lu, %u)\n",
|
||||
NFS_SERVER(inode)->hostname,
|
||||
NFS_SERVER(inode)->nfs_client->cl_hostname,
|
||||
inode->i_sb->s_id,
|
||||
(long long)NFS_FILEID(inode),
|
||||
(unsigned long long)rdata->args.pgbase,
|
||||
@ -568,8 +568,13 @@ int nfs_readpage_result(struct rpc_task *task, struct nfs_read_data *data)
|
||||
|
||||
nfs_add_stats(data->inode, NFSIOS_SERVERREADBYTES, resp->count);
|
||||
|
||||
/* Is this a short read? */
|
||||
if (task->tk_status >= 0 && resp->count < argp->count && !resp->eof) {
|
||||
if (task->tk_status < 0) {
|
||||
if (task->tk_status == -ESTALE) {
|
||||
set_bit(NFS_INO_STALE, &NFS_FLAGS(data->inode));
|
||||
nfs_mark_for_revalidate(data->inode);
|
||||
}
|
||||
} else if (resp->count < argp->count && !resp->eof) {
|
||||
/* This is a short read! */
|
||||
nfs_inc_stats(data->inode, NFSIOS_SHORTREAD);
|
||||
/* Has the server at least made some progress? */
|
||||
if (resp->count != 0) {
|
||||
@ -616,6 +621,10 @@ int nfs_readpage(struct file *file, struct page *page)
|
||||
if (error)
|
||||
goto out_error;
|
||||
|
||||
error = -ESTALE;
|
||||
if (NFS_STALE(inode))
|
||||
goto out_error;
|
||||
|
||||
if (file == NULL) {
|
||||
ctx = nfs_find_open_context(inode, NULL, FMODE_READ);
|
||||
if (ctx == NULL)
|
||||
@ -678,7 +687,7 @@ int nfs_readpages(struct file *filp, struct address_space *mapping,
|
||||
};
|
||||
struct inode *inode = mapping->host;
|
||||
struct nfs_server *server = NFS_SERVER(inode);
|
||||
int ret;
|
||||
int ret = -ESTALE;
|
||||
|
||||
dprintk("NFS: nfs_readpages (%s/%Ld %d)\n",
|
||||
inode->i_sb->s_id,
|
||||
@ -686,6 +695,9 @@ int nfs_readpages(struct file *filp, struct address_space *mapping,
|
||||
nr_pages);
|
||||
nfs_inc_stats(inode, NFSIOS_VFSREADPAGES);
|
||||
|
||||
if (NFS_STALE(inode))
|
||||
goto out;
|
||||
|
||||
if (filp == NULL) {
|
||||
desc.ctx = nfs_find_open_context(inode, NULL, FMODE_READ);
|
||||
if (desc.ctx == NULL)
|
||||
@ -701,6 +713,7 @@ int nfs_readpages(struct file *filp, struct address_space *mapping,
|
||||
ret = err;
|
||||
}
|
||||
put_nfs_open_context(desc.ctx);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
1499
fs/nfs/super.c
1499
fs/nfs/super.c
File diff suppressed because it is too large
Load Diff
@ -396,6 +396,7 @@ int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc)
|
||||
out:
|
||||
clear_bit(BDI_write_congested, &bdi->state);
|
||||
wake_up_all(&nfs_write_congestion);
|
||||
writeback_congestion_end();
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -1252,7 +1253,13 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data)
|
||||
dprintk("NFS: %4d nfs_writeback_done (status %d)\n",
|
||||
task->tk_pid, task->tk_status);
|
||||
|
||||
/* Call the NFS version-specific code */
|
||||
/*
|
||||
* ->write_done will attempt to use post-op attributes to detect
|
||||
* conflicting writes by other clients. A strict interpretation
|
||||
* of close-to-open would allow us to continue caching even if
|
||||
* another writer had changed the file, but some applications
|
||||
* depend on tighter cache coherency when writing.
|
||||
*/
|
||||
status = NFS_PROTO(data->inode)->write_done(task, data);
|
||||
if (status != 0)
|
||||
return status;
|
||||
@ -1273,7 +1280,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data)
|
||||
if (time_before(complain, jiffies)) {
|
||||
dprintk("NFS: faulty NFS server %s:"
|
||||
" (committed = %d) != (stable = %d)\n",
|
||||
NFS_SERVER(data->inode)->hostname,
|
||||
NFS_SERVER(data->inode)->nfs_client->cl_hostname,
|
||||
resp->verf->committed, argp->stable);
|
||||
complain = jiffies + 300 * HZ;
|
||||
}
|
||||
|
@ -375,16 +375,28 @@ nfsd4_probe_callback(struct nfs4_client *clp)
|
||||
{
|
||||
struct sockaddr_in addr;
|
||||
struct nfs4_callback *cb = &clp->cl_callback;
|
||||
struct rpc_timeout timeparms;
|
||||
struct rpc_xprt * xprt;
|
||||
struct rpc_timeout timeparms = {
|
||||
.to_initval = (NFSD_LEASE_TIME/4) * HZ,
|
||||
.to_retries = 5,
|
||||
.to_maxval = (NFSD_LEASE_TIME/2) * HZ,
|
||||
.to_exponential = 1,
|
||||
};
|
||||
struct rpc_program * program = &cb->cb_program;
|
||||
struct rpc_stat * stat = &cb->cb_stat;
|
||||
struct rpc_clnt * clnt;
|
||||
struct rpc_create_args args = {
|
||||
.protocol = IPPROTO_TCP,
|
||||
.address = (struct sockaddr *)&addr,
|
||||
.addrsize = sizeof(addr),
|
||||
.timeout = &timeparms,
|
||||
.servername = clp->cl_name.data,
|
||||
.program = program,
|
||||
.version = nfs_cb_version[1]->number,
|
||||
.authflavor = RPC_AUTH_UNIX, /* XXX: need AUTH_GSS... */
|
||||
.flags = (RPC_CLNT_CREATE_NOPING),
|
||||
};
|
||||
struct rpc_message msg = {
|
||||
.rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL],
|
||||
.rpc_argp = clp,
|
||||
};
|
||||
char hostname[32];
|
||||
int status;
|
||||
|
||||
if (atomic_read(&cb->cb_set))
|
||||
@ -396,51 +408,27 @@ nfsd4_probe_callback(struct nfs4_client *clp)
|
||||
addr.sin_port = htons(cb->cb_port);
|
||||
addr.sin_addr.s_addr = htonl(cb->cb_addr);
|
||||
|
||||
/* Initialize timeout */
|
||||
timeparms.to_initval = (NFSD_LEASE_TIME/4) * HZ;
|
||||
timeparms.to_retries = 0;
|
||||
timeparms.to_maxval = (NFSD_LEASE_TIME/2) * HZ;
|
||||
timeparms.to_exponential = 1;
|
||||
|
||||
/* Create RPC transport */
|
||||
xprt = xprt_create_proto(IPPROTO_TCP, &addr, &timeparms);
|
||||
if (IS_ERR(xprt)) {
|
||||
dprintk("NFSD: couldn't create callback transport!\n");
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
/* Initialize rpc_program */
|
||||
program->name = "nfs4_cb";
|
||||
program->number = cb->cb_prog;
|
||||
program->nrvers = ARRAY_SIZE(nfs_cb_version);
|
||||
program->version = nfs_cb_version;
|
||||
program->stats = stat;
|
||||
program->stats = &cb->cb_stat;
|
||||
|
||||
/* Initialize rpc_stat */
|
||||
memset(stat, 0, sizeof(struct rpc_stat));
|
||||
stat->program = program;
|
||||
memset(program->stats, 0, sizeof(cb->cb_stat));
|
||||
program->stats->program = program;
|
||||
|
||||
/* Create RPC client
|
||||
*
|
||||
* XXX AUTH_UNIX only - need AUTH_GSS....
|
||||
*/
|
||||
sprintf(hostname, "%u.%u.%u.%u", NIPQUAD(addr.sin_addr.s_addr));
|
||||
clnt = rpc_new_client(xprt, hostname, program, 1, RPC_AUTH_UNIX);
|
||||
if (IS_ERR(clnt)) {
|
||||
/* Create RPC client */
|
||||
cb->cb_client = rpc_create(&args);
|
||||
if (!cb->cb_client) {
|
||||
dprintk("NFSD: couldn't create callback client\n");
|
||||
goto out_err;
|
||||
}
|
||||
clnt->cl_intr = 0;
|
||||
clnt->cl_softrtry = 1;
|
||||
|
||||
/* Kick rpciod, put the call on the wire. */
|
||||
|
||||
if (rpciod_up() != 0) {
|
||||
dprintk("nfsd: couldn't start rpciod for callbacks!\n");
|
||||
if (rpciod_up() != 0)
|
||||
goto out_clnt;
|
||||
}
|
||||
|
||||
cb->cb_client = clnt;
|
||||
|
||||
/* the task holds a reference to the nfs4_client struct */
|
||||
atomic_inc(&clp->cl_count);
|
||||
@ -448,7 +436,7 @@ nfsd4_probe_callback(struct nfs4_client *clp)
|
||||
msg.rpc_cred = nfsd4_lookupcred(clp,0);
|
||||
if (IS_ERR(msg.rpc_cred))
|
||||
goto out_rpciod;
|
||||
status = rpc_call_async(clnt, &msg, RPC_TASK_ASYNC, &nfs4_cb_null_ops, NULL);
|
||||
status = rpc_call_async(cb->cb_client, &msg, RPC_TASK_ASYNC, &nfs4_cb_null_ops, NULL);
|
||||
put_rpccred(msg.rpc_cred);
|
||||
|
||||
if (status != 0) {
|
||||
@ -462,7 +450,7 @@ out_rpciod:
|
||||
rpciod_down();
|
||||
cb->cb_client = NULL;
|
||||
out_clnt:
|
||||
rpc_shutdown_client(clnt);
|
||||
rpc_shutdown_client(cb->cb_client);
|
||||
out_err:
|
||||
dprintk("NFSD: warning: no callback path to client %.*s\n",
|
||||
(int)clp->cl_name.len, clp->cl_name.data);
|
||||
|
@ -746,6 +746,7 @@ extern void blk_queue_free_tags(request_queue_t *);
|
||||
extern int blk_queue_resize_tags(request_queue_t *, int);
|
||||
extern void blk_queue_invalidate_tags(request_queue_t *);
|
||||
extern long blk_congestion_wait(int rw, long timeout);
|
||||
extern void blk_congestion_end(int rw);
|
||||
|
||||
extern void blk_rq_bio_prep(request_queue_t *, struct request *, struct bio *);
|
||||
extern int blkdev_issue_flush(struct block_device *, sector_t *);
|
||||
|
@ -221,6 +221,7 @@ static inline int dname_external(struct dentry *dentry)
|
||||
*/
|
||||
extern void d_instantiate(struct dentry *, struct inode *);
|
||||
extern struct dentry * d_instantiate_unique(struct dentry *, struct inode *);
|
||||
extern struct dentry * d_materialise_unique(struct dentry *, struct inode *);
|
||||
extern void d_delete(struct dentry *);
|
||||
|
||||
/* allocate/de-allocate */
|
||||
|
@ -42,6 +42,7 @@
|
||||
#include <linux/in.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/rbtree.h>
|
||||
#include <linux/rwsem.h>
|
||||
#include <linux/wait.h>
|
||||
|
||||
@ -69,6 +70,8 @@
|
||||
* NFSv3/v4 Access mode cache entry
|
||||
*/
|
||||
struct nfs_access_entry {
|
||||
struct rb_node rb_node;
|
||||
struct list_head lru;
|
||||
unsigned long jiffies;
|
||||
struct rpc_cred * cred;
|
||||
int mask;
|
||||
@ -145,7 +148,9 @@ struct nfs_inode {
|
||||
*/
|
||||
atomic_t data_updates;
|
||||
|
||||
struct nfs_access_entry cache_access;
|
||||
struct rb_root access_cache;
|
||||
struct list_head access_cache_entry_lru;
|
||||
struct list_head access_cache_inode_lru;
|
||||
#ifdef CONFIG_NFS_V3_ACL
|
||||
struct posix_acl *acl_access;
|
||||
struct posix_acl *acl_default;
|
||||
@ -199,6 +204,7 @@ struct nfs_inode {
|
||||
#define NFS_INO_REVALIDATING (0) /* revalidating attrs */
|
||||
#define NFS_INO_ADVISE_RDPLUS (1) /* advise readdirplus */
|
||||
#define NFS_INO_STALE (2) /* possible stale inode */
|
||||
#define NFS_INO_ACL_LRU_SET (3) /* Inode is on the LRU list */
|
||||
|
||||
static inline struct nfs_inode *NFS_I(struct inode *inode)
|
||||
{
|
||||
@ -209,8 +215,7 @@ static inline struct nfs_inode *NFS_I(struct inode *inode)
|
||||
#define NFS_FH(inode) (&NFS_I(inode)->fh)
|
||||
#define NFS_SERVER(inode) (NFS_SB(inode->i_sb))
|
||||
#define NFS_CLIENT(inode) (NFS_SERVER(inode)->client)
|
||||
#define NFS_PROTO(inode) (NFS_SERVER(inode)->rpc_ops)
|
||||
#define NFS_ADDR(inode) (RPC_PEERADDR(NFS_CLIENT(inode)))
|
||||
#define NFS_PROTO(inode) (NFS_SERVER(inode)->nfs_client->rpc_ops)
|
||||
#define NFS_COOKIEVERF(inode) (NFS_I(inode)->cookieverf)
|
||||
#define NFS_READTIME(inode) (NFS_I(inode)->read_cache_jiffies)
|
||||
#define NFS_CHANGE_ATTR(inode) (NFS_I(inode)->change_attr)
|
||||
@ -297,6 +302,7 @@ extern int nfs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
|
||||
extern int nfs_permission(struct inode *, int, struct nameidata *);
|
||||
extern int nfs_access_get_cached(struct inode *, struct rpc_cred *, struct nfs_access_entry *);
|
||||
extern void nfs_access_add_cache(struct inode *, struct nfs_access_entry *);
|
||||
extern void nfs_access_zap_cache(struct inode *inode);
|
||||
extern int nfs_open(struct inode *, struct file *);
|
||||
extern int nfs_release(struct inode *, struct file *);
|
||||
extern int nfs_attribute_timeout(struct inode *inode);
|
||||
@ -579,6 +585,7 @@ extern void * nfs_root_data(void);
|
||||
#define NFSDBG_FILE 0x0040
|
||||
#define NFSDBG_ROOT 0x0080
|
||||
#define NFSDBG_CALLBACK 0x0100
|
||||
#define NFSDBG_CLIENT 0x0200
|
||||
#define NFSDBG_ALL 0xFFFF
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
@ -6,14 +6,80 @@
|
||||
|
||||
struct nfs_iostats;
|
||||
|
||||
/*
|
||||
* The nfs_client identifies our client state to the server.
|
||||
*/
|
||||
struct nfs_client {
|
||||
atomic_t cl_count;
|
||||
int cl_cons_state; /* current construction state (-ve: init error) */
|
||||
#define NFS_CS_READY 0 /* ready to be used */
|
||||
#define NFS_CS_INITING 1 /* busy initialising */
|
||||
int cl_nfsversion; /* NFS protocol version */
|
||||
unsigned long cl_res_state; /* NFS resources state */
|
||||
#define NFS_CS_RPCIOD 0 /* - rpciod started */
|
||||
#define NFS_CS_CALLBACK 1 /* - callback started */
|
||||
#define NFS_CS_IDMAP 2 /* - idmap started */
|
||||
#define NFS_CS_RENEWD 3 /* - renewd started */
|
||||
struct sockaddr_in cl_addr; /* server identifier */
|
||||
char * cl_hostname; /* hostname of server */
|
||||
struct list_head cl_share_link; /* link in global client list */
|
||||
struct list_head cl_superblocks; /* List of nfs_server structs */
|
||||
|
||||
struct rpc_clnt * cl_rpcclient;
|
||||
const struct nfs_rpc_ops *rpc_ops; /* NFS protocol vector */
|
||||
unsigned long retrans_timeo; /* retransmit timeout */
|
||||
unsigned int retrans_count; /* number of retransmit tries */
|
||||
|
||||
#ifdef CONFIG_NFS_V4
|
||||
u64 cl_clientid; /* constant */
|
||||
nfs4_verifier cl_confirm;
|
||||
unsigned long cl_state;
|
||||
|
||||
u32 cl_lockowner_id;
|
||||
|
||||
/*
|
||||
* The following rwsem ensures exclusive access to the server
|
||||
* while we recover the state following a lease expiration.
|
||||
*/
|
||||
struct rw_semaphore cl_sem;
|
||||
|
||||
struct list_head cl_delegations;
|
||||
struct list_head cl_state_owners;
|
||||
struct list_head cl_unused;
|
||||
int cl_nunused;
|
||||
spinlock_t cl_lock;
|
||||
|
||||
unsigned long cl_lease_time;
|
||||
unsigned long cl_last_renewal;
|
||||
struct work_struct cl_renewd;
|
||||
|
||||
struct rpc_wait_queue cl_rpcwaitq;
|
||||
|
||||
/* used for the setclientid verifier */
|
||||
struct timespec cl_boot_time;
|
||||
|
||||
/* idmapper */
|
||||
struct idmap * cl_idmap;
|
||||
|
||||
/* Our own IP address, as a null-terminated string.
|
||||
* This is used to generate the clientid, and the callback address.
|
||||
*/
|
||||
char cl_ipaddr[16];
|
||||
unsigned char cl_id_uniquifier;
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
* NFS client parameters stored in the superblock.
|
||||
*/
|
||||
struct nfs_server {
|
||||
struct nfs_client * nfs_client; /* shared client and NFS4 state */
|
||||
struct list_head client_link; /* List of other nfs_server structs
|
||||
* that share the same client
|
||||
*/
|
||||
struct list_head master_link; /* link in master servers list */
|
||||
struct rpc_clnt * client; /* RPC client handle */
|
||||
struct rpc_clnt * client_sys; /* 2nd handle for FSINFO */
|
||||
struct rpc_clnt * client_acl; /* ACL RPC client handle */
|
||||
struct nfs_rpc_ops * rpc_ops; /* NFS protocol vector */
|
||||
struct nfs_iostats * io_stats; /* I/O statistics */
|
||||
struct backing_dev_info backing_dev_info;
|
||||
int flags; /* various flags */
|
||||
@ -29,24 +95,14 @@ struct nfs_server {
|
||||
unsigned int acregmax;
|
||||
unsigned int acdirmin;
|
||||
unsigned int acdirmax;
|
||||
unsigned long retrans_timeo; /* retransmit timeout */
|
||||
unsigned int retrans_count; /* number of retransmit tries */
|
||||
unsigned int namelen;
|
||||
char * hostname; /* remote hostname */
|
||||
struct nfs_fh fh;
|
||||
struct sockaddr_in addr;
|
||||
|
||||
struct nfs_fsid fsid;
|
||||
__u64 maxfilesize; /* maximum file size */
|
||||
unsigned long mount_time; /* when this fs was mounted */
|
||||
dev_t s_dev; /* superblock dev numbers */
|
||||
|
||||
#ifdef CONFIG_NFS_V4
|
||||
/* Our own IP address, as a null-terminated string.
|
||||
* This is used to generate the clientid, and the callback address.
|
||||
*/
|
||||
char ip_addr[16];
|
||||
char * mnt_path;
|
||||
struct nfs4_client * nfs4_state; /* all NFSv4 state starts here */
|
||||
struct list_head nfs4_siblings; /* List of other nfs_server structs
|
||||
* that share the same clientid
|
||||
*/
|
||||
u32 attr_bitmask[2];/* V4 bitmask representing the set
|
||||
of attributes supported on this
|
||||
filesystem */
|
||||
@ -54,6 +110,7 @@ struct nfs_server {
|
||||
that are supported on this
|
||||
filesystem */
|
||||
#endif
|
||||
void (*destroy)(struct nfs_server *);
|
||||
};
|
||||
|
||||
/* Server capabilities */
|
||||
|
@ -62,15 +62,15 @@ struct idmap_msg {
|
||||
#ifdef __KERNEL__
|
||||
|
||||
/* Forward declaration to make this header independent of others */
|
||||
struct nfs4_client;
|
||||
struct nfs_client;
|
||||
|
||||
void nfs_idmap_new(struct nfs4_client *);
|
||||
void nfs_idmap_delete(struct nfs4_client *);
|
||||
int nfs_idmap_new(struct nfs_client *);
|
||||
void nfs_idmap_delete(struct nfs_client *);
|
||||
|
||||
int nfs_map_name_to_uid(struct nfs4_client *, const char *, size_t, __u32 *);
|
||||
int nfs_map_group_to_gid(struct nfs4_client *, const char *, size_t, __u32 *);
|
||||
int nfs_map_uid_to_name(struct nfs4_client *, __u32, char *);
|
||||
int nfs_map_gid_to_group(struct nfs4_client *, __u32, char *);
|
||||
int nfs_map_name_to_uid(struct nfs_client *, const char *, size_t, __u32 *);
|
||||
int nfs_map_group_to_gid(struct nfs_client *, const char *, size_t, __u32 *);
|
||||
int nfs_map_uid_to_name(struct nfs_client *, __u32, char *);
|
||||
int nfs_map_gid_to_group(struct nfs_client *, __u32, char *);
|
||||
|
||||
extern unsigned int nfs_idmap_cache_timeout;
|
||||
#endif /* __KERNEL__ */
|
||||
|
@ -1,7 +1,6 @@
|
||||
#ifndef _LINUX_NFS_XDR_H
|
||||
#define _LINUX_NFS_XDR_H
|
||||
|
||||
#include <linux/sunrpc/xprt.h>
|
||||
#include <linux/nfsacl.h>
|
||||
|
||||
/*
|
||||
@ -359,8 +358,8 @@ struct nfs_symlinkargs {
|
||||
struct nfs_fh * fromfh;
|
||||
const char * fromname;
|
||||
unsigned int fromlen;
|
||||
const char * topath;
|
||||
unsigned int tolen;
|
||||
struct page ** pages;
|
||||
unsigned int pathlen;
|
||||
struct iattr * sattr;
|
||||
};
|
||||
|
||||
@ -435,8 +434,8 @@ struct nfs3_symlinkargs {
|
||||
struct nfs_fh * fromfh;
|
||||
const char * fromname;
|
||||
unsigned int fromlen;
|
||||
const char * topath;
|
||||
unsigned int tolen;
|
||||
struct page ** pages;
|
||||
unsigned int pathlen;
|
||||
struct iattr * sattr;
|
||||
};
|
||||
|
||||
@ -534,7 +533,10 @@ struct nfs4_accessres {
|
||||
struct nfs4_create_arg {
|
||||
u32 ftype;
|
||||
union {
|
||||
struct qstr * symlink; /* NF4LNK */
|
||||
struct {
|
||||
struct page ** pages;
|
||||
unsigned int len;
|
||||
} symlink; /* NF4LNK */
|
||||
struct {
|
||||
u32 specdata1;
|
||||
u32 specdata2;
|
||||
@ -770,6 +772,9 @@ struct nfs_rpc_ops {
|
||||
|
||||
int (*getroot) (struct nfs_server *, struct nfs_fh *,
|
||||
struct nfs_fsinfo *);
|
||||
int (*lookupfh)(struct nfs_server *, struct nfs_fh *,
|
||||
struct qstr *, struct nfs_fh *,
|
||||
struct nfs_fattr *);
|
||||
int (*getattr) (struct nfs_server *, struct nfs_fh *,
|
||||
struct nfs_fattr *);
|
||||
int (*setattr) (struct dentry *, struct nfs_fattr *,
|
||||
@ -791,9 +796,8 @@ struct nfs_rpc_ops {
|
||||
int (*rename) (struct inode *, struct qstr *,
|
||||
struct inode *, struct qstr *);
|
||||
int (*link) (struct inode *, struct inode *, struct qstr *);
|
||||
int (*symlink) (struct inode *, struct qstr *, struct qstr *,
|
||||
struct iattr *, struct nfs_fh *,
|
||||
struct nfs_fattr *);
|
||||
int (*symlink) (struct inode *, struct dentry *, struct page *,
|
||||
unsigned int, struct iattr *);
|
||||
int (*mkdir) (struct inode *, struct dentry *, struct iattr *);
|
||||
int (*rmdir) (struct inode *, struct qstr *);
|
||||
int (*readdir) (struct dentry *, struct rpc_cred *,
|
||||
@ -806,6 +810,7 @@ struct nfs_rpc_ops {
|
||||
struct nfs_fsinfo *);
|
||||
int (*pathconf) (struct nfs_server *, struct nfs_fh *,
|
||||
struct nfs_pathconf *);
|
||||
int (*set_capabilities)(struct nfs_server *, struct nfs_fh *);
|
||||
u32 * (*decode_dirent)(u32 *, struct nfs_entry *, int plus);
|
||||
void (*read_setup) (struct nfs_read_data *);
|
||||
int (*read_done) (struct rpc_task *, struct nfs_read_data *);
|
||||
@ -829,9 +834,9 @@ struct nfs_rpc_ops {
|
||||
/*
|
||||
* Function vectors etc. for the NFS client
|
||||
*/
|
||||
extern struct nfs_rpc_ops nfs_v2_clientops;
|
||||
extern struct nfs_rpc_ops nfs_v3_clientops;
|
||||
extern struct nfs_rpc_ops nfs_v4_clientops;
|
||||
extern const struct nfs_rpc_ops nfs_v2_clientops;
|
||||
extern const struct nfs_rpc_ops nfs_v3_clientops;
|
||||
extern const struct nfs_rpc_ops nfs_v4_clientops;
|
||||
extern struct rpc_version nfs_version2;
|
||||
extern struct rpc_version nfs_version3;
|
||||
extern struct rpc_version nfs_version4;
|
||||
|
@ -18,18 +18,6 @@
|
||||
#include <linux/sunrpc/timer.h>
|
||||
#include <asm/signal.h>
|
||||
|
||||
/*
|
||||
* This defines an RPC port mapping
|
||||
*/
|
||||
struct rpc_portmap {
|
||||
__u32 pm_prog;
|
||||
__u32 pm_vers;
|
||||
__u32 pm_prot;
|
||||
__u16 pm_port;
|
||||
unsigned char pm_binding : 1; /* doing a getport() */
|
||||
struct rpc_wait_queue pm_bindwait; /* waiting on getport() */
|
||||
};
|
||||
|
||||
struct rpc_inode;
|
||||
|
||||
/*
|
||||
@ -40,7 +28,9 @@ struct rpc_clnt {
|
||||
atomic_t cl_users; /* number of references */
|
||||
struct rpc_xprt * cl_xprt; /* transport */
|
||||
struct rpc_procinfo * cl_procinfo; /* procedure info */
|
||||
u32 cl_maxproc; /* max procedure number */
|
||||
u32 cl_prog, /* RPC program number */
|
||||
cl_vers, /* RPC version number */
|
||||
cl_maxproc; /* max procedure number */
|
||||
|
||||
char * cl_server; /* server machine name */
|
||||
char * cl_protname; /* protocol name */
|
||||
@ -55,7 +45,6 @@ struct rpc_clnt {
|
||||
cl_dead : 1;/* abandoned */
|
||||
|
||||
struct rpc_rtt * cl_rtt; /* RTO estimator data */
|
||||
struct rpc_portmap * cl_pmap; /* port mapping */
|
||||
|
||||
int cl_nodelen; /* nodename length */
|
||||
char cl_nodename[UNX_MAXNODENAME];
|
||||
@ -64,14 +53,8 @@ struct rpc_clnt {
|
||||
struct dentry * cl_dentry; /* inode */
|
||||
struct rpc_clnt * cl_parent; /* Points to parent of clones */
|
||||
struct rpc_rtt cl_rtt_default;
|
||||
struct rpc_portmap cl_pmap_default;
|
||||
char cl_inline_name[32];
|
||||
};
|
||||
#define cl_timeout cl_xprt->timeout
|
||||
#define cl_prog cl_pmap->pm_prog
|
||||
#define cl_vers cl_pmap->pm_vers
|
||||
#define cl_port cl_pmap->pm_port
|
||||
#define cl_prot cl_pmap->pm_prot
|
||||
|
||||
/*
|
||||
* General RPC program info
|
||||
@ -106,24 +89,36 @@ struct rpc_procinfo {
|
||||
char * p_name; /* name of procedure */
|
||||
};
|
||||
|
||||
#define RPC_CONGESTED(clnt) (RPCXPRT_CONGESTED((clnt)->cl_xprt))
|
||||
#define RPC_PEERADDR(clnt) (&(clnt)->cl_xprt->addr)
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
struct rpc_clnt *rpc_create_client(struct rpc_xprt *xprt, char *servname,
|
||||
struct rpc_program *info,
|
||||
u32 version, rpc_authflavor_t authflavor);
|
||||
struct rpc_clnt *rpc_new_client(struct rpc_xprt *xprt, char *servname,
|
||||
struct rpc_program *info,
|
||||
u32 version, rpc_authflavor_t authflavor);
|
||||
struct rpc_create_args {
|
||||
int protocol;
|
||||
struct sockaddr *address;
|
||||
size_t addrsize;
|
||||
struct rpc_timeout *timeout;
|
||||
char *servername;
|
||||
struct rpc_program *program;
|
||||
u32 version;
|
||||
rpc_authflavor_t authflavor;
|
||||
unsigned long flags;
|
||||
};
|
||||
|
||||
/* Values for "flags" field */
|
||||
#define RPC_CLNT_CREATE_HARDRTRY (1UL << 0)
|
||||
#define RPC_CLNT_CREATE_INTR (1UL << 1)
|
||||
#define RPC_CLNT_CREATE_AUTOBIND (1UL << 2)
|
||||
#define RPC_CLNT_CREATE_ONESHOT (1UL << 3)
|
||||
#define RPC_CLNT_CREATE_NONPRIVPORT (1UL << 4)
|
||||
#define RPC_CLNT_CREATE_NOPING (1UL << 5)
|
||||
|
||||
struct rpc_clnt *rpc_create(struct rpc_create_args *args);
|
||||
struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *,
|
||||
struct rpc_program *, int);
|
||||
struct rpc_clnt *rpc_clone_client(struct rpc_clnt *);
|
||||
int rpc_shutdown_client(struct rpc_clnt *);
|
||||
int rpc_destroy_client(struct rpc_clnt *);
|
||||
void rpc_release_client(struct rpc_clnt *);
|
||||
void rpc_getport(struct rpc_task *, struct rpc_clnt *);
|
||||
void rpc_getport(struct rpc_task *);
|
||||
int rpc_register(u32, u32, int, unsigned short, int *);
|
||||
|
||||
void rpc_call_setup(struct rpc_task *, struct rpc_message *, int);
|
||||
@ -140,6 +135,8 @@ void rpc_setbufsize(struct rpc_clnt *, unsigned int, unsigned int);
|
||||
size_t rpc_max_payload(struct rpc_clnt *);
|
||||
void rpc_force_rebind(struct rpc_clnt *);
|
||||
int rpc_ping(struct rpc_clnt *clnt, int flags);
|
||||
size_t rpc_peeraddr(struct rpc_clnt *, struct sockaddr *, size_t);
|
||||
char * rpc_peeraddr2str(struct rpc_clnt *, enum rpc_display_format_t);
|
||||
|
||||
/*
|
||||
* Helper function for NFSroot support
|
||||
|
@ -43,7 +43,7 @@ extern int rpc_queue_upcall(struct inode *, struct rpc_pipe_msg *);
|
||||
|
||||
extern struct dentry *rpc_mkdir(char *, struct rpc_clnt *);
|
||||
extern int rpc_rmdir(struct dentry *);
|
||||
extern struct dentry *rpc_mkpipe(char *, void *, struct rpc_pipe_ops *, int flags);
|
||||
extern struct dentry *rpc_mkpipe(struct dentry *, const char *, void *, struct rpc_pipe_ops *, int flags);
|
||||
extern int rpc_unlink(struct dentry *);
|
||||
extern struct vfsmount *rpc_get_mount(void);
|
||||
extern void rpc_put_mount(void);
|
||||
|
@ -127,7 +127,6 @@ struct rpc_call_ops {
|
||||
*/
|
||||
#define RPC_TASK_ASYNC 0x0001 /* is an async task */
|
||||
#define RPC_TASK_SWAPPER 0x0002 /* is swapping in/out */
|
||||
#define RPC_TASK_CHILD 0x0008 /* is child of other task */
|
||||
#define RPC_CALL_MAJORSEEN 0x0020 /* major timeout seen */
|
||||
#define RPC_TASK_ROOTCREDS 0x0040 /* force root creds */
|
||||
#define RPC_TASK_DYNAMIC 0x0080 /* task was kmalloc'ed */
|
||||
@ -136,7 +135,6 @@ struct rpc_call_ops {
|
||||
#define RPC_TASK_NOINTR 0x0400 /* uninterruptible task */
|
||||
|
||||
#define RPC_IS_ASYNC(t) ((t)->tk_flags & RPC_TASK_ASYNC)
|
||||
#define RPC_IS_CHILD(t) ((t)->tk_flags & RPC_TASK_CHILD)
|
||||
#define RPC_IS_SWAPPER(t) ((t)->tk_flags & RPC_TASK_SWAPPER)
|
||||
#define RPC_DO_ROOTOVERRIDE(t) ((t)->tk_flags & RPC_TASK_ROOTCREDS)
|
||||
#define RPC_ASSASSINATED(t) ((t)->tk_flags & RPC_TASK_KILLED)
|
||||
@ -253,7 +251,6 @@ struct rpc_task *rpc_new_task(struct rpc_clnt *, int flags,
|
||||
const struct rpc_call_ops *ops, void *data);
|
||||
struct rpc_task *rpc_run_task(struct rpc_clnt *clnt, int flags,
|
||||
const struct rpc_call_ops *ops, void *data);
|
||||
struct rpc_task *rpc_new_child(struct rpc_clnt *, struct rpc_task *parent);
|
||||
void rpc_init_task(struct rpc_task *task, struct rpc_clnt *clnt,
|
||||
int flags, const struct rpc_call_ops *ops,
|
||||
void *data);
|
||||
@ -261,8 +258,6 @@ void rpc_release_task(struct rpc_task *);
|
||||
void rpc_exit_task(struct rpc_task *);
|
||||
void rpc_killall_tasks(struct rpc_clnt *);
|
||||
int rpc_execute(struct rpc_task *);
|
||||
void rpc_run_child(struct rpc_task *parent, struct rpc_task *child,
|
||||
rpc_action action);
|
||||
void rpc_init_priority_wait_queue(struct rpc_wait_queue *, const char *);
|
||||
void rpc_init_wait_queue(struct rpc_wait_queue *, const char *);
|
||||
void rpc_sleep_on(struct rpc_wait_queue *, struct rpc_task *,
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <linux/uio.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/kref.h>
|
||||
#include <linux/sunrpc/sched.h>
|
||||
#include <linux/sunrpc/xdr.h>
|
||||
|
||||
@ -51,6 +52,14 @@ struct rpc_timeout {
|
||||
unsigned char to_exponential;
|
||||
};
|
||||
|
||||
enum rpc_display_format_t {
|
||||
RPC_DISPLAY_ADDR = 0,
|
||||
RPC_DISPLAY_PORT,
|
||||
RPC_DISPLAY_PROTO,
|
||||
RPC_DISPLAY_ALL,
|
||||
RPC_DISPLAY_MAX,
|
||||
};
|
||||
|
||||
struct rpc_task;
|
||||
struct rpc_xprt;
|
||||
struct seq_file;
|
||||
@ -103,8 +112,10 @@ struct rpc_rqst {
|
||||
|
||||
struct rpc_xprt_ops {
|
||||
void (*set_buffer_size)(struct rpc_xprt *xprt, size_t sndsize, size_t rcvsize);
|
||||
char * (*print_addr)(struct rpc_xprt *xprt, enum rpc_display_format_t format);
|
||||
int (*reserve_xprt)(struct rpc_task *task);
|
||||
void (*release_xprt)(struct rpc_xprt *xprt, struct rpc_task *task);
|
||||
void (*rpcbind)(struct rpc_task *task);
|
||||
void (*set_port)(struct rpc_xprt *xprt, unsigned short port);
|
||||
void (*connect)(struct rpc_task *task);
|
||||
void * (*buf_alloc)(struct rpc_task *task, size_t size);
|
||||
@ -119,12 +130,14 @@ struct rpc_xprt_ops {
|
||||
};
|
||||
|
||||
struct rpc_xprt {
|
||||
struct kref kref; /* Reference count */
|
||||
struct rpc_xprt_ops * ops; /* transport methods */
|
||||
struct socket * sock; /* BSD socket layer */
|
||||
struct sock * inet; /* INET layer */
|
||||
|
||||
struct rpc_timeout timeout; /* timeout parms */
|
||||
struct sockaddr_in addr; /* server address */
|
||||
struct sockaddr_storage addr; /* server address */
|
||||
size_t addrlen; /* size of server address */
|
||||
int prot; /* IP protocol */
|
||||
|
||||
unsigned long cong; /* current congestion */
|
||||
@ -138,6 +151,7 @@ struct rpc_xprt {
|
||||
unsigned int tsh_size; /* size of transport specific
|
||||
header */
|
||||
|
||||
struct rpc_wait_queue binding; /* requests waiting on rpcbind */
|
||||
struct rpc_wait_queue sending; /* requests waiting to send */
|
||||
struct rpc_wait_queue resend; /* requests waiting to resend */
|
||||
struct rpc_wait_queue pending; /* requests in flight */
|
||||
@ -205,6 +219,8 @@ struct rpc_xprt {
|
||||
void (*old_data_ready)(struct sock *, int);
|
||||
void (*old_state_change)(struct sock *);
|
||||
void (*old_write_space)(struct sock *);
|
||||
|
||||
char * address_strings[RPC_DISPLAY_MAX];
|
||||
};
|
||||
|
||||
#define XPRT_LAST_FRAG (1 << 0)
|
||||
@ -217,12 +233,12 @@ struct rpc_xprt {
|
||||
/*
|
||||
* Transport operations used by ULPs
|
||||
*/
|
||||
struct rpc_xprt * xprt_create_proto(int proto, struct sockaddr_in *addr, struct rpc_timeout *to);
|
||||
void xprt_set_timeout(struct rpc_timeout *to, unsigned int retr, unsigned long incr);
|
||||
|
||||
/*
|
||||
* Generic internal transport functions
|
||||
*/
|
||||
struct rpc_xprt * xprt_create_transport(int proto, struct sockaddr *addr, size_t size, struct rpc_timeout *toparms);
|
||||
void xprt_connect(struct rpc_task *task);
|
||||
void xprt_reserve(struct rpc_task *task);
|
||||
int xprt_reserve_xprt(struct rpc_task *task);
|
||||
@ -234,7 +250,8 @@ int xprt_adjust_timeout(struct rpc_rqst *req);
|
||||
void xprt_release_xprt(struct rpc_xprt *xprt, struct rpc_task *task);
|
||||
void xprt_release_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task);
|
||||
void xprt_release(struct rpc_task *task);
|
||||
int xprt_destroy(struct rpc_xprt *xprt);
|
||||
struct rpc_xprt * xprt_get(struct rpc_xprt *xprt);
|
||||
void xprt_put(struct rpc_xprt *xprt);
|
||||
|
||||
static inline u32 *xprt_skip_transport_header(struct rpc_xprt *xprt, u32 *p)
|
||||
{
|
||||
@ -269,6 +286,8 @@ int xs_setup_tcp(struct rpc_xprt *xprt, struct rpc_timeout *to);
|
||||
#define XPRT_CONNECTED (1)
|
||||
#define XPRT_CONNECTING (2)
|
||||
#define XPRT_CLOSE_WAIT (3)
|
||||
#define XPRT_BOUND (4)
|
||||
#define XPRT_BINDING (5)
|
||||
|
||||
static inline void xprt_set_connected(struct rpc_xprt *xprt)
|
||||
{
|
||||
@ -312,6 +331,33 @@ static inline int xprt_test_and_set_connecting(struct rpc_xprt *xprt)
|
||||
return test_and_set_bit(XPRT_CONNECTING, &xprt->state);
|
||||
}
|
||||
|
||||
static inline void xprt_set_bound(struct rpc_xprt *xprt)
|
||||
{
|
||||
test_and_set_bit(XPRT_BOUND, &xprt->state);
|
||||
}
|
||||
|
||||
static inline int xprt_bound(struct rpc_xprt *xprt)
|
||||
{
|
||||
return test_bit(XPRT_BOUND, &xprt->state);
|
||||
}
|
||||
|
||||
static inline void xprt_clear_bound(struct rpc_xprt *xprt)
|
||||
{
|
||||
clear_bit(XPRT_BOUND, &xprt->state);
|
||||
}
|
||||
|
||||
static inline void xprt_clear_binding(struct rpc_xprt *xprt)
|
||||
{
|
||||
smp_mb__before_clear_bit();
|
||||
clear_bit(XPRT_BINDING, &xprt->state);
|
||||
smp_mb__after_clear_bit();
|
||||
}
|
||||
|
||||
static inline int xprt_test_and_set_binding(struct rpc_xprt *xprt)
|
||||
{
|
||||
return test_and_set_bit(XPRT_BINDING, &xprt->state);
|
||||
}
|
||||
|
||||
#endif /* __KERNEL__*/
|
||||
|
||||
#endif /* _LINUX_SUNRPC_XPRT_H */
|
||||
|
@ -85,6 +85,7 @@ int wakeup_pdflush(long nr_pages);
|
||||
void laptop_io_completion(void);
|
||||
void laptop_sync_completion(void);
|
||||
void throttle_vm_writeout(void);
|
||||
void writeback_congestion_end(void);
|
||||
|
||||
/* These are exported to sysctl. */
|
||||
extern int dirty_background_ratio;
|
||||
|
@ -802,6 +802,15 @@ int test_set_page_writeback(struct page *page)
|
||||
}
|
||||
EXPORT_SYMBOL(test_set_page_writeback);
|
||||
|
||||
/*
|
||||
* Wakes up tasks that are being throttled due to writeback congestion
|
||||
*/
|
||||
void writeback_congestion_end(void)
|
||||
{
|
||||
blk_congestion_end(WRITE);
|
||||
}
|
||||
EXPORT_SYMBOL(writeback_congestion_end);
|
||||
|
||||
/*
|
||||
* Return true if any of the pages in the mapping are marged with the
|
||||
* passed tag.
|
||||
|
@ -88,7 +88,6 @@ struct gss_auth {
|
||||
struct list_head upcalls;
|
||||
struct rpc_clnt *client;
|
||||
struct dentry *dentry;
|
||||
char path[48];
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
@ -690,10 +689,8 @@ gss_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor)
|
||||
if (err)
|
||||
goto err_put_mech;
|
||||
|
||||
snprintf(gss_auth->path, sizeof(gss_auth->path), "%s/%s",
|
||||
clnt->cl_pathname,
|
||||
gss_auth->mech->gm_name);
|
||||
gss_auth->dentry = rpc_mkpipe(gss_auth->path, clnt, &gss_upcall_ops, RPC_PIPE_WAIT_FOR_OPEN);
|
||||
gss_auth->dentry = rpc_mkpipe(clnt->cl_dentry, gss_auth->mech->gm_name,
|
||||
clnt, &gss_upcall_ops, RPC_PIPE_WAIT_FOR_OPEN);
|
||||
if (IS_ERR(gss_auth->dentry)) {
|
||||
err = PTR_ERR(gss_auth->dentry);
|
||||
goto err_put_mech;
|
||||
|
@ -97,17 +97,7 @@ rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Create an RPC client
|
||||
* FIXME: This should also take a flags argument (as in task->tk_flags).
|
||||
* It's called (among others) from pmap_create_client, which may in
|
||||
* turn be called by an async task. In this case, rpciod should not be
|
||||
* made to sleep too long.
|
||||
*/
|
||||
struct rpc_clnt *
|
||||
rpc_new_client(struct rpc_xprt *xprt, char *servname,
|
||||
struct rpc_program *program, u32 vers,
|
||||
rpc_authflavor_t flavor)
|
||||
static struct rpc_clnt * rpc_new_client(struct rpc_xprt *xprt, char *servname, struct rpc_program *program, u32 vers, rpc_authflavor_t flavor)
|
||||
{
|
||||
struct rpc_version *version;
|
||||
struct rpc_clnt *clnt = NULL;
|
||||
@ -147,16 +137,12 @@ rpc_new_client(struct rpc_xprt *xprt, char *servname,
|
||||
clnt->cl_procinfo = version->procs;
|
||||
clnt->cl_maxproc = version->nrprocs;
|
||||
clnt->cl_protname = program->name;
|
||||
clnt->cl_pmap = &clnt->cl_pmap_default;
|
||||
clnt->cl_port = xprt->addr.sin_port;
|
||||
clnt->cl_prog = program->number;
|
||||
clnt->cl_vers = version->number;
|
||||
clnt->cl_prot = xprt->prot;
|
||||
clnt->cl_stats = program->stats;
|
||||
clnt->cl_metrics = rpc_alloc_iostats(clnt);
|
||||
rpc_init_wait_queue(&clnt->cl_pmap_default.pm_bindwait, "bindwait");
|
||||
|
||||
if (!clnt->cl_port)
|
||||
if (!xprt_bound(clnt->cl_xprt))
|
||||
clnt->cl_autobind = 1;
|
||||
|
||||
clnt->cl_rtt = &clnt->cl_rtt_default;
|
||||
@ -191,40 +177,71 @@ out_no_path:
|
||||
kfree(clnt->cl_server);
|
||||
kfree(clnt);
|
||||
out_err:
|
||||
xprt_destroy(xprt);
|
||||
xprt_put(xprt);
|
||||
out_no_xprt:
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an RPC client
|
||||
* @xprt - pointer to xprt struct
|
||||
* @servname - name of server
|
||||
* @info - rpc_program
|
||||
* @version - rpc_program version
|
||||
* @authflavor - rpc_auth flavour to use
|
||||
/*
|
||||
* rpc_create - create an RPC client and transport with one call
|
||||
* @args: rpc_clnt create argument structure
|
||||
*
|
||||
* Creates an RPC client structure, then pings the server in order to
|
||||
* determine if it is up, and if it supports this program and version.
|
||||
* Creates and initializes an RPC transport and an RPC client.
|
||||
*
|
||||
* This function should never be called by asynchronous tasks such as
|
||||
* the portmapper.
|
||||
* It can ping the server in order to determine if it is up, and to see if
|
||||
* it supports this program and version. RPC_CLNT_CREATE_NOPING disables
|
||||
* this behavior so asynchronous tasks can also use rpc_create.
|
||||
*/
|
||||
struct rpc_clnt *rpc_create_client(struct rpc_xprt *xprt, char *servname,
|
||||
struct rpc_program *info, u32 version, rpc_authflavor_t authflavor)
|
||||
struct rpc_clnt *rpc_create(struct rpc_create_args *args)
|
||||
{
|
||||
struct rpc_xprt *xprt;
|
||||
struct rpc_clnt *clnt;
|
||||
int err;
|
||||
|
||||
clnt = rpc_new_client(xprt, servname, info, version, authflavor);
|
||||
|
||||
xprt = xprt_create_transport(args->protocol, args->address,
|
||||
args->addrsize, args->timeout);
|
||||
if (IS_ERR(xprt))
|
||||
return (struct rpc_clnt *)xprt;
|
||||
|
||||
/*
|
||||
* By default, kernel RPC client connects from a reserved port.
|
||||
* CAP_NET_BIND_SERVICE will not be set for unprivileged requesters,
|
||||
* but it is always enabled for rpciod, which handles the connect
|
||||
* operation.
|
||||
*/
|
||||
xprt->resvport = 1;
|
||||
if (args->flags & RPC_CLNT_CREATE_NONPRIVPORT)
|
||||
xprt->resvport = 0;
|
||||
|
||||
dprintk("RPC: creating %s client for %s (xprt %p)\n",
|
||||
args->program->name, args->servername, xprt);
|
||||
|
||||
clnt = rpc_new_client(xprt, args->servername, args->program,
|
||||
args->version, args->authflavor);
|
||||
if (IS_ERR(clnt))
|
||||
return clnt;
|
||||
err = rpc_ping(clnt, RPC_TASK_SOFT|RPC_TASK_NOINTR);
|
||||
if (err == 0)
|
||||
return clnt;
|
||||
rpc_shutdown_client(clnt);
|
||||
return ERR_PTR(err);
|
||||
|
||||
if (!(args->flags & RPC_CLNT_CREATE_NOPING)) {
|
||||
int err = rpc_ping(clnt, RPC_TASK_SOFT|RPC_TASK_NOINTR);
|
||||
if (err != 0) {
|
||||
rpc_shutdown_client(clnt);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
}
|
||||
|
||||
clnt->cl_softrtry = 1;
|
||||
if (args->flags & RPC_CLNT_CREATE_HARDRTRY)
|
||||
clnt->cl_softrtry = 0;
|
||||
|
||||
if (args->flags & RPC_CLNT_CREATE_INTR)
|
||||
clnt->cl_intr = 1;
|
||||
if (args->flags & RPC_CLNT_CREATE_AUTOBIND)
|
||||
clnt->cl_autobind = 1;
|
||||
if (args->flags & RPC_CLNT_CREATE_ONESHOT)
|
||||
clnt->cl_oneshot = 1;
|
||||
|
||||
return clnt;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rpc_create);
|
||||
|
||||
/*
|
||||
* This function clones the RPC client structure. It allows us to share the
|
||||
@ -244,8 +261,7 @@ rpc_clone_client(struct rpc_clnt *clnt)
|
||||
atomic_set(&new->cl_users, 0);
|
||||
new->cl_parent = clnt;
|
||||
atomic_inc(&clnt->cl_count);
|
||||
/* Duplicate portmapper */
|
||||
rpc_init_wait_queue(&new->cl_pmap_default.pm_bindwait, "bindwait");
|
||||
new->cl_xprt = xprt_get(clnt->cl_xprt);
|
||||
/* Turn off autobind on clones */
|
||||
new->cl_autobind = 0;
|
||||
new->cl_oneshot = 0;
|
||||
@ -255,8 +271,7 @@ rpc_clone_client(struct rpc_clnt *clnt)
|
||||
rpc_init_rtt(&new->cl_rtt_default, clnt->cl_xprt->timeout.to_initval);
|
||||
if (new->cl_auth)
|
||||
atomic_inc(&new->cl_auth->au_count);
|
||||
new->cl_pmap = &new->cl_pmap_default;
|
||||
new->cl_metrics = rpc_alloc_iostats(clnt);
|
||||
new->cl_metrics = rpc_alloc_iostats(clnt);
|
||||
return new;
|
||||
out_no_clnt:
|
||||
printk(KERN_INFO "RPC: out of memory in %s\n", __FUNCTION__);
|
||||
@ -323,15 +338,12 @@ rpc_destroy_client(struct rpc_clnt *clnt)
|
||||
rpc_rmdir(clnt->cl_dentry);
|
||||
rpc_put_mount();
|
||||
}
|
||||
if (clnt->cl_xprt) {
|
||||
xprt_destroy(clnt->cl_xprt);
|
||||
clnt->cl_xprt = NULL;
|
||||
}
|
||||
if (clnt->cl_server != clnt->cl_inline_name)
|
||||
kfree(clnt->cl_server);
|
||||
out_free:
|
||||
rpc_free_iostats(clnt->cl_metrics);
|
||||
clnt->cl_metrics = NULL;
|
||||
xprt_put(clnt->cl_xprt);
|
||||
kfree(clnt);
|
||||
return 0;
|
||||
}
|
||||
@ -540,6 +552,40 @@ rpc_call_setup(struct rpc_task *task, struct rpc_message *msg, int flags)
|
||||
task->tk_action = rpc_exit_task;
|
||||
}
|
||||
|
||||
/**
|
||||
* rpc_peeraddr - extract remote peer address from clnt's xprt
|
||||
* @clnt: RPC client structure
|
||||
* @buf: target buffer
|
||||
* @size: length of target buffer
|
||||
*
|
||||
* Returns the number of bytes that are actually in the stored address.
|
||||
*/
|
||||
size_t rpc_peeraddr(struct rpc_clnt *clnt, struct sockaddr *buf, size_t bufsize)
|
||||
{
|
||||
size_t bytes;
|
||||
struct rpc_xprt *xprt = clnt->cl_xprt;
|
||||
|
||||
bytes = sizeof(xprt->addr);
|
||||
if (bytes > bufsize)
|
||||
bytes = bufsize;
|
||||
memcpy(buf, &clnt->cl_xprt->addr, bytes);
|
||||
return xprt->addrlen;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rpc_peeraddr);
|
||||
|
||||
/**
|
||||
* rpc_peeraddr2str - return remote peer address in printable format
|
||||
* @clnt: RPC client structure
|
||||
* @format: address format
|
||||
*
|
||||
*/
|
||||
char *rpc_peeraddr2str(struct rpc_clnt *clnt, enum rpc_display_format_t format)
|
||||
{
|
||||
struct rpc_xprt *xprt = clnt->cl_xprt;
|
||||
return xprt->ops->print_addr(xprt, format);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rpc_peeraddr2str);
|
||||
|
||||
void
|
||||
rpc_setbufsize(struct rpc_clnt *clnt, unsigned int sndsize, unsigned int rcvsize)
|
||||
{
|
||||
@ -560,7 +606,7 @@ size_t rpc_max_payload(struct rpc_clnt *clnt)
|
||||
{
|
||||
return clnt->cl_xprt->max_payload;
|
||||
}
|
||||
EXPORT_SYMBOL(rpc_max_payload);
|
||||
EXPORT_SYMBOL_GPL(rpc_max_payload);
|
||||
|
||||
/**
|
||||
* rpc_force_rebind - force transport to check that remote port is unchanged
|
||||
@ -570,9 +616,9 @@ EXPORT_SYMBOL(rpc_max_payload);
|
||||
void rpc_force_rebind(struct rpc_clnt *clnt)
|
||||
{
|
||||
if (clnt->cl_autobind)
|
||||
clnt->cl_port = 0;
|
||||
xprt_clear_bound(clnt->cl_xprt);
|
||||
}
|
||||
EXPORT_SYMBOL(rpc_force_rebind);
|
||||
EXPORT_SYMBOL_GPL(rpc_force_rebind);
|
||||
|
||||
/*
|
||||
* Restart an (async) RPC call. Usually called from within the
|
||||
@ -781,16 +827,16 @@ call_encode(struct rpc_task *task)
|
||||
static void
|
||||
call_bind(struct rpc_task *task)
|
||||
{
|
||||
struct rpc_clnt *clnt = task->tk_client;
|
||||
struct rpc_xprt *xprt = task->tk_xprt;
|
||||
|
||||
dprintk("RPC: %4d call_bind (status %d)\n",
|
||||
task->tk_pid, task->tk_status);
|
||||
|
||||
task->tk_action = call_connect;
|
||||
if (!clnt->cl_port) {
|
||||
if (!xprt_bound(xprt)) {
|
||||
task->tk_action = call_bind_status;
|
||||
task->tk_timeout = task->tk_xprt->bind_timeout;
|
||||
rpc_getport(task, clnt);
|
||||
task->tk_timeout = xprt->bind_timeout;
|
||||
xprt->ops->rpcbind(task);
|
||||
}
|
||||
}
|
||||
|
||||
@ -815,15 +861,11 @@ call_bind_status(struct rpc_task *task)
|
||||
dprintk("RPC: %4d remote rpcbind: RPC program/version unavailable\n",
|
||||
task->tk_pid);
|
||||
rpc_delay(task, 3*HZ);
|
||||
goto retry_bind;
|
||||
goto retry_timeout;
|
||||
case -ETIMEDOUT:
|
||||
dprintk("RPC: %4d rpcbind request timed out\n",
|
||||
task->tk_pid);
|
||||
if (RPC_IS_SOFT(task)) {
|
||||
status = -EIO;
|
||||
break;
|
||||
}
|
||||
goto retry_bind;
|
||||
goto retry_timeout;
|
||||
case -EPFNOSUPPORT:
|
||||
dprintk("RPC: %4d remote rpcbind service unavailable\n",
|
||||
task->tk_pid);
|
||||
@ -836,16 +878,13 @@ call_bind_status(struct rpc_task *task)
|
||||
dprintk("RPC: %4d unrecognized rpcbind error (%d)\n",
|
||||
task->tk_pid, -task->tk_status);
|
||||
status = -EIO;
|
||||
break;
|
||||
}
|
||||
|
||||
rpc_exit(task, status);
|
||||
return;
|
||||
|
||||
retry_bind:
|
||||
task->tk_status = 0;
|
||||
task->tk_action = call_bind;
|
||||
return;
|
||||
retry_timeout:
|
||||
task->tk_action = call_timeout;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -893,14 +932,16 @@ call_connect_status(struct rpc_task *task)
|
||||
|
||||
switch (status) {
|
||||
case -ENOTCONN:
|
||||
case -ETIMEDOUT:
|
||||
case -EAGAIN:
|
||||
task->tk_action = call_bind;
|
||||
break;
|
||||
default:
|
||||
rpc_exit(task, -EIO);
|
||||
break;
|
||||
if (!RPC_IS_SOFT(task))
|
||||
return;
|
||||
/* if soft mounted, test if we've timed out */
|
||||
case -ETIMEDOUT:
|
||||
task->tk_action = call_timeout;
|
||||
return;
|
||||
}
|
||||
rpc_exit(task, -EIO);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -982,6 +1023,14 @@ call_status(struct rpc_task *task)
|
||||
|
||||
task->tk_status = 0;
|
||||
switch(status) {
|
||||
case -EHOSTDOWN:
|
||||
case -EHOSTUNREACH:
|
||||
case -ENETUNREACH:
|
||||
/*
|
||||
* Delay any retries for 3 seconds, then handle as if it
|
||||
* were a timeout.
|
||||
*/
|
||||
rpc_delay(task, 3*HZ);
|
||||
case -ETIMEDOUT:
|
||||
task->tk_action = call_timeout;
|
||||
break;
|
||||
@ -1001,7 +1050,6 @@ call_status(struct rpc_task *task)
|
||||
printk("%s: RPC call returned error %d\n",
|
||||
clnt->cl_protname, -status);
|
||||
rpc_exit(task, status);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1069,10 +1117,10 @@ call_decode(struct rpc_task *task)
|
||||
clnt->cl_stats->rpcretrans++;
|
||||
goto out_retry;
|
||||
}
|
||||
printk(KERN_WARNING "%s: too small RPC reply size (%d bytes)\n",
|
||||
dprintk("%s: too small RPC reply size (%d bytes)\n",
|
||||
clnt->cl_protname, task->tk_status);
|
||||
rpc_exit(task, -EIO);
|
||||
return;
|
||||
task->tk_action = call_timeout;
|
||||
goto out_retry;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1,7 +1,9 @@
|
||||
/*
|
||||
* linux/net/sunrpc/pmap.c
|
||||
* linux/net/sunrpc/pmap_clnt.c
|
||||
*
|
||||
* Portmapper client.
|
||||
* In-kernel RPC portmapper client.
|
||||
*
|
||||
* Portmapper supports version 2 of the rpcbind protocol (RFC 1833).
|
||||
*
|
||||
* Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
|
||||
*/
|
||||
@ -13,7 +15,6 @@
|
||||
#include <linux/uio.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/sunrpc/clnt.h>
|
||||
#include <linux/sunrpc/xprt.h>
|
||||
#include <linux/sunrpc/sched.h>
|
||||
|
||||
#ifdef RPC_DEBUG
|
||||
@ -24,80 +25,141 @@
|
||||
#define PMAP_UNSET 2
|
||||
#define PMAP_GETPORT 3
|
||||
|
||||
struct portmap_args {
|
||||
u32 pm_prog;
|
||||
u32 pm_vers;
|
||||
u32 pm_prot;
|
||||
unsigned short pm_port;
|
||||
struct rpc_xprt * pm_xprt;
|
||||
};
|
||||
|
||||
static struct rpc_procinfo pmap_procedures[];
|
||||
static struct rpc_clnt * pmap_create(char *, struct sockaddr_in *, int, int);
|
||||
static void pmap_getport_done(struct rpc_task *);
|
||||
static void pmap_getport_done(struct rpc_task *, void *);
|
||||
static struct rpc_program pmap_program;
|
||||
static DEFINE_SPINLOCK(pmap_lock);
|
||||
|
||||
/*
|
||||
* Obtain the port for a given RPC service on a given host. This one can
|
||||
* be called for an ongoing RPC request.
|
||||
*/
|
||||
void
|
||||
rpc_getport(struct rpc_task *task, struct rpc_clnt *clnt)
|
||||
static void pmap_getport_prepare(struct rpc_task *task, void *calldata)
|
||||
{
|
||||
struct rpc_portmap *map = clnt->cl_pmap;
|
||||
struct sockaddr_in *sap = &clnt->cl_xprt->addr;
|
||||
struct portmap_args *map = calldata;
|
||||
struct rpc_message msg = {
|
||||
.rpc_proc = &pmap_procedures[PMAP_GETPORT],
|
||||
.rpc_argp = map,
|
||||
.rpc_resp = &clnt->cl_port,
|
||||
.rpc_cred = NULL
|
||||
.rpc_resp = &map->pm_port,
|
||||
};
|
||||
struct rpc_clnt *pmap_clnt;
|
||||
struct rpc_task *child;
|
||||
|
||||
dprintk("RPC: %4d rpc_getport(%s, %d, %d, %d)\n",
|
||||
rpc_call_setup(task, &msg, 0);
|
||||
}
|
||||
|
||||
static inline struct portmap_args *pmap_map_alloc(void)
|
||||
{
|
||||
return kmalloc(sizeof(struct portmap_args), GFP_NOFS);
|
||||
}
|
||||
|
||||
static inline void pmap_map_free(struct portmap_args *map)
|
||||
{
|
||||
kfree(map);
|
||||
}
|
||||
|
||||
static void pmap_map_release(void *data)
|
||||
{
|
||||
pmap_map_free(data);
|
||||
}
|
||||
|
||||
static const struct rpc_call_ops pmap_getport_ops = {
|
||||
.rpc_call_prepare = pmap_getport_prepare,
|
||||
.rpc_call_done = pmap_getport_done,
|
||||
.rpc_release = pmap_map_release,
|
||||
};
|
||||
|
||||
static inline void pmap_wake_portmap_waiters(struct rpc_xprt *xprt, int status)
|
||||
{
|
||||
xprt_clear_binding(xprt);
|
||||
rpc_wake_up_status(&xprt->binding, status);
|
||||
}
|
||||
|
||||
/**
|
||||
* rpc_getport - obtain the port for a given RPC service on a given host
|
||||
* @task: task that is waiting for portmapper request
|
||||
*
|
||||
* This one can be called for an ongoing RPC request, and can be used in
|
||||
* an async (rpciod) context.
|
||||
*/
|
||||
void rpc_getport(struct rpc_task *task)
|
||||
{
|
||||
struct rpc_clnt *clnt = task->tk_client;
|
||||
struct rpc_xprt *xprt = task->tk_xprt;
|
||||
struct sockaddr_in addr;
|
||||
struct portmap_args *map;
|
||||
struct rpc_clnt *pmap_clnt;
|
||||
struct rpc_task *child;
|
||||
int status;
|
||||
|
||||
dprintk("RPC: %4d rpc_getport(%s, %u, %u, %d)\n",
|
||||
task->tk_pid, clnt->cl_server,
|
||||
map->pm_prog, map->pm_vers, map->pm_prot);
|
||||
clnt->cl_prog, clnt->cl_vers, xprt->prot);
|
||||
|
||||
/* Autobind on cloned rpc clients is discouraged */
|
||||
BUG_ON(clnt->cl_parent != clnt);
|
||||
|
||||
spin_lock(&pmap_lock);
|
||||
if (map->pm_binding) {
|
||||
rpc_sleep_on(&map->pm_bindwait, task, NULL, NULL);
|
||||
spin_unlock(&pmap_lock);
|
||||
if (xprt_test_and_set_binding(xprt)) {
|
||||
task->tk_status = -EACCES; /* tell caller to check again */
|
||||
rpc_sleep_on(&xprt->binding, task, NULL, NULL);
|
||||
return;
|
||||
}
|
||||
map->pm_binding = 1;
|
||||
spin_unlock(&pmap_lock);
|
||||
|
||||
pmap_clnt = pmap_create(clnt->cl_server, sap, map->pm_prot, 0);
|
||||
if (IS_ERR(pmap_clnt)) {
|
||||
task->tk_status = PTR_ERR(pmap_clnt);
|
||||
goto bailout;
|
||||
}
|
||||
task->tk_status = 0;
|
||||
/* Someone else may have bound if we slept */
|
||||
status = 0;
|
||||
if (xprt_bound(xprt))
|
||||
goto bailout_nofree;
|
||||
|
||||
/*
|
||||
* Note: rpc_new_child will release client after a failure.
|
||||
*/
|
||||
if (!(child = rpc_new_child(pmap_clnt, task)))
|
||||
status = -ENOMEM;
|
||||
map = pmap_map_alloc();
|
||||
if (!map)
|
||||
goto bailout_nofree;
|
||||
map->pm_prog = clnt->cl_prog;
|
||||
map->pm_vers = clnt->cl_vers;
|
||||
map->pm_prot = xprt->prot;
|
||||
map->pm_port = 0;
|
||||
map->pm_xprt = xprt_get(xprt);
|
||||
|
||||
rpc_peeraddr(clnt, (struct sockaddr *) &addr, sizeof(addr));
|
||||
pmap_clnt = pmap_create(clnt->cl_server, &addr, map->pm_prot, 0);
|
||||
status = PTR_ERR(pmap_clnt);
|
||||
if (IS_ERR(pmap_clnt))
|
||||
goto bailout;
|
||||
|
||||
/* Setup the call info struct */
|
||||
rpc_call_setup(child, &msg, 0);
|
||||
status = -EIO;
|
||||
child = rpc_run_task(pmap_clnt, RPC_TASK_ASYNC, &pmap_getport_ops, map);
|
||||
if (IS_ERR(child))
|
||||
goto bailout;
|
||||
rpc_release_task(child);
|
||||
|
||||
rpc_sleep_on(&xprt->binding, task, NULL, NULL);
|
||||
|
||||
/* ... and run the child task */
|
||||
task->tk_xprt->stat.bind_count++;
|
||||
rpc_run_child(task, child, pmap_getport_done);
|
||||
return;
|
||||
|
||||
bailout:
|
||||
spin_lock(&pmap_lock);
|
||||
map->pm_binding = 0;
|
||||
rpc_wake_up(&map->pm_bindwait);
|
||||
spin_unlock(&pmap_lock);
|
||||
rpc_exit(task, -EIO);
|
||||
pmap_map_free(map);
|
||||
xprt_put(xprt);
|
||||
bailout_nofree:
|
||||
task->tk_status = status;
|
||||
pmap_wake_portmap_waiters(xprt, status);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ROOT_NFS
|
||||
int
|
||||
rpc_getport_external(struct sockaddr_in *sin, __u32 prog, __u32 vers, int prot)
|
||||
/**
|
||||
* rpc_getport_external - obtain the port for a given RPC service on a given host
|
||||
* @sin: address of remote peer
|
||||
* @prog: RPC program number to bind
|
||||
* @vers: RPC version number to bind
|
||||
* @prot: transport protocol to use to make this request
|
||||
*
|
||||
* This one is called from outside the RPC client in a synchronous task context.
|
||||
*/
|
||||
int rpc_getport_external(struct sockaddr_in *sin, __u32 prog, __u32 vers, int prot)
|
||||
{
|
||||
struct rpc_portmap map = {
|
||||
struct portmap_args map = {
|
||||
.pm_prog = prog,
|
||||
.pm_vers = vers,
|
||||
.pm_prot = prot,
|
||||
@ -112,7 +174,7 @@ rpc_getport_external(struct sockaddr_in *sin, __u32 prog, __u32 vers, int prot)
|
||||
char hostname[32];
|
||||
int status;
|
||||
|
||||
dprintk("RPC: rpc_getport_external(%u.%u.%u.%u, %d, %d, %d)\n",
|
||||
dprintk("RPC: rpc_getport_external(%u.%u.%u.%u, %u, %u, %d)\n",
|
||||
NIPQUAD(sin->sin_addr.s_addr), prog, vers, prot);
|
||||
|
||||
sprintf(hostname, "%u.%u.%u.%u", NIPQUAD(sin->sin_addr.s_addr));
|
||||
@ -132,45 +194,53 @@ rpc_getport_external(struct sockaddr_in *sin, __u32 prog, __u32 vers, int prot)
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
pmap_getport_done(struct rpc_task *task)
|
||||
/*
|
||||
* Portmapper child task invokes this callback via tk_exit.
|
||||
*/
|
||||
static void pmap_getport_done(struct rpc_task *child, void *data)
|
||||
{
|
||||
struct rpc_clnt *clnt = task->tk_client;
|
||||
struct rpc_xprt *xprt = task->tk_xprt;
|
||||
struct rpc_portmap *map = clnt->cl_pmap;
|
||||
struct portmap_args *map = data;
|
||||
struct rpc_xprt *xprt = map->pm_xprt;
|
||||
int status = child->tk_status;
|
||||
|
||||
dprintk("RPC: %4d pmap_getport_done(status %d, port %d)\n",
|
||||
task->tk_pid, task->tk_status, clnt->cl_port);
|
||||
|
||||
xprt->ops->set_port(xprt, 0);
|
||||
if (task->tk_status < 0) {
|
||||
/* Make the calling task exit with an error */
|
||||
task->tk_action = rpc_exit_task;
|
||||
} else if (clnt->cl_port == 0) {
|
||||
/* Program not registered */
|
||||
rpc_exit(task, -EACCES);
|
||||
if (status < 0) {
|
||||
/* Portmapper not available */
|
||||
xprt->ops->set_port(xprt, 0);
|
||||
} else if (map->pm_port == 0) {
|
||||
/* Requested RPC service wasn't registered */
|
||||
xprt->ops->set_port(xprt, 0);
|
||||
status = -EACCES;
|
||||
} else {
|
||||
xprt->ops->set_port(xprt, clnt->cl_port);
|
||||
clnt->cl_port = htons(clnt->cl_port);
|
||||
/* Succeeded */
|
||||
xprt->ops->set_port(xprt, map->pm_port);
|
||||
xprt_set_bound(xprt);
|
||||
status = 0;
|
||||
}
|
||||
spin_lock(&pmap_lock);
|
||||
map->pm_binding = 0;
|
||||
rpc_wake_up(&map->pm_bindwait);
|
||||
spin_unlock(&pmap_lock);
|
||||
|
||||
dprintk("RPC: %4d pmap_getport_done(status %d, port %u)\n",
|
||||
child->tk_pid, status, map->pm_port);
|
||||
|
||||
pmap_wake_portmap_waiters(xprt, status);
|
||||
xprt_put(xprt);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set or unset a port registration with the local portmapper.
|
||||
/**
|
||||
* rpc_register - set or unset a port registration with the local portmapper
|
||||
* @prog: RPC program number to bind
|
||||
* @vers: RPC version number to bind
|
||||
* @prot: transport protocol to use to make this request
|
||||
* @port: port value to register
|
||||
* @okay: result code
|
||||
*
|
||||
* port == 0 means unregister, port != 0 means register.
|
||||
*/
|
||||
int
|
||||
rpc_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay)
|
||||
int rpc_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay)
|
||||
{
|
||||
struct sockaddr_in sin = {
|
||||
.sin_family = AF_INET,
|
||||
.sin_addr.s_addr = htonl(INADDR_LOOPBACK),
|
||||
};
|
||||
struct rpc_portmap map = {
|
||||
struct portmap_args map = {
|
||||
.pm_prog = prog,
|
||||
.pm_vers = vers,
|
||||
.pm_prot = prot,
|
||||
@ -184,7 +254,7 @@ rpc_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay)
|
||||
struct rpc_clnt *pmap_clnt;
|
||||
int error = 0;
|
||||
|
||||
dprintk("RPC: registering (%d, %d, %d, %d) with portmapper.\n",
|
||||
dprintk("RPC: registering (%u, %u, %d, %u) with portmapper.\n",
|
||||
prog, vers, prot, port);
|
||||
|
||||
pmap_clnt = pmap_create("localhost", &sin, IPPROTO_UDP, 1);
|
||||
@ -207,38 +277,32 @@ rpc_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay)
|
||||
return error;
|
||||
}
|
||||
|
||||
static struct rpc_clnt *
|
||||
pmap_create(char *hostname, struct sockaddr_in *srvaddr, int proto, int privileged)
|
||||
static struct rpc_clnt *pmap_create(char *hostname, struct sockaddr_in *srvaddr, int proto, int privileged)
|
||||
{
|
||||
struct rpc_xprt *xprt;
|
||||
struct rpc_clnt *clnt;
|
||||
struct rpc_create_args args = {
|
||||
.protocol = proto,
|
||||
.address = (struct sockaddr *)srvaddr,
|
||||
.addrsize = sizeof(*srvaddr),
|
||||
.servername = hostname,
|
||||
.program = &pmap_program,
|
||||
.version = RPC_PMAP_VERSION,
|
||||
.authflavor = RPC_AUTH_UNIX,
|
||||
.flags = (RPC_CLNT_CREATE_ONESHOT |
|
||||
RPC_CLNT_CREATE_NOPING),
|
||||
};
|
||||
|
||||
/* printk("pmap: create xprt\n"); */
|
||||
xprt = xprt_create_proto(proto, srvaddr, NULL);
|
||||
if (IS_ERR(xprt))
|
||||
return (struct rpc_clnt *)xprt;
|
||||
xprt->ops->set_port(xprt, RPC_PMAP_PORT);
|
||||
srvaddr->sin_port = htons(RPC_PMAP_PORT);
|
||||
if (!privileged)
|
||||
xprt->resvport = 0;
|
||||
|
||||
/* printk("pmap: create clnt\n"); */
|
||||
clnt = rpc_new_client(xprt, hostname,
|
||||
&pmap_program, RPC_PMAP_VERSION,
|
||||
RPC_AUTH_UNIX);
|
||||
if (!IS_ERR(clnt)) {
|
||||
clnt->cl_softrtry = 1;
|
||||
clnt->cl_oneshot = 1;
|
||||
}
|
||||
return clnt;
|
||||
args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;
|
||||
return rpc_create(&args);
|
||||
}
|
||||
|
||||
/*
|
||||
* XDR encode/decode functions for PMAP
|
||||
*/
|
||||
static int
|
||||
xdr_encode_mapping(struct rpc_rqst *req, u32 *p, struct rpc_portmap *map)
|
||||
static int xdr_encode_mapping(struct rpc_rqst *req, u32 *p, struct portmap_args *map)
|
||||
{
|
||||
dprintk("RPC: xdr_encode_mapping(%d, %d, %d, %d)\n",
|
||||
dprintk("RPC: xdr_encode_mapping(%u, %u, %u, %u)\n",
|
||||
map->pm_prog, map->pm_vers, map->pm_prot, map->pm_port);
|
||||
*p++ = htonl(map->pm_prog);
|
||||
*p++ = htonl(map->pm_vers);
|
||||
@ -249,15 +313,13 @@ xdr_encode_mapping(struct rpc_rqst *req, u32 *p, struct rpc_portmap *map)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
xdr_decode_port(struct rpc_rqst *req, u32 *p, unsigned short *portp)
|
||||
static int xdr_decode_port(struct rpc_rqst *req, u32 *p, unsigned short *portp)
|
||||
{
|
||||
*portp = (unsigned short) ntohl(*p++);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
xdr_decode_bool(struct rpc_rqst *req, u32 *p, unsigned int *boolp)
|
||||
static int xdr_decode_bool(struct rpc_rqst *req, u32 *p, unsigned int *boolp)
|
||||
{
|
||||
*boolp = (unsigned int) ntohl(*p++);
|
||||
return 0;
|
||||
|
@ -327,10 +327,8 @@ rpc_show_info(struct seq_file *m, void *v)
|
||||
seq_printf(m, "RPC server: %s\n", clnt->cl_server);
|
||||
seq_printf(m, "service: %s (%d) version %d\n", clnt->cl_protname,
|
||||
clnt->cl_prog, clnt->cl_vers);
|
||||
seq_printf(m, "address: %u.%u.%u.%u\n",
|
||||
NIPQUAD(clnt->cl_xprt->addr.sin_addr.s_addr));
|
||||
seq_printf(m, "protocol: %s\n",
|
||||
clnt->cl_xprt->prot == IPPROTO_UDP ? "udp" : "tcp");
|
||||
seq_printf(m, "address: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_ADDR));
|
||||
seq_printf(m, "protocol: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_PROTO));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -623,17 +621,13 @@ __rpc_rmdir(struct inode *dir, struct dentry *dentry)
|
||||
}
|
||||
|
||||
static struct dentry *
|
||||
rpc_lookup_negative(char *path, struct nameidata *nd)
|
||||
rpc_lookup_create(struct dentry *parent, const char *name, int len)
|
||||
{
|
||||
struct inode *dir = parent->d_inode;
|
||||
struct dentry *dentry;
|
||||
struct inode *dir;
|
||||
int error;
|
||||
|
||||
if ((error = rpc_lookup_parent(path, nd)) != 0)
|
||||
return ERR_PTR(error);
|
||||
dir = nd->dentry->d_inode;
|
||||
mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
|
||||
dentry = lookup_one_len(nd->last.name, nd->dentry, nd->last.len);
|
||||
dentry = lookup_one_len(name, parent, len);
|
||||
if (IS_ERR(dentry))
|
||||
goto out_err;
|
||||
if (dentry->d_inode) {
|
||||
@ -644,7 +638,20 @@ rpc_lookup_negative(char *path, struct nameidata *nd)
|
||||
return dentry;
|
||||
out_err:
|
||||
mutex_unlock(&dir->i_mutex);
|
||||
rpc_release_path(nd);
|
||||
return dentry;
|
||||
}
|
||||
|
||||
static struct dentry *
|
||||
rpc_lookup_negative(char *path, struct nameidata *nd)
|
||||
{
|
||||
struct dentry *dentry;
|
||||
int error;
|
||||
|
||||
if ((error = rpc_lookup_parent(path, nd)) != 0)
|
||||
return ERR_PTR(error);
|
||||
dentry = rpc_lookup_create(nd->dentry, nd->last.name, nd->last.len);
|
||||
if (IS_ERR(dentry))
|
||||
rpc_release_path(nd);
|
||||
return dentry;
|
||||
}
|
||||
|
||||
@ -703,18 +710,17 @@ rpc_rmdir(struct dentry *dentry)
|
||||
}
|
||||
|
||||
struct dentry *
|
||||
rpc_mkpipe(char *path, void *private, struct rpc_pipe_ops *ops, int flags)
|
||||
rpc_mkpipe(struct dentry *parent, const char *name, void *private, struct rpc_pipe_ops *ops, int flags)
|
||||
{
|
||||
struct nameidata nd;
|
||||
struct dentry *dentry;
|
||||
struct inode *dir, *inode;
|
||||
struct rpc_inode *rpci;
|
||||
|
||||
dentry = rpc_lookup_negative(path, &nd);
|
||||
dentry = rpc_lookup_create(parent, name, strlen(name));
|
||||
if (IS_ERR(dentry))
|
||||
return dentry;
|
||||
dir = nd.dentry->d_inode;
|
||||
inode = rpc_get_inode(dir->i_sb, S_IFSOCK | S_IRUSR | S_IWUSR);
|
||||
dir = parent->d_inode;
|
||||
inode = rpc_get_inode(dir->i_sb, S_IFIFO | S_IRUSR | S_IWUSR);
|
||||
if (!inode)
|
||||
goto err_dput;
|
||||
inode->i_ino = iunique(dir->i_sb, 100);
|
||||
@ -728,13 +734,13 @@ rpc_mkpipe(char *path, void *private, struct rpc_pipe_ops *ops, int flags)
|
||||
dget(dentry);
|
||||
out:
|
||||
mutex_unlock(&dir->i_mutex);
|
||||
rpc_release_path(&nd);
|
||||
return dentry;
|
||||
err_dput:
|
||||
dput(dentry);
|
||||
dentry = ERR_PTR(-ENOMEM);
|
||||
printk(KERN_WARNING "%s: %s() failed to create pipe %s (errno = %d)\n",
|
||||
__FILE__, __FUNCTION__, path, -ENOMEM);
|
||||
printk(KERN_WARNING "%s: %s() failed to create pipe %s/%s (errno = %d)\n",
|
||||
__FILE__, __FUNCTION__, parent->d_name.name, name,
|
||||
-ENOMEM);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,6 @@
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#include <linux/sunrpc/clnt.h>
|
||||
#include <linux/sunrpc/xprt.h>
|
||||
|
||||
#ifdef RPC_DEBUG
|
||||
#define RPCDBG_FACILITY RPCDBG_SCHED
|
||||
@ -44,12 +43,6 @@ static void __rpc_default_timer(struct rpc_task *task);
|
||||
static void rpciod_killall(void);
|
||||
static void rpc_async_schedule(void *);
|
||||
|
||||
/*
|
||||
* RPC tasks that create another task (e.g. for contacting the portmapper)
|
||||
* will wait on this queue for their child's completion
|
||||
*/
|
||||
static RPC_WAITQ(childq, "childq");
|
||||
|
||||
/*
|
||||
* RPC tasks sit here while waiting for conditions to improve.
|
||||
*/
|
||||
@ -323,16 +316,6 @@ static void rpc_make_runnable(struct rpc_task *task)
|
||||
wake_up_bit(&task->tk_runstate, RPC_TASK_QUEUED);
|
||||
}
|
||||
|
||||
/*
|
||||
* Place a newly initialized task on the workqueue.
|
||||
*/
|
||||
static inline void
|
||||
rpc_schedule_run(struct rpc_task *task)
|
||||
{
|
||||
rpc_set_active(task);
|
||||
rpc_make_runnable(task);
|
||||
}
|
||||
|
||||
/*
|
||||
* Prepare for sleeping on a wait queue.
|
||||
* By always appending tasks to the list we ensure FIFO behavior.
|
||||
@ -559,24 +542,20 @@ void rpc_wake_up_status(struct rpc_wait_queue *queue, int status)
|
||||
spin_unlock_bh(&queue->lock);
|
||||
}
|
||||
|
||||
static void __rpc_atrun(struct rpc_task *task)
|
||||
{
|
||||
rpc_wake_up_task(task);
|
||||
}
|
||||
|
||||
/*
|
||||
* Run a task at a later time
|
||||
*/
|
||||
static void __rpc_atrun(struct rpc_task *);
|
||||
void
|
||||
rpc_delay(struct rpc_task *task, unsigned long delay)
|
||||
void rpc_delay(struct rpc_task *task, unsigned long delay)
|
||||
{
|
||||
task->tk_timeout = delay;
|
||||
rpc_sleep_on(&delay_queue, task, NULL, __rpc_atrun);
|
||||
}
|
||||
|
||||
static void
|
||||
__rpc_atrun(struct rpc_task *task)
|
||||
{
|
||||
task->tk_status = 0;
|
||||
rpc_wake_up_task(task);
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper to call task->tk_ops->rpc_call_prepare
|
||||
*/
|
||||
@ -933,72 +912,6 @@ struct rpc_task *rpc_run_task(struct rpc_clnt *clnt, int flags,
|
||||
}
|
||||
EXPORT_SYMBOL(rpc_run_task);
|
||||
|
||||
/**
|
||||
* rpc_find_parent - find the parent of a child task.
|
||||
* @child: child task
|
||||
* @parent: parent task
|
||||
*
|
||||
* Checks that the parent task is still sleeping on the
|
||||
* queue 'childq'. If so returns a pointer to the parent.
|
||||
* Upon failure returns NULL.
|
||||
*
|
||||
* Caller must hold childq.lock
|
||||
*/
|
||||
static inline struct rpc_task *rpc_find_parent(struct rpc_task *child, struct rpc_task *parent)
|
||||
{
|
||||
struct rpc_task *task;
|
||||
struct list_head *le;
|
||||
|
||||
task_for_each(task, le, &childq.tasks[0])
|
||||
if (task == parent)
|
||||
return parent;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void rpc_child_exit(struct rpc_task *child, void *calldata)
|
||||
{
|
||||
struct rpc_task *parent;
|
||||
|
||||
spin_lock_bh(&childq.lock);
|
||||
if ((parent = rpc_find_parent(child, calldata)) != NULL) {
|
||||
parent->tk_status = child->tk_status;
|
||||
__rpc_wake_up_task(parent);
|
||||
}
|
||||
spin_unlock_bh(&childq.lock);
|
||||
}
|
||||
|
||||
static const struct rpc_call_ops rpc_child_ops = {
|
||||
.rpc_call_done = rpc_child_exit,
|
||||
};
|
||||
|
||||
/*
|
||||
* Note: rpc_new_task releases the client after a failure.
|
||||
*/
|
||||
struct rpc_task *
|
||||
rpc_new_child(struct rpc_clnt *clnt, struct rpc_task *parent)
|
||||
{
|
||||
struct rpc_task *task;
|
||||
|
||||
task = rpc_new_task(clnt, RPC_TASK_ASYNC | RPC_TASK_CHILD, &rpc_child_ops, parent);
|
||||
if (!task)
|
||||
goto fail;
|
||||
return task;
|
||||
|
||||
fail:
|
||||
parent->tk_status = -ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void rpc_run_child(struct rpc_task *task, struct rpc_task *child, rpc_action func)
|
||||
{
|
||||
spin_lock_bh(&childq.lock);
|
||||
/* N.B. Is it possible for the child to have already finished? */
|
||||
__rpc_sleep_on(&childq, task, func, NULL);
|
||||
rpc_schedule_run(child);
|
||||
spin_unlock_bh(&childq.lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Kill all tasks for the given client.
|
||||
* XXX: kill their descendants as well?
|
||||
|
@ -36,8 +36,6 @@ EXPORT_SYMBOL(rpc_wake_up_status);
|
||||
EXPORT_SYMBOL(rpc_release_task);
|
||||
|
||||
/* RPC client functions */
|
||||
EXPORT_SYMBOL(rpc_create_client);
|
||||
EXPORT_SYMBOL(rpc_new_client);
|
||||
EXPORT_SYMBOL(rpc_clone_client);
|
||||
EXPORT_SYMBOL(rpc_bind_new_program);
|
||||
EXPORT_SYMBOL(rpc_destroy_client);
|
||||
@ -57,7 +55,6 @@ EXPORT_SYMBOL(rpc_queue_upcall);
|
||||
EXPORT_SYMBOL(rpc_mkpipe);
|
||||
|
||||
/* Client transport */
|
||||
EXPORT_SYMBOL(xprt_create_proto);
|
||||
EXPORT_SYMBOL(xprt_set_timeout);
|
||||
|
||||
/* Client credential cache */
|
||||
|
@ -19,8 +19,6 @@
|
||||
#include <linux/unistd.h>
|
||||
|
||||
#include <linux/sunrpc/clnt.h>
|
||||
#include <linux/sunrpc/xprt.h>
|
||||
#include <linux/sunrpc/timer.h>
|
||||
|
||||
#define RPC_RTO_MAX (60*HZ)
|
||||
#define RPC_RTO_INIT (HZ/5)
|
||||
|
@ -534,7 +534,7 @@ void xprt_connect(struct rpc_task *task)
|
||||
dprintk("RPC: %4d xprt_connect xprt %p %s connected\n", task->tk_pid,
|
||||
xprt, (xprt_connected(xprt) ? "is" : "is not"));
|
||||
|
||||
if (!xprt->addr.sin_port) {
|
||||
if (!xprt_bound(xprt)) {
|
||||
task->tk_status = -EIO;
|
||||
return;
|
||||
}
|
||||
@ -585,13 +585,6 @@ static void xprt_connect_status(struct rpc_task *task)
|
||||
task->tk_pid, -task->tk_status, task->tk_client->cl_server);
|
||||
xprt_release_write(xprt, task);
|
||||
task->tk_status = -EIO;
|
||||
return;
|
||||
}
|
||||
|
||||
/* if soft mounted, just cause this RPC to fail */
|
||||
if (RPC_IS_SOFT(task)) {
|
||||
xprt_release_write(xprt, task);
|
||||
task->tk_status = -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
@ -829,6 +822,7 @@ static void xprt_request_init(struct rpc_task *task, struct rpc_xprt *xprt)
|
||||
req->rq_bufsize = 0;
|
||||
req->rq_xid = xprt_alloc_xid(xprt);
|
||||
req->rq_release_snd_buf = NULL;
|
||||
xprt_reset_majortimeo(req);
|
||||
dprintk("RPC: %4d reserved req %p xid %08x\n", task->tk_pid,
|
||||
req, ntohl(req->rq_xid));
|
||||
}
|
||||
@ -887,16 +881,32 @@ void xprt_set_timeout(struct rpc_timeout *to, unsigned int retr, unsigned long i
|
||||
to->to_exponential = 0;
|
||||
}
|
||||
|
||||
static struct rpc_xprt *xprt_setup(int proto, struct sockaddr_in *ap, struct rpc_timeout *to)
|
||||
/**
|
||||
* xprt_create_transport - create an RPC transport
|
||||
* @proto: requested transport protocol
|
||||
* @ap: remote peer address
|
||||
* @size: length of address
|
||||
* @to: timeout parameters
|
||||
*
|
||||
*/
|
||||
struct rpc_xprt *xprt_create_transport(int proto, struct sockaddr *ap, size_t size, struct rpc_timeout *to)
|
||||
{
|
||||
int result;
|
||||
struct rpc_xprt *xprt;
|
||||
struct rpc_rqst *req;
|
||||
|
||||
if ((xprt = kzalloc(sizeof(struct rpc_xprt), GFP_KERNEL)) == NULL)
|
||||
if ((xprt = kzalloc(sizeof(struct rpc_xprt), GFP_KERNEL)) == NULL) {
|
||||
dprintk("RPC: xprt_create_transport: no memory\n");
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
xprt->addr = *ap;
|
||||
}
|
||||
if (size <= sizeof(xprt->addr)) {
|
||||
memcpy(&xprt->addr, ap, size);
|
||||
xprt->addrlen = size;
|
||||
} else {
|
||||
kfree(xprt);
|
||||
dprintk("RPC: xprt_create_transport: address too large\n");
|
||||
return ERR_PTR(-EBADF);
|
||||
}
|
||||
|
||||
switch (proto) {
|
||||
case IPPROTO_UDP:
|
||||
@ -908,14 +918,15 @@ static struct rpc_xprt *xprt_setup(int proto, struct sockaddr_in *ap, struct rpc
|
||||
default:
|
||||
printk(KERN_ERR "RPC: unrecognized transport protocol: %d\n",
|
||||
proto);
|
||||
result = -EIO;
|
||||
break;
|
||||
return ERR_PTR(-EIO);
|
||||
}
|
||||
if (result) {
|
||||
kfree(xprt);
|
||||
dprintk("RPC: xprt_create_transport: failed, %d\n", result);
|
||||
return ERR_PTR(result);
|
||||
}
|
||||
|
||||
kref_init(&xprt->kref);
|
||||
spin_lock_init(&xprt->transport_lock);
|
||||
spin_lock_init(&xprt->reserve_lock);
|
||||
|
||||
@ -928,6 +939,7 @@ static struct rpc_xprt *xprt_setup(int proto, struct sockaddr_in *ap, struct rpc
|
||||
xprt->last_used = jiffies;
|
||||
xprt->cwnd = RPC_INITCWND;
|
||||
|
||||
rpc_init_wait_queue(&xprt->binding, "xprt_binding");
|
||||
rpc_init_wait_queue(&xprt->pending, "xprt_pending");
|
||||
rpc_init_wait_queue(&xprt->sending, "xprt_sending");
|
||||
rpc_init_wait_queue(&xprt->resend, "xprt_resend");
|
||||
@ -941,41 +953,43 @@ static struct rpc_xprt *xprt_setup(int proto, struct sockaddr_in *ap, struct rpc
|
||||
|
||||
dprintk("RPC: created transport %p with %u slots\n", xprt,
|
||||
xprt->max_reqs);
|
||||
|
||||
return xprt;
|
||||
}
|
||||
|
||||
/**
|
||||
* xprt_create_proto - create an RPC client transport
|
||||
* @proto: requested transport protocol
|
||||
* @sap: remote peer's address
|
||||
* @to: timeout parameters for new transport
|
||||
*
|
||||
*/
|
||||
struct rpc_xprt *xprt_create_proto(int proto, struct sockaddr_in *sap, struct rpc_timeout *to)
|
||||
{
|
||||
struct rpc_xprt *xprt;
|
||||
|
||||
xprt = xprt_setup(proto, sap, to);
|
||||
if (IS_ERR(xprt))
|
||||
dprintk("RPC: xprt_create_proto failed\n");
|
||||
else
|
||||
dprintk("RPC: xprt_create_proto created xprt %p\n", xprt);
|
||||
return xprt;
|
||||
}
|
||||
|
||||
/**
|
||||
* xprt_destroy - destroy an RPC transport, killing off all requests.
|
||||
* @xprt: transport to destroy
|
||||
* @kref: kref for the transport to destroy
|
||||
*
|
||||
*/
|
||||
int xprt_destroy(struct rpc_xprt *xprt)
|
||||
static void xprt_destroy(struct kref *kref)
|
||||
{
|
||||
struct rpc_xprt *xprt = container_of(kref, struct rpc_xprt, kref);
|
||||
|
||||
dprintk("RPC: destroying transport %p\n", xprt);
|
||||
xprt->shutdown = 1;
|
||||
del_timer_sync(&xprt->timer);
|
||||
xprt->ops->destroy(xprt);
|
||||
kfree(xprt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* xprt_put - release a reference to an RPC transport.
|
||||
* @xprt: pointer to the transport
|
||||
*
|
||||
*/
|
||||
void xprt_put(struct rpc_xprt *xprt)
|
||||
{
|
||||
kref_put(&xprt->kref, xprt_destroy);
|
||||
}
|
||||
|
||||
/**
|
||||
* xprt_get - return a reference to an RPC transport.
|
||||
* @xprt: pointer to the transport
|
||||
*
|
||||
*/
|
||||
struct rpc_xprt *xprt_get(struct rpc_xprt *xprt)
|
||||
{
|
||||
kref_get(&xprt->kref);
|
||||
return xprt;
|
||||
}
|
||||
|
@ -125,6 +125,47 @@ static inline void xs_pktdump(char *msg, u32 *packet, unsigned int count)
|
||||
}
|
||||
#endif
|
||||
|
||||
static void xs_format_peer_addresses(struct rpc_xprt *xprt)
|
||||
{
|
||||
struct sockaddr_in *addr = (struct sockaddr_in *) &xprt->addr;
|
||||
char *buf;
|
||||
|
||||
buf = kzalloc(20, GFP_KERNEL);
|
||||
if (buf) {
|
||||
snprintf(buf, 20, "%u.%u.%u.%u",
|
||||
NIPQUAD(addr->sin_addr.s_addr));
|
||||
}
|
||||
xprt->address_strings[RPC_DISPLAY_ADDR] = buf;
|
||||
|
||||
buf = kzalloc(8, GFP_KERNEL);
|
||||
if (buf) {
|
||||
snprintf(buf, 8, "%u",
|
||||
ntohs(addr->sin_port));
|
||||
}
|
||||
xprt->address_strings[RPC_DISPLAY_PORT] = buf;
|
||||
|
||||
if (xprt->prot == IPPROTO_UDP)
|
||||
xprt->address_strings[RPC_DISPLAY_PROTO] = "udp";
|
||||
else
|
||||
xprt->address_strings[RPC_DISPLAY_PROTO] = "tcp";
|
||||
|
||||
buf = kzalloc(48, GFP_KERNEL);
|
||||
if (buf) {
|
||||
snprintf(buf, 48, "addr=%u.%u.%u.%u port=%u proto=%s",
|
||||
NIPQUAD(addr->sin_addr.s_addr),
|
||||
ntohs(addr->sin_port),
|
||||
xprt->prot == IPPROTO_UDP ? "udp" : "tcp");
|
||||
}
|
||||
xprt->address_strings[RPC_DISPLAY_ALL] = buf;
|
||||
}
|
||||
|
||||
static void xs_free_peer_addresses(struct rpc_xprt *xprt)
|
||||
{
|
||||
kfree(xprt->address_strings[RPC_DISPLAY_ADDR]);
|
||||
kfree(xprt->address_strings[RPC_DISPLAY_PORT]);
|
||||
kfree(xprt->address_strings[RPC_DISPLAY_ALL]);
|
||||
}
|
||||
|
||||
#define XS_SENDMSG_FLAGS (MSG_DONTWAIT | MSG_NOSIGNAL)
|
||||
|
||||
static inline int xs_send_head(struct socket *sock, struct sockaddr *addr, int addrlen, struct xdr_buf *xdr, unsigned int base, unsigned int len)
|
||||
@ -295,7 +336,7 @@ static int xs_udp_send_request(struct rpc_task *task)
|
||||
|
||||
req->rq_xtime = jiffies;
|
||||
status = xs_sendpages(xprt->sock, (struct sockaddr *) &xprt->addr,
|
||||
sizeof(xprt->addr), xdr, req->rq_bytes_sent);
|
||||
xprt->addrlen, xdr, req->rq_bytes_sent);
|
||||
|
||||
dprintk("RPC: xs_udp_send_request(%u) = %d\n",
|
||||
xdr->len - req->rq_bytes_sent, status);
|
||||
@ -485,6 +526,7 @@ static void xs_destroy(struct rpc_xprt *xprt)
|
||||
|
||||
xprt_disconnect(xprt);
|
||||
xs_close(xprt);
|
||||
xs_free_peer_addresses(xprt);
|
||||
kfree(xprt->slot);
|
||||
}
|
||||
|
||||
@ -959,6 +1001,19 @@ static unsigned short xs_get_random_port(void)
|
||||
return rand + xprt_min_resvport;
|
||||
}
|
||||
|
||||
/**
|
||||
* xs_print_peer_address - format an IPv4 address for printing
|
||||
* @xprt: generic transport
|
||||
* @format: flags field indicating which parts of the address to render
|
||||
*/
|
||||
static char *xs_print_peer_address(struct rpc_xprt *xprt, enum rpc_display_format_t format)
|
||||
{
|
||||
if (xprt->address_strings[format] != NULL)
|
||||
return xprt->address_strings[format];
|
||||
else
|
||||
return "unprintable";
|
||||
}
|
||||
|
||||
/**
|
||||
* xs_set_port - reset the port number in the remote endpoint address
|
||||
* @xprt: generic transport
|
||||
@ -967,8 +1022,11 @@ static unsigned short xs_get_random_port(void)
|
||||
*/
|
||||
static void xs_set_port(struct rpc_xprt *xprt, unsigned short port)
|
||||
{
|
||||
struct sockaddr_in *sap = (struct sockaddr_in *) &xprt->addr;
|
||||
|
||||
dprintk("RPC: setting port for xprt %p to %u\n", xprt, port);
|
||||
xprt->addr.sin_port = htons(port);
|
||||
|
||||
sap->sin_port = htons(port);
|
||||
}
|
||||
|
||||
static int xs_bindresvport(struct rpc_xprt *xprt, struct socket *sock)
|
||||
@ -1011,11 +1069,9 @@ static void xs_udp_connect_worker(void *args)
|
||||
struct socket *sock = xprt->sock;
|
||||
int err, status = -EIO;
|
||||
|
||||
if (xprt->shutdown || xprt->addr.sin_port == 0)
|
||||
if (xprt->shutdown || !xprt_bound(xprt))
|
||||
goto out;
|
||||
|
||||
dprintk("RPC: xs_udp_connect_worker for xprt %p\n", xprt);
|
||||
|
||||
/* Start by resetting any existing state */
|
||||
xs_close(xprt);
|
||||
|
||||
@ -1029,6 +1085,9 @@ static void xs_udp_connect_worker(void *args)
|
||||
goto out;
|
||||
}
|
||||
|
||||
dprintk("RPC: worker connecting xprt %p to address: %s\n",
|
||||
xprt, xs_print_peer_address(xprt, RPC_DISPLAY_ALL));
|
||||
|
||||
if (!xprt->inet) {
|
||||
struct sock *sk = sock->sk;
|
||||
|
||||
@ -1094,11 +1153,9 @@ static void xs_tcp_connect_worker(void *args)
|
||||
struct socket *sock = xprt->sock;
|
||||
int err, status = -EIO;
|
||||
|
||||
if (xprt->shutdown || xprt->addr.sin_port == 0)
|
||||
if (xprt->shutdown || !xprt_bound(xprt))
|
||||
goto out;
|
||||
|
||||
dprintk("RPC: xs_tcp_connect_worker for xprt %p\n", xprt);
|
||||
|
||||
if (!xprt->sock) {
|
||||
/* start from scratch */
|
||||
if ((err = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock)) < 0) {
|
||||
@ -1114,6 +1171,9 @@ static void xs_tcp_connect_worker(void *args)
|
||||
/* "close" the socket, preserving the local port */
|
||||
xs_tcp_reuse_connection(xprt);
|
||||
|
||||
dprintk("RPC: worker connecting xprt %p to address: %s\n",
|
||||
xprt, xs_print_peer_address(xprt, RPC_DISPLAY_ALL));
|
||||
|
||||
if (!xprt->inet) {
|
||||
struct sock *sk = sock->sk;
|
||||
|
||||
@ -1147,7 +1207,7 @@ static void xs_tcp_connect_worker(void *args)
|
||||
xprt->stat.connect_count++;
|
||||
xprt->stat.connect_start = jiffies;
|
||||
status = kernel_connect(sock, (struct sockaddr *) &xprt->addr,
|
||||
sizeof(xprt->addr), O_NONBLOCK);
|
||||
xprt->addrlen, O_NONBLOCK);
|
||||
dprintk("RPC: %p connect status %d connected %d sock state %d\n",
|
||||
xprt, -status, xprt_connected(xprt), sock->sk->sk_state);
|
||||
if (status < 0) {
|
||||
@ -1255,8 +1315,10 @@ static void xs_tcp_print_stats(struct rpc_xprt *xprt, struct seq_file *seq)
|
||||
|
||||
static struct rpc_xprt_ops xs_udp_ops = {
|
||||
.set_buffer_size = xs_udp_set_buffer_size,
|
||||
.print_addr = xs_print_peer_address,
|
||||
.reserve_xprt = xprt_reserve_xprt_cong,
|
||||
.release_xprt = xprt_release_xprt_cong,
|
||||
.rpcbind = rpc_getport,
|
||||
.set_port = xs_set_port,
|
||||
.connect = xs_connect,
|
||||
.buf_alloc = rpc_malloc,
|
||||
@ -1271,8 +1333,10 @@ static struct rpc_xprt_ops xs_udp_ops = {
|
||||
};
|
||||
|
||||
static struct rpc_xprt_ops xs_tcp_ops = {
|
||||
.print_addr = xs_print_peer_address,
|
||||
.reserve_xprt = xprt_reserve_xprt,
|
||||
.release_xprt = xs_tcp_release_xprt,
|
||||
.rpcbind = rpc_getport,
|
||||
.set_port = xs_set_port,
|
||||
.connect = xs_connect,
|
||||
.buf_alloc = rpc_malloc,
|
||||
@ -1293,8 +1357,7 @@ static struct rpc_xprt_ops xs_tcp_ops = {
|
||||
int xs_setup_udp(struct rpc_xprt *xprt, struct rpc_timeout *to)
|
||||
{
|
||||
size_t slot_table_size;
|
||||
|
||||
dprintk("RPC: setting up udp-ipv4 transport...\n");
|
||||
struct sockaddr_in *addr = (struct sockaddr_in *) &xprt->addr;
|
||||
|
||||
xprt->max_reqs = xprt_udp_slot_table_entries;
|
||||
slot_table_size = xprt->max_reqs * sizeof(xprt->slot[0]);
|
||||
@ -1302,10 +1365,12 @@ int xs_setup_udp(struct rpc_xprt *xprt, struct rpc_timeout *to)
|
||||
if (xprt->slot == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
xprt->prot = IPPROTO_UDP;
|
||||
if (ntohs(addr->sin_port != 0))
|
||||
xprt_set_bound(xprt);
|
||||
xprt->port = xs_get_random_port();
|
||||
|
||||
xprt->prot = IPPROTO_UDP;
|
||||
xprt->tsh_size = 0;
|
||||
xprt->resvport = capable(CAP_NET_BIND_SERVICE) ? 1 : 0;
|
||||
/* XXX: header size can vary due to auth type, IPv6, etc. */
|
||||
xprt->max_payload = (1U << 16) - (MAX_HEADER << 3);
|
||||
|
||||
@ -1322,6 +1387,10 @@ int xs_setup_udp(struct rpc_xprt *xprt, struct rpc_timeout *to)
|
||||
else
|
||||
xprt_set_timeout(&xprt->timeout, 5, 5 * HZ);
|
||||
|
||||
xs_format_peer_addresses(xprt);
|
||||
dprintk("RPC: set up transport to address %s\n",
|
||||
xs_print_peer_address(xprt, RPC_DISPLAY_ALL));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1334,8 +1403,7 @@ int xs_setup_udp(struct rpc_xprt *xprt, struct rpc_timeout *to)
|
||||
int xs_setup_tcp(struct rpc_xprt *xprt, struct rpc_timeout *to)
|
||||
{
|
||||
size_t slot_table_size;
|
||||
|
||||
dprintk("RPC: setting up tcp-ipv4 transport...\n");
|
||||
struct sockaddr_in *addr = (struct sockaddr_in *) &xprt->addr;
|
||||
|
||||
xprt->max_reqs = xprt_tcp_slot_table_entries;
|
||||
slot_table_size = xprt->max_reqs * sizeof(xprt->slot[0]);
|
||||
@ -1343,10 +1411,12 @@ int xs_setup_tcp(struct rpc_xprt *xprt, struct rpc_timeout *to)
|
||||
if (xprt->slot == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
xprt->prot = IPPROTO_TCP;
|
||||
if (ntohs(addr->sin_port) != 0)
|
||||
xprt_set_bound(xprt);
|
||||
xprt->port = xs_get_random_port();
|
||||
|
||||
xprt->prot = IPPROTO_TCP;
|
||||
xprt->tsh_size = sizeof(rpc_fraghdr) / sizeof(u32);
|
||||
xprt->resvport = capable(CAP_NET_BIND_SERVICE) ? 1 : 0;
|
||||
xprt->max_payload = RPC_MAX_FRAGMENT_SIZE;
|
||||
|
||||
INIT_WORK(&xprt->connect_worker, xs_tcp_connect_worker, xprt);
|
||||
@ -1362,5 +1432,9 @@ int xs_setup_tcp(struct rpc_xprt *xprt, struct rpc_timeout *to)
|
||||
else
|
||||
xprt_set_timeout(&xprt->timeout, 2, 60 * HZ);
|
||||
|
||||
xs_format_peer_addresses(xprt);
|
||||
dprintk("RPC: set up transport to address %s\n",
|
||||
xs_print_peer_address(xprt, RPC_DISPLAY_ALL));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user