You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
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:
@@ -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
|
||||
*/
|
||||
|
||||
+2
-2
@@ -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
|
||||
|
||||
+150
-14
@@ -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);
|
||||
|
||||
+5
-5
@@ -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;
|
||||
|
||||
|
||||
+25
-22
@@ -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;
|
||||
|
||||
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 */
|
||||
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),
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+16
-23
@@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+3
-3
@@ -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
|
||||
|
||||
+22
-9
@@ -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)
|
||||
|
||||
+6
-1
@@ -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
File diff suppressed because it is too large
Load Diff
+18
-17
@@ -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;
|
||||
|
||||
+5
-5
@@ -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);
|
||||
|
||||
+283
-63
@@ -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,
|
||||
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;
|
||||
d_instantiate(dentry, inode);
|
||||
return 0;
|
||||
out_err:
|
||||
d_drop(dentry);
|
||||
return error;
|
||||
d_instantiate(dentry, inode);
|
||||
if (d_unhashed(dentry))
|
||||
d_rehash(dentry);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -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 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))
|
||||
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;
|
||||
memcpy(res, cache, sizeof(*res));
|
||||
return 0;
|
||||
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)
|
||||
|
||||
+2
-2
@@ -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)
|
||||
|
||||
@@ -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 */
|
||||
+29
-16
@@ -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;
|
||||
|
||||
|
||||
+24
-16
@@ -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,14 +717,12 @@ 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)) {
|
||||
/* 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 */
|
||||
|
||||
+67
-34
@@ -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,21 +138,20 @@ 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
|
||||
@@ -111,7 +160,8 @@ static inline char *nfs_devname(const struct vfsmount *mnt_parent,
|
||||
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;
|
||||
}
|
||||
|
||||
+12
-16
@@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user