Commit 08cc36cb authored by Trond Myklebust's avatar Trond Myklebust

Merge branch 'devel' into next

parents 3c92ec8a 46f72f57
......@@ -14,6 +14,7 @@
#include <linux/sunrpc/svc.h>
#include <linux/lockd/lockd.h>
#include <linux/smp_lock.h>
#include <linux/kthread.h>
#define NLMDBG_FACILITY NLMDBG_CLIENT
......@@ -60,7 +61,7 @@ struct nlm_host *nlmclnt_init(const struct nlmclnt_initdata *nlm_init)
host = nlmclnt_lookup_host(nlm_init->address, nlm_init->addrlen,
nlm_init->protocol, nlm_version,
nlm_init->hostname);
nlm_init->hostname, nlm_init->noresvport);
if (host == NULL) {
lockd_down();
return ERR_PTR(-ENOLCK);
......@@ -191,11 +192,15 @@ __be32 nlmclnt_grant(const struct sockaddr *addr, const struct nlm_lock *lock)
void
nlmclnt_recovery(struct nlm_host *host)
{
struct task_struct *task;
if (!host->h_reclaiming++) {
nlm_get_host(host);
__module_get(THIS_MODULE);
if (kernel_thread(reclaimer, host, CLONE_FS | CLONE_FILES) < 0)
module_put(THIS_MODULE);
task = kthread_run(reclaimer, host, "%s-reclaim", host->h_name);
if (IS_ERR(task))
printk(KERN_ERR "lockd: unable to spawn reclaimer "
"thread. Locks for %s won't be reclaimed! "
"(%ld)\n", host->h_name, PTR_ERR(task));
}
}
......@@ -207,7 +212,6 @@ reclaimer(void *ptr)
struct file_lock *fl, *next;
u32 nsmstate;
daemonize("%s-reclaim", host->h_name);
allow_signal(SIGKILL);
down_write(&host->h_rwsem);
......@@ -233,7 +237,12 @@ reclaimer(void *ptr)
list_for_each_entry_safe(fl, next, &host->h_reclaim, fl_u.nfs_fl.list) {
list_del_init(&fl->fl_u.nfs_fl.list);
/* Why are we leaking memory here? --okir */
/*
* sending this thread a SIGKILL will result in any unreclaimed
* locks being removed from the h_granted list. This means that
* the kernel will not attempt to reclaim them again if a new
* reclaimer thread is spawned for this host.
*/
if (signalled())
continue;
if (nlmclnt_reclaim(host, fl) != 0)
......@@ -261,5 +270,5 @@ reclaimer(void *ptr)
nlm_release_host(host);
lockd_down();
unlock_kernel();
module_put_and_exit(0);
return 0;
}
......@@ -48,6 +48,7 @@ struct nlm_lookup_host_info {
const size_t hostname_len; /* it's length */
const struct sockaddr *src_sap; /* our address (optional) */
const size_t src_len; /* it's length */
const int noresvport; /* use non-priv port */
};
/*
......@@ -222,6 +223,7 @@ static struct nlm_host *nlm_lookup_host(struct nlm_lookup_host_info *ni)
host->h_nsmstate = 0; /* real NSM state */
host->h_nsmhandle = nsm;
host->h_server = ni->server;
host->h_noresvport = ni->noresvport;
hlist_add_head(&host->h_hash, chain);
INIT_LIST_HEAD(&host->h_lockowners);
spin_lock_init(&host->h_lock);
......@@ -272,6 +274,7 @@ nlm_destroy_host(struct nlm_host *host)
* @protocol: transport protocol to use
* @version: NLM protocol version
* @hostname: '\0'-terminated hostname of server
* @noresvport: 1 if non-privileged port should be used
*
* Returns an nlm_host structure that matches the passed-in
* [server address, transport protocol, NLM version, server hostname].
......@@ -281,7 +284,9 @@ nlm_destroy_host(struct nlm_host *host)
struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap,
const size_t salen,
const unsigned short protocol,
const u32 version, const char *hostname)
const u32 version,
const char *hostname,
int noresvport)
{
const struct sockaddr source = {
.sa_family = AF_UNSPEC,
......@@ -296,6 +301,7 @@ struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap,
.hostname_len = strlen(hostname),
.src_sap = &source,
.src_len = sizeof(source),
.noresvport = noresvport,
};
dprintk("lockd: %s(host='%s', vers=%u, proto=%s)\n", __func__,
......@@ -417,6 +423,8 @@ nlm_bind_host(struct nlm_host *host)
*/
if (!host->h_server)
args.flags |= RPC_CLNT_CREATE_HARDRTRY;
if (host->h_noresvport)
args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;
clnt = rpc_create(&args);
if (!IS_ERR(clnt))
......
......@@ -45,7 +45,7 @@
static struct svc_program nlmsvc_program;
struct nlmsvc_binding * nlmsvc_ops;
EXPORT_SYMBOL(nlmsvc_ops);
EXPORT_SYMBOL_GPL(nlmsvc_ops);
static DEFINE_MUTEX(nlmsvc_mutex);
static unsigned int nlmsvc_users;
......@@ -300,7 +300,7 @@ int lockd_up(void)
mutex_unlock(&nlmsvc_mutex);
return error;
}
EXPORT_SYMBOL(lockd_up);
EXPORT_SYMBOL_GPL(lockd_up);
/*
* Decrement the user count and bring down lockd if we're the last.
......@@ -329,7 +329,7 @@ lockd_down(void)
out:
mutex_unlock(&nlmsvc_mutex);
}
EXPORT_SYMBOL(lockd_down);
EXPORT_SYMBOL_GPL(lockd_down);
#ifdef CONFIG_SYSCTL
......
......@@ -16,6 +16,7 @@
#include <linux/mutex.h>
#include <linux/freezer.h>
#include <linux/kthread.h>
#include <linux/sunrpc/svcauth_gss.h>
#include <net/inet_sock.h>
......@@ -182,10 +183,34 @@ void nfs_callback_down(void)
mutex_unlock(&nfs_callback_mutex);
}
static int check_gss_callback_principal(struct nfs_client *clp,
struct svc_rqst *rqstp)
{
struct rpc_clnt *r = clp->cl_rpcclient;
char *p = svc_gss_principal(rqstp);
/*
* It might just be a normal user principal, in which case
* userspace won't bother to tell us the name at all.
*/
if (p == NULL)
return SVC_DENIED;
/* Expect a GSS_C_NT_HOSTBASED_NAME like "nfs@serverhostname" */
if (memcmp(p, "nfs@", 4) != 0)
return SVC_DENIED;
p += 4;
if (strcmp(p, r->cl_server) != 0)
return SVC_DENIED;
return SVC_OK;
}
static int nfs_callback_authenticate(struct svc_rqst *rqstp)
{
struct nfs_client *clp;
RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]);
int ret = SVC_OK;
/* Don't talk to strangers */
clp = nfs_find_client(svc_addr(rqstp), 4);
......@@ -194,21 +219,22 @@ static int nfs_callback_authenticate(struct svc_rqst *rqstp)
dprintk("%s: %s NFSv4 callback!\n", __func__,
svc_print_addr(rqstp, buf, sizeof(buf)));
nfs_put_client(clp);
switch (rqstp->rq_authop->flavour) {
case RPC_AUTH_NULL:
if (rqstp->rq_proc != CB_NULL)
return SVC_DENIED;
ret = SVC_DENIED;
break;
case RPC_AUTH_UNIX:
break;
case RPC_AUTH_GSS:
/* FIXME: RPCSEC_GSS handling? */
ret = check_gss_callback_principal(clp, rqstp);
break;
default:
return SVC_DENIED;
ret = SVC_DENIED;
}
return SVC_OK;
nfs_put_client(clp);
return ret;
}
/*
......
......@@ -143,7 +143,6 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_
clp->cl_proto = cl_init->proto;
#ifdef CONFIG_NFS_V4
init_rwsem(&clp->cl_sem);
INIT_LIST_HEAD(&clp->cl_delegations);
spin_lock_init(&clp->cl_lock);
INIT_DELAYED_WORK(&clp->cl_renewd, nfs4_renew_state);
......@@ -224,31 +223,54 @@ void nfs_put_client(struct nfs_client *clp)
}
}
static int nfs_sockaddr_match_ipaddr4(const struct sockaddr_in *sa1,
const struct sockaddr_in *sa2)
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
static const struct in6_addr *nfs_map_ipv4_addr(const struct sockaddr *sa, struct in6_addr *addr_mapped)
{
return sa1->sin_addr.s_addr == sa2->sin_addr.s_addr;
switch (sa->sa_family) {
default:
return NULL;
case AF_INET6:
return &((const struct sockaddr_in6 *)sa)->sin6_addr;
break;
case AF_INET:
ipv6_addr_set_v4mapped(((const struct sockaddr_in *)sa)->sin_addr.s_addr,
addr_mapped);
return addr_mapped;
}
}
static int nfs_sockaddr_match_ipaddr6(const struct sockaddr_in6 *sa1,
const struct sockaddr_in6 *sa2)
static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1,
const struct sockaddr *sa2)
{
const struct in6_addr *addr1;
const struct in6_addr *addr2;
struct in6_addr addr1_mapped;
struct in6_addr addr2_mapped;
addr1 = nfs_map_ipv4_addr(sa1, &addr1_mapped);
if (likely(addr1 != NULL)) {
addr2 = nfs_map_ipv4_addr(sa2, &addr2_mapped);
if (likely(addr2 != NULL))
return ipv6_addr_equal(addr1, addr2);
}
return 0;
}
#else
static int nfs_sockaddr_match_ipaddr4(const struct sockaddr_in *sa1,
const struct sockaddr_in *sa2)
{
return ipv6_addr_equal(&sa1->sin6_addr, &sa2->sin6_addr);
return sa1->sin_addr.s_addr == sa2->sin_addr.s_addr;
}
static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1,
const struct sockaddr *sa2)
{
switch (sa1->sa_family) {
case AF_INET:
return nfs_sockaddr_match_ipaddr4((const struct sockaddr_in *)sa1,
(const struct sockaddr_in *)sa2);
case AF_INET6:
return nfs_sockaddr_match_ipaddr6((const struct sockaddr_in6 *)sa1,
(const struct sockaddr_in6 *)sa2);
}
BUG();
if (unlikely(sa1->sa_family != AF_INET || sa2->sa_family != AF_INET))
return 0;
return nfs_sockaddr_match_ipaddr4((const struct sockaddr_in *)sa1,
(const struct sockaddr_in *)sa2);
}
#endif
/*
* Find a client by IP address and protocol version
......@@ -270,8 +292,6 @@ struct nfs_client *nfs_find_client(const struct sockaddr *addr, u32 nfsversion)
if (clp->rpc_ops->version != nfsversion)
continue;
if (addr->sa_family != clap->sa_family)
continue;
/* Match only the IP address, not the port number */
if (!nfs_sockaddr_match_ipaddr(addr, clap))
continue;
......@@ -305,8 +325,6 @@ struct nfs_client *nfs_find_client_next(struct nfs_client *clp)
if (clp->rpc_ops->version != nfsvers)
continue;
if (sap->sa_family != clap->sa_family)
continue;
/* Match only the IP address, not the port number */
if (!nfs_sockaddr_match_ipaddr(sap, clap))
continue;
......@@ -470,7 +488,7 @@ static void nfs_init_timeout_values(struct rpc_timeout *to, int proto,
static int nfs_create_rpc_client(struct nfs_client *clp,
const struct rpc_timeout *timeparms,
rpc_authflavor_t flavor,
int flags)
int discrtry, int noresvport)
{
struct rpc_clnt *clnt = NULL;
struct rpc_create_args args = {
......@@ -482,9 +500,13 @@ static int nfs_create_rpc_client(struct nfs_client *clp,
.program = &nfs_program,
.version = clp->rpc_ops->version,
.authflavor = flavor,
.flags = flags,
};
if (discrtry)
args.flags |= RPC_CLNT_CREATE_DISCRTRY;
if (noresvport)
args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;
if (!IS_ERR(clp->cl_rpcclient))
return 0;
......@@ -522,6 +544,8 @@ static int nfs_start_lockd(struct nfs_server *server)
.protocol = server->flags & NFS_MOUNT_TCP ?
IPPROTO_TCP : IPPROTO_UDP,
.nfs_version = clp->rpc_ops->version,
.noresvport = server->flags & NFS_MOUNT_NORESVPORT ?
1 : 0,
};
if (nlm_init.nfs_version > 3)
......@@ -623,7 +647,8 @@ static int nfs_init_client(struct nfs_client *clp,
* Create a client RPC handle for doing FSSTAT with UNIX auth only
* - RFC 2623, sec 2.3.2
*/
error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_UNIX, 0);
error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_UNIX,
0, data->flags & NFS_MOUNT_NORESVPORT);
if (error < 0)
goto error;
nfs_mark_client_ready(clp, NFS_CS_READY);
......@@ -965,7 +990,8 @@ struct nfs_server *nfs_create_server(const struct nfs_parsed_mount_data *data,
static int nfs4_init_client(struct nfs_client *clp,
const struct rpc_timeout *timeparms,
const char *ip_addr,
rpc_authflavor_t authflavour)
rpc_authflavor_t authflavour,
int flags)
{
int error;
......@@ -979,7 +1005,7 @@ static int nfs4_init_client(struct nfs_client *clp,
clp->rpc_ops = &nfs_v4_clientops;
error = nfs_create_rpc_client(clp, timeparms, authflavour,
RPC_CLNT_CREATE_DISCRTRY);
1, flags & NFS_MOUNT_NORESVPORT);
if (error < 0)
goto error;
memcpy(clp->cl_ipaddr, ip_addr, sizeof(clp->cl_ipaddr));
......@@ -1030,7 +1056,8 @@ static int nfs4_set_client(struct nfs_server *server,
error = PTR_ERR(clp);
goto error;
}
error = nfs4_init_client(clp, timeparms, ip_addr, authflavour);
error = nfs4_init_client(clp, timeparms, ip_addr, authflavour,
server->flags);
if (error < 0)
goto error_put;
......@@ -1059,6 +1086,10 @@ static int nfs4_init_server(struct nfs_server *server,
nfs_init_timeout_values(&timeparms, data->nfs_server.protocol,
data->timeo, data->retrans);
/* Initialise the client representation from the mount data */
server->flags = data->flags;
server->caps |= NFS_CAP_ATOMIC_OPEN;
/* Get a client record */
error = nfs4_set_client(server,
data->nfs_server.hostname,
......@@ -1071,10 +1102,6 @@ static int nfs4_init_server(struct nfs_server *server,
if (error < 0)
goto error;
/* Initialise the client representation from the mount data */
server->flags = data->flags;
server->caps |= NFS_CAP_ATOMIC_OPEN;
if (data->rsize)
server->rsize = nfs_block_size(data->rsize, NULL);
if (data->wsize)
......@@ -1177,6 +1204,10 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,
parent_server = NFS_SB(data->sb);
parent_client = parent_server->nfs_client;
/* Initialise the client representation from the parent server */
nfs_server_copy_userdata(server, parent_server);
server->caps |= NFS_CAP_ATOMIC_OPEN;
/* Get a client representation.
* Note: NFSv4 always uses TCP, */
error = nfs4_set_client(server, data->hostname,
......@@ -1189,10 +1220,6 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,
if (error < 0)
goto error;
/* Initialise the client representation from the parent server */
nfs_server_copy_userdata(server, parent_server);
server->caps |= NFS_CAP_ATOMIC_OPEN;
error = nfs_init_server_rpcclient(server, parent_server->client->cl_timeout, data->authflavor);
if (error < 0)
goto error;
......
This diff is collapsed.
......@@ -17,14 +17,20 @@ struct nfs_delegation {
struct rpc_cred *cred;
struct inode *inode;
nfs4_stateid stateid;
int type;
#define NFS_DELEGATION_NEED_RECLAIM 1
long flags;
fmode_t type;
loff_t maxsize;
__u64 change_attr;
unsigned long flags;
spinlock_t lock;
struct rcu_head rcu;
};
enum {
NFS_DELEGATION_NEED_RECLAIM = 0,
NFS_DELEGATION_RETURN,
NFS_DELEGATION_REFERENCED,
};
int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res);
void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res);
int nfs_inode_return_delegation(struct inode *inode);
......@@ -32,9 +38,11 @@ int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *s
void nfs_inode_return_delegation_noreclaim(struct inode *inode);
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_super_return_all_delegations(struct super_block *sb);
void nfs_expire_all_delegations(struct nfs_client *clp);
void nfs_expire_unreferenced_delegations(struct nfs_client *clp);
void nfs_handle_cb_pathdown(struct nfs_client *clp);
void nfs_client_return_marked_delegations(struct nfs_client *clp);
void nfs_delegation_mark_reclaim(struct nfs_client *clp);
void nfs_delegation_reap_unclaimed(struct nfs_client *clp);
......@@ -45,22 +53,11 @@ int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state
int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl);
int nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode);
static inline int nfs_have_delegation(struct inode *inode, int flags)
{
struct nfs_delegation *delegation;
int ret = 0;
flags &= FMODE_READ|FMODE_WRITE;
rcu_read_lock();
delegation = rcu_dereference(NFS_I(inode)->delegation);
if (delegation != NULL && (delegation->type & flags) == flags)
ret = 1;
rcu_read_unlock();
return ret;
}
void nfs_mark_delegation_referenced(struct nfs_delegation *delegation);
int nfs_have_delegation(struct inode *inode, fmode_t flags);
#else
static inline int nfs_have_delegation(struct inode *inode, int flags)
static inline int nfs_have_delegation(struct inode *inode, fmode_t flags)
{
return 0;
}
......
......@@ -799,6 +799,9 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd)
goto out_bad;
}
if (nfs_have_delegation(inode, FMODE_READ))
goto out_set_verifier;
/* Force a full look up iff the parent directory has changed */
if (!nfs_is_exclusive_create(dir, nd) && nfs_check_verifier(dir, dentry)) {
if (nfs_lookup_verify_inode(inode, nd))
......@@ -817,6 +820,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd)
if ((error = nfs_refresh_inode(inode, &fattr)) != 0)
goto out_bad;
out_set_verifier:
nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
out_valid:
dput(parent);
......@@ -973,7 +977,7 @@ struct dentry_operations nfs4_dentry_operations = {
* Use intent information to determine whether we need to substitute
* the NFSv4-style stateful OPEN for the LOOKUP call
*/
static int is_atomic_open(struct inode *dir, struct nameidata *nd)
static int is_atomic_open(struct nameidata *nd)
{
if (nd == NULL || nfs_lookup_check_intent(nd, LOOKUP_OPEN) == 0)
return 0;
......@@ -996,7 +1000,7 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry
dir->i_sb->s_id, dir->i_ino, dentry->d_name.name);
/* Check that we are indeed trying to open this file */
if (!is_atomic_open(dir, nd))
if (!is_atomic_open(nd))
goto no_open;
if (dentry->d_name.len > NFS_SERVER(dir)->namelen) {
......@@ -1047,10 +1051,10 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd)
struct inode *dir;
int openflags, ret = 0;
if (!is_atomic_open(nd))
goto no_open;
parent = dget_parent(dentry);
dir = parent->d_inode;
if (!is_atomic_open(dir, nd))
goto no_open;
/* We can't create new files in nfs_open_revalidate(), so we
* optimize away revalidation of negative dentries.
*/
......@@ -1062,11 +1066,11 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd)
/* NFS only supports OPEN on regular files */
if (!S_ISREG(inode->i_mode))
goto no_open;
goto no_open_dput;
openflags = nd->intent.open.flags;
/* We cannot do exclusive creation on a positive dentry */
if ((openflags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL))
goto no_open;
goto no_open_dput;
/* We can't create new files, or truncate existing ones here */
openflags &= ~(O_CREAT|O_TRUNC);
......@@ -1081,10 +1085,9 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd)
if (!ret)
d_drop(dentry);
return ret;
no_open:
no_open_dput:
dput(parent);
if (inode != NULL && nfs_have_delegation(inode, FMODE_READ))
return 1;
no_open:
return nfs_lookup_revalidate(dentry, nd);
}
#endif /* CONFIG_NFSV4 */
......@@ -1794,7 +1797,8 @@ static int nfs_access_get_cached(struct inode *inode, struct rpc_cred *cred, str
cache = nfs_access_search_rbtree(inode, cred);
if (cache == NULL)
goto out;
if (!time_in_range(jiffies, cache->jiffies, cache->jiffies + nfsi->attrtimeo))
if (!nfs_have_delegation(inode, FMODE_READ) &&
!time_in_range_open(jiffies, cache->jiffies, cache->jiffies + nfsi->attrtimeo))
goto out_stale;
res->jiffies = cache->jiffies;
res->cred = cache->cred;
......
......@@ -592,7 +592,7 @@ static void nfs_file_set_open_context(struct file *filp, struct nfs_open_context
/*
* Given an inode, search for an open context with the desired characteristics
*/
struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_cred *cred, int mode)
struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_cred *cred, fmode_t mode)
{
struct nfs_inode *nfsi = NFS_I(inode);
struct nfs_open_context *pos, *ctx = NULL;
......@@ -712,14 +712,7 @@ int nfs_attribute_timeout(struct inode *inode)
if (nfs_have_delegation(inode, FMODE_READ))
return 0;
/*
* Special case: if the attribute timeout is set to 0, then always
* treat the cache as having expired (unless holding
* a delegation).
*/
if (nfsi->attrtimeo == 0)
return 1;
return !time_in_range(jiffies, nfsi->read_cache_jiffies, nfsi->read_cache_jiffies + nfsi->attrtimeo);
return !time_in_range_open(jiffies, nfsi->read_cache_jiffies, nfsi->read_cache_jiffies + nfsi->attrtimeo);
}
/**
......@@ -1182,7 +1175,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
nfsi->attrtimeo_timestamp = now;
nfsi->attr_gencount = nfs_inc_attr_generation_counter();
} else {
if (!time_in_range(now, nfsi->attrtimeo_timestamp, nfsi->attrtimeo_timestamp + nfsi->attrtimeo)) {
if (!time_in_range_open(now, nfsi->attrtimeo_timestamp, nfsi->attrtimeo_timestamp + nfsi->attrtimeo)) {
if ((nfsi->attrtimeo <<= 1) > NFS_MAXATTRTIMEO(inode))
nfsi->attrtimeo = NFS_MAXATTRTIMEO(inode);
nfsi->attrtimeo_timestamp = now;
......
......@@ -63,6 +63,20 @@ struct nfs_parsed_mount_data {
struct security_mnt_opts lsm_opts;
};
/* mount_clnt.c */
struct nfs_mount_request {
struct sockaddr *sap;
size_t salen;
char *hostname;
char *dirpath;
u32 version;
unsigned short protocol;
struct nfs_fh *fh;
int noresvport;
};
extern int nfs_mount(struct nfs_mount_request *info);
/* client.c */
extern struct rpc_program nfs_program;
......
......@@ -29,47 +29,43 @@ struct mnt_fhstatus {
/**
* nfs_mount - Obtain an NFS file handle for the given host and path
* @addr: pointer to server's address
* @len: size of server's address
* @hostname: name of server host, or NULL
* @path: pointer to string containing export path to mount
* @version: mount version to use for this request
* @protocol: transport protocol to use for thie request
* @fh: pointer to location to place returned file handle
* @info: pointer to mount request arguments
*
* Uses default timeout parameters specified by underlying transport.
*/
int nfs_mount(struct sockaddr *addr, size_t len, char *hostname, char *path,
int version, int protocol, struct nfs_fh *fh)
int nfs_mount(struct nfs_mount_request *info)
{
struct mnt_fhstatus result = {
.fh = fh
.fh = info->fh
};
struct rpc_message msg = {
.rpc_argp = path,
.rpc_argp = info->dirpath,
.rpc_resp = &result,
};
struct rpc_create_args args = {
.protocol = protocol,
.address = addr,
.addrsize = len,
.servername = hostname,
.protocol = info->protocol,
.address = info->sap,
.addrsize = info->salen,
.servername = info->hostname,
.program = &mnt_program,
.version = version,
.version = info->version,
.authflavor = RPC_AUTH_UNIX,
.flags = 0,
};
struct rpc_clnt *mnt_clnt;
int status;
dprintk("NFS: sending MNT request for %s:%s\n",
(hostname ? hostname : "server"), path);
(info->hostname ? info->hostname : "server"),
info->dirpath);
if (info->noresvport)
args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;
mnt_clnt = rpc_create(&args);
if (IS_ERR(mnt_clnt))
goto out_clnt_err;
if (version == NFS_MNT3_VERSION)
if (info->version == NFS_MNT3_VERSION)
msg.rpc_proc = &mnt_clnt->cl_procinfo[MOUNTPROC3_MNT];
else
msg.rpc_proc = &mnt_clnt->cl_procinfo[MNTPROC_MNT];
......
......@@ -38,8 +38,12 @@ struct idmap;
((err) != NFSERR_NOFILEHANDLE))
enum nfs4_client_state {
NFS4CLNT_STATE_RECOVER = 0,
NFS4CLNT_MANAGER_RUNNING = 0,
NFS4CLNT_CHECK_LEASE,
NFS4CLNT_LEASE_EXPIRED,
NFS4CLNT_RECLAIM_REBOOT,
NFS4CLNT_RECLAIM_NOGRACE,
NFS4CLNT_DELEGRETURN,
};
/*
......@@ -90,12 +94,18 @@ struct nfs4_state_owner {
spinlock_t so_lock;
atomic_t so_count;
unsigned long so_flags;
struct list_head so_states;
struct list_head so_delegations;
struct nfs_seqid_counter so_seqid;
struct rpc_sequence so_sequence;
};
enum {
NFS_OWNER_RECLAIM_REBOOT,
NFS_OWNER_RECLAIM_NOGRACE
};
/*
* struct nfs4_state maintains the client-side state for a given
* (state_owner,inode) tuple (OPEN) or state_owner (LOCK).
......@@ -128,6 +138,8 @@ enum {
NFS_O_RDONLY_STATE, /* OPEN stateid has read-only state */
NFS_O_WRONLY_STATE, /* OPEN stateid has write-only state */
NFS_O_RDWR_STATE, /* OPEN stateid has read/write state */
NFS_STATE_RECLAIM_REBOOT, /* OPEN stateid server rebooted */
NFS_STATE_RECLAIM_NOGRACE, /* OPEN stateid needs to recover state */
};
struct nfs4_state {
......@@ -149,7 +161,7 @@ struct nfs4_state {
unsigned int n_rdonly; /* Number of read-only references */
unsigned int n_wronly; /* Number of write-only references */
unsigned int n_rdwr; /* Number of read/write references */
int state; /* State on the server (R,W, or RW) */
fmode_t state; /* State on the server (R,W, or RW) */
atomic_t count;
};
......@@ -157,9 +169,12 @@ struct nfs4_state {
struct nfs4_exception {
long timeout;
int retry;
struct nfs4_state *state;
};
struct nfs4_state_recovery_ops {
int owner_flag_bit;
int state_flag_bit;
int (*recover_open)(struct nfs4_state_owner *, struct nfs4_state *);
int (*recover_lock)(struct nfs4_state *, struct file_lock *);
};
......@@ -174,7 +189,6 @@ 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 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 *);
......@@ -187,7 +201,7 @@ extern int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name,
struct nfs4_fs_locations *fs_locations, struct page *page);
extern struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops;
extern struct nfs4_state_recovery_ops nfs4_network_partition_recovery_ops;
extern struct nfs4_state_recovery_ops nfs4_nograce_recovery_ops;
extern const u32 nfs4_fattr_bitmap[2];
extern const u32 nfs4_statfs_bitmap[2];
......@@ -202,16 +216,18 @@ extern void nfs4_kill_renewd(struct nfs_client *);
extern void nfs4_renew_state(struct work_struct *);
/* nfs4state.c */
struct rpc_cred *nfs4_get_renew_cred(struct nfs_client *clp);
struct rpc_cred *nfs4_get_renew_cred_locked(struct nfs_client *clp);
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 *);
extern struct nfs4_state * nfs4_get_open_state(struct inode *, struct nfs4_state_owner *);
extern void nfs4_put_open_state(struct nfs4_state *);
extern void nfs4_close_state(struct path *, struct nfs4_state *, mode_t);
extern void nfs4_close_sync(struct path *, struct nfs4_state *, mode_t);
extern void nfs4_state_set_mode_locked(struct nfs4_state *, mode_t);
extern void nfs4_close_state(struct path *, struct nfs4_state *, fmode_t);
extern void nfs4_close_sync(struct path *, struct nfs4_state *, fmode_t);
extern void nfs4_state_set_mode_locked(struct nfs4_state *, fmode_t);
extern void nfs4_schedule_state_recovery(struct nfs_client *);
extern void nfs4_schedule_state_manager(struct nfs_client *);
extern int nfs4_state_mark_reclaim_nograce(struct nfs_client *clp, struct nfs4_state *state);
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);
......
This diff is collapsed.
......@@ -65,7 +65,6 @@ nfs4_renew_state(struct work_struct *work)
long lease, timeout;
unsigned long last, now;
down_read(&clp->cl_sem);
dprintk("%s: start\n", __func__);
/* Are there any active superblocks? */
if (list_empty(&clp->cl_superblocks))
......@@ -77,17 +76,19 @@ nfs4_renew_state(struct work_struct *work)
timeout = (2 * lease) / 3 + (long)last - (long)now;
/* Are we close to a lease timeout? */
if (time_after(now, last + lease/3)) {
cred = nfs4_get_renew_cred(clp);
cred = nfs4_get_renew_cred_locked(clp);
spin_unlock(&clp->cl_lock);
if (cred == NULL) {
set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
spin_unlock(&clp->cl_lock);
if (list_empty(&clp->cl_delegations)) {
set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
goto out;
}
nfs_expire_all_delegations(clp);
goto out;
} else {
/* Queue an asynchronous RENEW. */
nfs4_proc_async_renew(clp, cred);
put_rpccred(cred);
}
spin_unlock(&clp->cl_lock);
/* Queue an asynchronous RENEW. */
nfs4_proc_async_renew(clp, cred);
put_rpccred(cred);
timeout = (2 * lease) / 3;
spin_lock(&clp->cl_lock);
} else
......@@ -100,12 +101,11 @@ nfs4_renew_state(struct work_struct *work)
cancel_delayed_work(&clp->cl_renewd);
schedule_delayed_work(&clp->cl_renewd, timeout);
spin_unlock(&clp->cl_lock);
nfs_expire_unreferenced_delegations(clp);
out:
up_read(&clp->cl_sem);
dprintk("%s: done\n", __func__);
}
/* Must be called with clp->cl_sem locked for writes */
void
nfs4_schedule_state_renewal(struct nfs_client *clp)
{
......
This diff is collapsed.
This diff is collapsed.
......@@ -86,6 +86,8 @@
#include <net/ipconfig.h>
#include <linux/parser.h>
#include "internal.h"
/* Define this to allow debugging output */
#undef NFSROOT_DEBUG
#define NFSDBG_FACILITY NFSDBG_ROOT
......@@ -100,7 +102,7 @@ static char nfs_root_name[256] __initdata = "";
static __be32 servaddr __initdata = 0;
/* Name of directory to mount */
static char nfs_path[NFS_MAXPATHLEN] __initdata = { 0, };
static char nfs_export_path[NFS_MAXPATHLEN] __initdata = { 0, };
/* NFS-related data */
static struct nfs_mount_data nfs_data __initdata = { 0, };/* NFS mount info */
......@@ -312,7 +314,7 @@ static int __init root_nfs_name(char *name)
printk(KERN_ERR "Root-NFS: Pathname for remote directory too long.\n");
return -1;
}
sprintf(nfs_path, buf, cp);
sprintf(nfs_export_path, buf, cp);
return 1;
}
......@@ -340,7 +342,7 @@ static int __init root_nfs_addr(void)
static void __init root_nfs_print(void)
{
printk(KERN_NOTICE "Root-NFS: Mounting %s on server %s as root\n",
nfs_path, nfs_data.hostname);
nfs_export_path, nfs_data.hostname);
printk(KERN_NOTICE "Root-NFS: rsize = %d, wsize = %d, timeo = %d, retrans = %d\n",
nfs_data.rsize, nfs_data.wsize, nfs_data.timeo, nfs_data.retrans);
printk(KERN_NOTICE "Root-NFS: acreg (min,max) = (%d,%d), acdir (min,max) = (%d,%d)\n",
......@@ -485,18 +487,23 @@ static int __init root_nfs_get_handle(void)
{
struct nfs_fh fh;
struct sockaddr_in sin;
struct nfs_mount_request request = {
.sap = (struct sockaddr *)&sin,
.salen = sizeof(sin),
.dirpath = nfs_export_path,
.version = (nfs_data.flags & NFS_MOUNT_VER3) ?
NFS_MNT3_VERSION : NFS_MNT_VERSION,
.protocol = (nfs_data.flags & NFS_MOUNT_TCP) ?
XPRT_TRANSPORT_TCP : XPRT_TRANSPORT_UDP,
.fh = &fh,
};
int status;
int protocol = (nfs_data.flags & NFS_MOUNT_TCP) ?
XPRT_TRANSPORT_TCP : XPRT_TRANSPORT_UDP;
int version = (nfs_data.flags & NFS_MOUNT_VER3) ?
NFS_MNT3_VERSION : NFS_MNT_VERSION;
set_sockaddr(&sin, servaddr, htons(mount_port));
status = nfs_mount((struct sockaddr *) &sin, sizeof(sin), NULL,
nfs_path, version, protocol, &fh);
status = nfs_mount(&request);
if (status < 0)
printk(KERN_ERR "Root-NFS: Server returned error %d "
"while mounting %s\n", status, nfs_path);
"while mounting %s\n", status, nfs_export_path);
else {
nfs_data.root.size = fh.size;
memcpy(nfs_data.root.data, fh.data, fh.size);
......
......@@ -533,12 +533,6 @@ readpage_async_filler(void *data, struct page *page)
unsigned int len;
int error;
error = nfs_wb_page(inode, page);
if (error)
goto out_unlock;
if (PageUptodate(page))
goto out_unlock;
len = nfs_page_length(page);
if (len == 0)
return nfs_return_empty_page(page);
......
This diff is collapsed.
......@@ -29,8 +29,8 @@
MODULE_LICENSE("GPL");
EXPORT_SYMBOL(nfsacl_encode);
EXPORT_SYMBOL(nfsacl_decode);
EXPORT_SYMBOL_GPL(nfsacl_encode);
EXPORT_SYMBOL_GPL(nfsacl_decode);
struct nfsacl_encode_desc {
struct xdr_array2_desc desc;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -41,6 +41,7 @@ struct nlmclnt_initdata {
size_t addrlen;
unsigned short protocol;
u32 nfs_version;
int noresvport;
};
/*
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -124,6 +124,8 @@ struct nfs4_client {
nfs4_verifier cl_verifier; /* generated by client */
time_t cl_time; /* time of last lease renewal */
__be32 cl_addr; /* client ipaddress */
u32 cl_flavor; /* setclientid pseudoflavor */
char *cl_principal; /* setclientid principal name */
struct svc_cred cl_cred; /* setclientid principal */
clientid_t cl_clientid; /* generated by server */
nfs4_verifier cl_confirm; /* generated by server */
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment