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 branch 'for-3.8' of git://linux-nfs.org/~bfields/linux
Pull nfsd update from Bruce Fields:
"Included this time:
- more nfsd containerization work from Stanislav Kinsbursky: we're
not quite there yet, but should be by 3.9.
- NFSv4.1 progress: implementation of basic backchannel security
negotiation and the mandatory BACKCHANNEL_CTL operation. See
http://wiki.linux-nfs.org/wiki/index.php/Server_4.0_and_4.1_issues
for remaining TODO's
- Fixes for some bugs that could be triggered by unusual compounds.
Our xdr code wasn't designed with v4 compounds in mind, and it
shows. A more thorough rewrite is still a todo.
- If you've ever seen "RPC: multiple fragments per record not
supported" logged while using some sort of odd userland NFS client,
that should now be fixed.
- Further work from Jeff Layton on our mechanism for storing
information about NFSv4 clients across reboots.
- Further work from Bryan Schumaker on his fault-injection mechanism
(which allows us to discard selective NFSv4 state, to excercise
rarely-taken recovery code paths in the client.)
- The usual mix of miscellaneous bugs and cleanup.
Thanks to everyone who tested or contributed this cycle."
* 'for-3.8' of git://linux-nfs.org/~bfields/linux: (111 commits)
nfsd4: don't leave freed stateid hashed
nfsd4: free_stateid can use the current stateid
nfsd4: cleanup: replace rq_resused count by rq_next_page pointer
nfsd: warn on odd reply state in nfsd_vfs_read
nfsd4: fix oops on unusual readlike compound
nfsd4: disable zero-copy on non-final read ops
svcrpc: fix some printks
NFSD: Correct the size calculation in fault_inject_write
NFSD: Pass correct buffer size to rpc_ntop
nfsd: pass proper net to nfsd_destroy() from NFSd kthreads
nfsd: simplify service shutdown
nfsd: replace boolean nfsd_up flag by users counter
nfsd: simplify NFSv4 state init and shutdown
nfsd: introduce helpers for generic resources init and shutdown
nfsd: make NFSd service structure allocated per net
nfsd: make NFSd service boot time per-net
nfsd: per-net NFSd up flag introduced
nfsd: move per-net startup code to separated function
nfsd: pass net to __write_ports() and down
nfsd: pass net to nfsd_set_nrthreads()
...
This commit is contained in:
@@ -39,21 +39,10 @@ interoperability problems with future clients. Known issues:
|
||||
from a linux client are possible, but we aren't really
|
||||
conformant with the spec (for example, we don't use kerberos
|
||||
on the backchannel correctly).
|
||||
- Incomplete backchannel support: incomplete backchannel gss
|
||||
support and no support for BACKCHANNEL_CTL mean that
|
||||
callbacks (hence delegations and layouts) may not be
|
||||
available and clients confused by the incomplete
|
||||
implementation may fail.
|
||||
- We do not support SSV, which provides security for shared
|
||||
client-server state (thus preventing unauthorized tampering
|
||||
with locks and opens, for example). It is mandatory for
|
||||
servers to support this, though no clients use it yet.
|
||||
- Mandatory operations which we do not support, such as
|
||||
DESTROY_CLIENTID, are not currently used by clients, but will be
|
||||
(and the spec recommends their uses in common cases), and
|
||||
clients should not be expected to know how to recover from the
|
||||
case where they are not supported. This will eventually cause
|
||||
interoperability failures.
|
||||
|
||||
In addition, some limitations are inherited from the current NFSv4
|
||||
implementation:
|
||||
@@ -89,7 +78,7 @@ Operations
|
||||
| | MNI | or OPT) | |
|
||||
+----------------------+------------+--------------+----------------+
|
||||
| ACCESS | REQ | | Section 18.1 |
|
||||
NS | BACKCHANNEL_CTL | REQ | | Section 18.33 |
|
||||
I | BACKCHANNEL_CTL | REQ | | Section 18.33 |
|
||||
I | BIND_CONN_TO_SESSION | REQ | | Section 18.34 |
|
||||
| CLOSE | REQ | | Section 18.2 |
|
||||
| COMMIT | REQ | | Section 18.3 |
|
||||
@@ -99,7 +88,7 @@ NS*| DELEGPURGE | OPT | FDELG (REQ) | Section 18.5 |
|
||||
| DELEGRETURN | OPT | FDELG, | Section 18.6 |
|
||||
| | | DDELG, pNFS | |
|
||||
| | | (REQ) | |
|
||||
NS | DESTROY_CLIENTID | REQ | | Section 18.50 |
|
||||
I | DESTROY_CLIENTID | REQ | | Section 18.50 |
|
||||
I | DESTROY_SESSION | REQ | | Section 18.37 |
|
||||
I | EXCHANGE_ID | REQ | | Section 18.35 |
|
||||
I | FREE_STATEID | REQ | | Section 18.38 |
|
||||
@@ -192,7 +181,6 @@ EXCHANGE_ID:
|
||||
|
||||
CREATE_SESSION:
|
||||
* backchannel attributes are ignored
|
||||
* backchannel security parameters are ignored
|
||||
|
||||
SEQUENCE:
|
||||
* no support for dynamic slot table renegotiation (optional)
|
||||
@@ -202,7 +190,7 @@ Nonstandard compound limitations:
|
||||
ca_maxrequestsize request and a ca_maxresponsesize reply, so we may
|
||||
fail to live up to the promise we made in CREATE_SESSION fore channel
|
||||
negotiation.
|
||||
* No more than one IO operation (read, write, readdir) allowed per
|
||||
compound.
|
||||
* No more than one read-like operation allowed per compound; encoding
|
||||
replies that cross page boundaries (except for read data) not handled.
|
||||
|
||||
See also http://wiki.linux-nfs.org/wiki/index.php/Server_4.0_and_4.1_issues.
|
||||
|
||||
+2
-2
@@ -322,10 +322,10 @@ static int export_encode_fh(struct inode *inode, struct fid *fid,
|
||||
|
||||
if (parent && (len < 4)) {
|
||||
*max_len = 4;
|
||||
return 255;
|
||||
return FILEID_INVALID;
|
||||
} else if (len < 2) {
|
||||
*max_len = 2;
|
||||
return 255;
|
||||
return FILEID_INVALID;
|
||||
}
|
||||
|
||||
len = 2;
|
||||
|
||||
+1
-1
@@ -52,7 +52,7 @@ static long do_sys_name_to_handle(struct path *path,
|
||||
handle_bytes = handle_dwords * sizeof(u32);
|
||||
handle->handle_bytes = handle_bytes;
|
||||
if ((handle->handle_bytes > f_handle.handle_bytes) ||
|
||||
(retval == 255) || (retval == -ENOSPC)) {
|
||||
(retval == FILEID_INVALID) || (retval == -ENOSPC)) {
|
||||
/* As per old exportfs_encode_fh documentation
|
||||
* we could return ENOSPC to indicate overflow
|
||||
* But file system returned 255 always. So handle
|
||||
|
||||
+98
-15
@@ -8,61 +8,144 @@
|
||||
#include <linux/fs.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/nsproxy.h>
|
||||
#include <linux/sunrpc/clnt.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#include "state.h"
|
||||
#include "fault_inject.h"
|
||||
#include "netns.h"
|
||||
|
||||
struct nfsd_fault_inject_op {
|
||||
char *file;
|
||||
void (*func)(u64);
|
||||
u64 (*forget)(struct nfs4_client *, u64);
|
||||
u64 (*print)(struct nfs4_client *, u64);
|
||||
};
|
||||
|
||||
static struct nfsd_fault_inject_op inject_ops[] = {
|
||||
{
|
||||
.file = "forget_clients",
|
||||
.func = nfsd_forget_clients,
|
||||
.forget = nfsd_forget_client,
|
||||
.print = nfsd_print_client,
|
||||
},
|
||||
{
|
||||
.file = "forget_locks",
|
||||
.func = nfsd_forget_locks,
|
||||
.forget = nfsd_forget_client_locks,
|
||||
.print = nfsd_print_client_locks,
|
||||
},
|
||||
{
|
||||
.file = "forget_openowners",
|
||||
.func = nfsd_forget_openowners,
|
||||
.forget = nfsd_forget_client_openowners,
|
||||
.print = nfsd_print_client_openowners,
|
||||
},
|
||||
{
|
||||
.file = "forget_delegations",
|
||||
.func = nfsd_forget_delegations,
|
||||
.forget = nfsd_forget_client_delegations,
|
||||
.print = nfsd_print_client_delegations,
|
||||
},
|
||||
{
|
||||
.file = "recall_delegations",
|
||||
.func = nfsd_recall_delegations,
|
||||
.forget = nfsd_recall_client_delegations,
|
||||
.print = nfsd_print_client_delegations,
|
||||
},
|
||||
};
|
||||
|
||||
static long int NUM_INJECT_OPS = sizeof(inject_ops) / sizeof(struct nfsd_fault_inject_op);
|
||||
static struct dentry *debug_dir;
|
||||
|
||||
static int nfsd_inject_set(void *op_ptr, u64 val)
|
||||
static void nfsd_inject_set(struct nfsd_fault_inject_op *op, u64 val)
|
||||
{
|
||||
struct nfsd_fault_inject_op *op = op_ptr;
|
||||
u64 count = 0;
|
||||
|
||||
if (val == 0)
|
||||
printk(KERN_INFO "NFSD Fault Injection: %s (all)", op->file);
|
||||
else
|
||||
printk(KERN_INFO "NFSD Fault Injection: %s (n = %llu)", op->file, val);
|
||||
|
||||
op->func(val);
|
||||
return 0;
|
||||
nfs4_lock_state();
|
||||
count = nfsd_for_n_state(val, op->forget);
|
||||
nfs4_unlock_state();
|
||||
printk(KERN_INFO "NFSD: %s: found %llu", op->file, count);
|
||||
}
|
||||
|
||||
static int nfsd_inject_get(void *data, u64 *val)
|
||||
static void nfsd_inject_set_client(struct nfsd_fault_inject_op *op,
|
||||
struct sockaddr_storage *addr,
|
||||
size_t addr_size)
|
||||
{
|
||||
*val = 0;
|
||||
return 0;
|
||||
char buf[INET6_ADDRSTRLEN];
|
||||
struct nfs4_client *clp;
|
||||
u64 count;
|
||||
|
||||
nfs4_lock_state();
|
||||
clp = nfsd_find_client(addr, addr_size);
|
||||
if (clp) {
|
||||
count = op->forget(clp, 0);
|
||||
rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf));
|
||||
printk(KERN_INFO "NFSD [%s]: Client %s had %llu state object(s)\n", op->file, buf, count);
|
||||
}
|
||||
nfs4_unlock_state();
|
||||
}
|
||||
|
||||
DEFINE_SIMPLE_ATTRIBUTE(fops_nfsd, nfsd_inject_get, nfsd_inject_set, "%llu\n");
|
||||
static void nfsd_inject_get(struct nfsd_fault_inject_op *op, u64 *val)
|
||||
{
|
||||
nfs4_lock_state();
|
||||
*val = nfsd_for_n_state(0, op->print);
|
||||
nfs4_unlock_state();
|
||||
}
|
||||
|
||||
static ssize_t fault_inject_read(struct file *file, char __user *buf,
|
||||
size_t len, loff_t *ppos)
|
||||
{
|
||||
static u64 val;
|
||||
char read_buf[25];
|
||||
size_t size, ret;
|
||||
loff_t pos = *ppos;
|
||||
|
||||
if (!pos)
|
||||
nfsd_inject_get(file->f_dentry->d_inode->i_private, &val);
|
||||
size = scnprintf(read_buf, sizeof(read_buf), "%llu\n", val);
|
||||
|
||||
if (pos < 0)
|
||||
return -EINVAL;
|
||||
if (pos >= size || !len)
|
||||
return 0;
|
||||
if (len > size - pos)
|
||||
len = size - pos;
|
||||
ret = copy_to_user(buf, read_buf + pos, len);
|
||||
if (ret == len)
|
||||
return -EFAULT;
|
||||
len -= ret;
|
||||
*ppos = pos + len;
|
||||
return len;
|
||||
}
|
||||
|
||||
static ssize_t fault_inject_write(struct file *file, const char __user *buf,
|
||||
size_t len, loff_t *ppos)
|
||||
{
|
||||
char write_buf[INET6_ADDRSTRLEN];
|
||||
size_t size = min(sizeof(write_buf) - 1, len);
|
||||
struct net *net = current->nsproxy->net_ns;
|
||||
struct sockaddr_storage sa;
|
||||
u64 val;
|
||||
|
||||
if (copy_from_user(write_buf, buf, size))
|
||||
return -EFAULT;
|
||||
write_buf[size] = '\0';
|
||||
|
||||
size = rpc_pton(net, write_buf, size, (struct sockaddr *)&sa, sizeof(sa));
|
||||
if (size > 0)
|
||||
nfsd_inject_set_client(file->f_dentry->d_inode->i_private, &sa, size);
|
||||
else {
|
||||
val = simple_strtoll(write_buf, NULL, 0);
|
||||
nfsd_inject_set(file->f_dentry->d_inode->i_private, val);
|
||||
}
|
||||
return len; /* on success, claim we got the whole input */
|
||||
}
|
||||
|
||||
static const struct file_operations fops_nfsd = {
|
||||
.owner = THIS_MODULE,
|
||||
.read = fault_inject_read,
|
||||
.write = fault_inject_write,
|
||||
};
|
||||
|
||||
void nfsd_fault_inject_cleanup(void)
|
||||
{
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2011 Bryan Schumaker <bjschuma@netapp.com>
|
||||
*
|
||||
* Function definitions for fault injection
|
||||
*/
|
||||
|
||||
#ifndef LINUX_NFSD_FAULT_INJECT_H
|
||||
#define LINUX_NFSD_FAULT_INJECT_H
|
||||
|
||||
#ifdef CONFIG_NFSD_FAULT_INJECTION
|
||||
int nfsd_fault_inject_init(void);
|
||||
void nfsd_fault_inject_cleanup(void);
|
||||
void nfsd_forget_clients(u64);
|
||||
void nfsd_forget_locks(u64);
|
||||
void nfsd_forget_openowners(u64);
|
||||
void nfsd_forget_delegations(u64);
|
||||
void nfsd_recall_delegations(u64);
|
||||
#else /* CONFIG_NFSD_FAULT_INJECTION */
|
||||
static inline int nfsd_fault_inject_init(void) { return 0; }
|
||||
static inline void nfsd_fault_inject_cleanup(void) {}
|
||||
static inline void nfsd_forget_clients(u64 num) {}
|
||||
static inline void nfsd_forget_locks(u64 num) {}
|
||||
static inline void nfsd_forget_openowners(u64 num) {}
|
||||
static inline void nfsd_forget_delegations(u64 num) {}
|
||||
static inline void nfsd_recall_delegations(u64 num) {}
|
||||
#endif /* CONFIG_NFSD_FAULT_INJECTION */
|
||||
|
||||
#endif /* LINUX_NFSD_FAULT_INJECT_H */
|
||||
@@ -24,7 +24,18 @@
|
||||
#include <net/net_namespace.h>
|
||||
#include <net/netns/generic.h>
|
||||
|
||||
/* Hash tables for nfs4_clientid state */
|
||||
#define CLIENT_HASH_BITS 4
|
||||
#define CLIENT_HASH_SIZE (1 << CLIENT_HASH_BITS)
|
||||
#define CLIENT_HASH_MASK (CLIENT_HASH_SIZE - 1)
|
||||
|
||||
#define LOCKOWNER_INO_HASH_BITS 8
|
||||
#define LOCKOWNER_INO_HASH_SIZE (1 << LOCKOWNER_INO_HASH_BITS)
|
||||
|
||||
#define SESSION_HASH_SIZE 512
|
||||
|
||||
struct cld_net;
|
||||
struct nfsd4_client_tracking_ops;
|
||||
|
||||
struct nfsd_net {
|
||||
struct cld_net *cld_net;
|
||||
@@ -38,7 +49,62 @@ struct nfsd_net {
|
||||
struct lock_manager nfsd4_manager;
|
||||
bool grace_ended;
|
||||
time_t boot_time;
|
||||
|
||||
/*
|
||||
* reclaim_str_hashtbl[] holds known client info from previous reset/reboot
|
||||
* used in reboot/reset lease grace period processing
|
||||
*
|
||||
* conf_id_hashtbl[], and conf_name_tree hold confirmed
|
||||
* setclientid_confirmed info.
|
||||
*
|
||||
* unconf_str_hastbl[] and unconf_name_tree hold unconfirmed
|
||||
* setclientid info.
|
||||
*/
|
||||
struct list_head *reclaim_str_hashtbl;
|
||||
int reclaim_str_hashtbl_size;
|
||||
struct list_head *conf_id_hashtbl;
|
||||
struct rb_root conf_name_tree;
|
||||
struct list_head *unconf_id_hashtbl;
|
||||
struct rb_root unconf_name_tree;
|
||||
struct list_head *ownerstr_hashtbl;
|
||||
struct list_head *lockowner_ino_hashtbl;
|
||||
struct list_head *sessionid_hashtbl;
|
||||
/*
|
||||
* client_lru holds client queue ordered by nfs4_client.cl_time
|
||||
* for lease renewal.
|
||||
*
|
||||
* close_lru holds (open) stateowner queue ordered by nfs4_stateowner.so_time
|
||||
* for last close replay.
|
||||
*
|
||||
* All of the above fields are protected by the client_mutex.
|
||||
*/
|
||||
struct list_head client_lru;
|
||||
struct list_head close_lru;
|
||||
|
||||
struct delayed_work laundromat_work;
|
||||
|
||||
/* client_lock protects the client lru list and session hash table */
|
||||
spinlock_t client_lock;
|
||||
|
||||
struct file *rec_file;
|
||||
bool in_grace;
|
||||
struct nfsd4_client_tracking_ops *client_tracking_ops;
|
||||
|
||||
time_t nfsd4_lease;
|
||||
time_t nfsd4_grace;
|
||||
|
||||
bool nfsd_net_up;
|
||||
|
||||
/*
|
||||
* Time of server startup
|
||||
*/
|
||||
struct timeval nfssvc_boot;
|
||||
|
||||
struct svc_serv *nfsd_serv;
|
||||
};
|
||||
|
||||
/* Simple check to find out if a given net was properly initialized */
|
||||
#define nfsd_netns_ready(nn) ((nn)->sessionid_hashtbl)
|
||||
|
||||
extern int nfsd_net_id;
|
||||
#endif /* __NFSD_NETNS_H__ */
|
||||
|
||||
+1
-1
@@ -253,7 +253,7 @@ static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p,
|
||||
(resp->mask & NFS_ACL) ? resp->acl_access : NULL,
|
||||
(resp->mask & NFS_DFACL) ? resp->acl_default : NULL);
|
||||
while (w > 0) {
|
||||
if (!rqstp->rq_respages[rqstp->rq_resused++])
|
||||
if (!*(rqstp->rq_next_page++))
|
||||
return 0;
|
||||
w -= PAGE_SIZE;
|
||||
}
|
||||
|
||||
+1
-1
@@ -184,7 +184,7 @@ static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p,
|
||||
(resp->mask & NFS_ACL) ? resp->acl_access : NULL,
|
||||
(resp->mask & NFS_DFACL) ? resp->acl_default : NULL);
|
||||
while (w > 0) {
|
||||
if (!rqstp->rq_respages[rqstp->rq_resused++])
|
||||
if (!*(rqstp->rq_next_page++))
|
||||
return 0;
|
||||
w -= PAGE_SIZE;
|
||||
}
|
||||
|
||||
+3
-3
@@ -460,7 +460,7 @@ nfsd3_proc_readdirplus(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp,
|
||||
__be32 nfserr;
|
||||
int count = 0;
|
||||
loff_t offset;
|
||||
int i;
|
||||
struct page **p;
|
||||
caddr_t page_addr = NULL;
|
||||
|
||||
dprintk("nfsd: READDIR+(3) %s %d bytes at %d\n",
|
||||
@@ -484,8 +484,8 @@ nfsd3_proc_readdirplus(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp,
|
||||
&resp->common,
|
||||
nfs3svc_encode_entry_plus);
|
||||
memcpy(resp->verf, argp->verf, 8);
|
||||
for (i=1; i<rqstp->rq_resused ; i++) {
|
||||
page_addr = page_address(rqstp->rq_respages[i]);
|
||||
for (p = rqstp->rq_respages + 1; p < rqstp->rq_next_page; p++) {
|
||||
page_addr = page_address(*p);
|
||||
|
||||
if (((caddr_t)resp->buffer >= page_addr) &&
|
||||
((caddr_t)resp->buffer < page_addr + PAGE_SIZE)) {
|
||||
|
||||
+26
-21
@@ -7,8 +7,10 @@
|
||||
*/
|
||||
|
||||
#include <linux/namei.h>
|
||||
#include <linux/sunrpc/svc_xprt.h>
|
||||
#include "xdr3.h"
|
||||
#include "auth.h"
|
||||
#include "netns.h"
|
||||
|
||||
#define NFSDDBG_FACILITY NFSDDBG_XDR
|
||||
|
||||
@@ -323,7 +325,7 @@ nfs3svc_decode_readargs(struct svc_rqst *rqstp, __be32 *p,
|
||||
struct nfsd3_readargs *args)
|
||||
{
|
||||
unsigned int len;
|
||||
int v,pn;
|
||||
int v;
|
||||
u32 max_blocksize = svc_max_payload(rqstp);
|
||||
|
||||
if (!(p = decode_fh(p, &args->fh)))
|
||||
@@ -338,8 +340,9 @@ nfs3svc_decode_readargs(struct svc_rqst *rqstp, __be32 *p,
|
||||
/* set up the kvec */
|
||||
v=0;
|
||||
while (len > 0) {
|
||||
pn = rqstp->rq_resused++;
|
||||
rqstp->rq_vec[v].iov_base = page_address(rqstp->rq_respages[pn]);
|
||||
struct page *p = *(rqstp->rq_next_page++);
|
||||
|
||||
rqstp->rq_vec[v].iov_base = page_address(p);
|
||||
rqstp->rq_vec[v].iov_len = len < PAGE_SIZE? len : PAGE_SIZE;
|
||||
len -= rqstp->rq_vec[v].iov_len;
|
||||
v++;
|
||||
@@ -461,8 +464,7 @@ nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p,
|
||||
len = ntohl(*p++);
|
||||
if (len == 0 || len > NFS3_MAXPATHLEN || len >= PAGE_SIZE)
|
||||
return 0;
|
||||
args->tname = new =
|
||||
page_address(rqstp->rq_respages[rqstp->rq_resused++]);
|
||||
args->tname = new = page_address(*(rqstp->rq_next_page++));
|
||||
args->tlen = len;
|
||||
/* first copy and check from the first page */
|
||||
old = (char*)p;
|
||||
@@ -533,8 +535,7 @@ nfs3svc_decode_readlinkargs(struct svc_rqst *rqstp, __be32 *p,
|
||||
{
|
||||
if (!(p = decode_fh(p, &args->fh)))
|
||||
return 0;
|
||||
args->buffer =
|
||||
page_address(rqstp->rq_respages[rqstp->rq_resused++]);
|
||||
args->buffer = page_address(*(rqstp->rq_next_page++));
|
||||
|
||||
return xdr_argsize_check(rqstp, p);
|
||||
}
|
||||
@@ -565,8 +566,7 @@ nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p,
|
||||
if (args->count > PAGE_SIZE)
|
||||
args->count = PAGE_SIZE;
|
||||
|
||||
args->buffer =
|
||||
page_address(rqstp->rq_respages[rqstp->rq_resused++]);
|
||||
args->buffer = page_address(*(rqstp->rq_next_page++));
|
||||
|
||||
return xdr_argsize_check(rqstp, p);
|
||||
}
|
||||
@@ -575,7 +575,7 @@ int
|
||||
nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, __be32 *p,
|
||||
struct nfsd3_readdirargs *args)
|
||||
{
|
||||
int len, pn;
|
||||
int len;
|
||||
u32 max_blocksize = svc_max_payload(rqstp);
|
||||
|
||||
if (!(p = decode_fh(p, &args->fh)))
|
||||
@@ -590,9 +590,9 @@ nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, __be32 *p,
|
||||
args->count = len;
|
||||
|
||||
while (len > 0) {
|
||||
pn = rqstp->rq_resused++;
|
||||
struct page *p = *(rqstp->rq_next_page++);
|
||||
if (!args->buffer)
|
||||
args->buffer = page_address(rqstp->rq_respages[pn]);
|
||||
args->buffer = page_address(p);
|
||||
len -= PAGE_SIZE;
|
||||
}
|
||||
|
||||
@@ -720,12 +720,14 @@ int
|
||||
nfs3svc_encode_writeres(struct svc_rqst *rqstp, __be32 *p,
|
||||
struct nfsd3_writeres *resp)
|
||||
{
|
||||
struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
|
||||
|
||||
p = encode_wcc_data(rqstp, p, &resp->fh);
|
||||
if (resp->status == 0) {
|
||||
*p++ = htonl(resp->count);
|
||||
*p++ = htonl(resp->committed);
|
||||
*p++ = htonl(nfssvc_boot.tv_sec);
|
||||
*p++ = htonl(nfssvc_boot.tv_usec);
|
||||
*p++ = htonl(nn->nfssvc_boot.tv_sec);
|
||||
*p++ = htonl(nn->nfssvc_boot.tv_usec);
|
||||
}
|
||||
return xdr_ressize_check(rqstp, p);
|
||||
}
|
||||
@@ -876,7 +878,7 @@ encode_entry(struct readdir_cd *ccd, const char *name, int namlen,
|
||||
common);
|
||||
__be32 *p = cd->buffer;
|
||||
caddr_t curr_page_addr = NULL;
|
||||
int pn; /* current page number */
|
||||
struct page ** page;
|
||||
int slen; /* string (name) length */
|
||||
int elen; /* estimated entry length in words */
|
||||
int num_entry_words = 0; /* actual number of words */
|
||||
@@ -913,8 +915,9 @@ encode_entry(struct readdir_cd *ccd, const char *name, int namlen,
|
||||
}
|
||||
|
||||
/* determine which page in rq_respages[] we are currently filling */
|
||||
for (pn=1; pn < cd->rqstp->rq_resused; pn++) {
|
||||
curr_page_addr = page_address(cd->rqstp->rq_respages[pn]);
|
||||
for (page = cd->rqstp->rq_respages + 1;
|
||||
page < cd->rqstp->rq_next_page; page++) {
|
||||
curr_page_addr = page_address(*page);
|
||||
|
||||
if (((caddr_t)cd->buffer >= curr_page_addr) &&
|
||||
((caddr_t)cd->buffer < curr_page_addr + PAGE_SIZE))
|
||||
@@ -929,14 +932,14 @@ encode_entry(struct readdir_cd *ccd, const char *name, int namlen,
|
||||
if (plus)
|
||||
p = encode_entryplus_baggage(cd, p, name, namlen);
|
||||
num_entry_words = p - cd->buffer;
|
||||
} else if (cd->rqstp->rq_respages[pn+1] != NULL) {
|
||||
} else if (*(page+1) != NULL) {
|
||||
/* temporarily encode entry into next page, then move back to
|
||||
* current and next page in rq_respages[] */
|
||||
__be32 *p1, *tmp;
|
||||
int len1, len2;
|
||||
|
||||
/* grab next page for temporary storage of entry */
|
||||
p1 = tmp = page_address(cd->rqstp->rq_respages[pn+1]);
|
||||
p1 = tmp = page_address(*(page+1));
|
||||
|
||||
p1 = encode_entry_baggage(cd, p1, name, namlen, ino);
|
||||
|
||||
@@ -1082,11 +1085,13 @@ int
|
||||
nfs3svc_encode_commitres(struct svc_rqst *rqstp, __be32 *p,
|
||||
struct nfsd3_commitres *resp)
|
||||
{
|
||||
struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
|
||||
|
||||
p = encode_wcc_data(rqstp, p, &resp->fh);
|
||||
/* Write verifier */
|
||||
if (resp->status == 0) {
|
||||
*p++ = htonl(nfssvc_boot.tv_sec);
|
||||
*p++ = htonl(nfssvc_boot.tv_usec);
|
||||
*p++ = htonl(nn->nfssvc_boot.tv_sec);
|
||||
*p++ = htonl(nn->nfssvc_boot.tv_usec);
|
||||
}
|
||||
return xdr_ressize_check(rqstp, p);
|
||||
}
|
||||
|
||||
+48
-21
@@ -36,6 +36,7 @@
|
||||
#include <linux/slab.h>
|
||||
#include "nfsd.h"
|
||||
#include "state.h"
|
||||
#include "netns.h"
|
||||
|
||||
#define NFSDDBG_FACILITY NFSDDBG_PROC
|
||||
|
||||
@@ -625,20 +626,46 @@ static const struct rpc_program cb_program = {
|
||||
.pipe_dir_name = "nfsd4_cb",
|
||||
};
|
||||
|
||||
static int max_cb_time(void)
|
||||
static int max_cb_time(struct net *net)
|
||||
{
|
||||
return max(nfsd4_lease/10, (time_t)1) * HZ;
|
||||
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
||||
return max(nn->nfsd4_lease/10, (time_t)1) * HZ;
|
||||
}
|
||||
|
||||
static struct rpc_cred *callback_cred;
|
||||
|
||||
int set_callback_cred(void)
|
||||
{
|
||||
if (callback_cred)
|
||||
return 0;
|
||||
callback_cred = rpc_lookup_machine_cred("nfs");
|
||||
if (!callback_cred)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct rpc_cred *get_backchannel_cred(struct nfs4_client *clp, struct rpc_clnt *client, struct nfsd4_session *ses)
|
||||
{
|
||||
if (clp->cl_minorversion == 0) {
|
||||
return get_rpccred(callback_cred);
|
||||
} else {
|
||||
struct rpc_auth *auth = client->cl_auth;
|
||||
struct auth_cred acred = {};
|
||||
|
||||
acred.uid = ses->se_cb_sec.uid;
|
||||
acred.gid = ses->se_cb_sec.gid;
|
||||
return auth->au_ops->lookup_cred(client->cl_auth, &acred, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *conn, struct nfsd4_session *ses)
|
||||
{
|
||||
struct rpc_timeout timeparms = {
|
||||
.to_initval = max_cb_time(),
|
||||
.to_initval = max_cb_time(clp->net),
|
||||
.to_retries = 0,
|
||||
};
|
||||
struct rpc_create_args args = {
|
||||
.net = &init_net,
|
||||
.net = clp->net,
|
||||
.address = (struct sockaddr *) &conn->cb_addr,
|
||||
.addrsize = conn->cb_addrlen,
|
||||
.saddress = (struct sockaddr *) &conn->cb_saddr,
|
||||
@@ -648,6 +675,7 @@ static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *c
|
||||
.flags = (RPC_CLNT_CREATE_NOPING | RPC_CLNT_CREATE_QUIET),
|
||||
};
|
||||
struct rpc_clnt *client;
|
||||
struct rpc_cred *cred;
|
||||
|
||||
if (clp->cl_minorversion == 0) {
|
||||
if (!clp->cl_cred.cr_principal &&
|
||||
@@ -666,7 +694,7 @@ static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *c
|
||||
args.bc_xprt = conn->cb_xprt;
|
||||
args.prognumber = clp->cl_cb_session->se_cb_prog;
|
||||
args.protocol = XPRT_TRANSPORT_BC_TCP;
|
||||
args.authflavor = RPC_AUTH_UNIX;
|
||||
args.authflavor = ses->se_cb_sec.flavor;
|
||||
}
|
||||
/* Create RPC client */
|
||||
client = rpc_create(&args);
|
||||
@@ -675,9 +703,14 @@ static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *c
|
||||
PTR_ERR(client));
|
||||
return PTR_ERR(client);
|
||||
}
|
||||
cred = get_backchannel_cred(clp, client, ses);
|
||||
if (IS_ERR(cred)) {
|
||||
rpc_shutdown_client(client);
|
||||
return PTR_ERR(cred);
|
||||
}
|
||||
clp->cl_cb_client = client;
|
||||
clp->cl_cb_cred = cred;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static void warn_no_callback_path(struct nfs4_client *clp, int reason)
|
||||
@@ -714,18 +747,6 @@ static const struct rpc_call_ops nfsd4_cb_probe_ops = {
|
||||
.rpc_call_done = nfsd4_cb_probe_done,
|
||||
};
|
||||
|
||||
static struct rpc_cred *callback_cred;
|
||||
|
||||
int set_callback_cred(void)
|
||||
{
|
||||
if (callback_cred)
|
||||
return 0;
|
||||
callback_cred = rpc_lookup_machine_cred("nfs");
|
||||
if (!callback_cred)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct workqueue_struct *callback_wq;
|
||||
|
||||
static void run_nfsd4_cb(struct nfsd4_callback *cb)
|
||||
@@ -743,7 +764,6 @@ static void do_probe_callback(struct nfs4_client *clp)
|
||||
cb->cb_msg.rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL];
|
||||
cb->cb_msg.rpc_argp = NULL;
|
||||
cb->cb_msg.rpc_resp = NULL;
|
||||
cb->cb_msg.rpc_cred = callback_cred;
|
||||
|
||||
cb->cb_ops = &nfsd4_cb_probe_ops;
|
||||
|
||||
@@ -962,6 +982,8 @@ static void nfsd4_process_cb_update(struct nfsd4_callback *cb)
|
||||
if (clp->cl_cb_client) {
|
||||
rpc_shutdown_client(clp->cl_cb_client);
|
||||
clp->cl_cb_client = NULL;
|
||||
put_rpccred(clp->cl_cb_cred);
|
||||
clp->cl_cb_cred = NULL;
|
||||
}
|
||||
if (clp->cl_cb_conn.cb_xprt) {
|
||||
svc_xprt_put(clp->cl_cb_conn.cb_xprt);
|
||||
@@ -995,7 +1017,7 @@ static void nfsd4_process_cb_update(struct nfsd4_callback *cb)
|
||||
run_nfsd4_cb(cb);
|
||||
}
|
||||
|
||||
void nfsd4_do_callback_rpc(struct work_struct *w)
|
||||
static void nfsd4_do_callback_rpc(struct work_struct *w)
|
||||
{
|
||||
struct nfsd4_callback *cb = container_of(w, struct nfsd4_callback, cb_work);
|
||||
struct nfs4_client *clp = cb->cb_clp;
|
||||
@@ -1010,10 +1032,16 @@ void nfsd4_do_callback_rpc(struct work_struct *w)
|
||||
nfsd4_release_cb(cb);
|
||||
return;
|
||||
}
|
||||
cb->cb_msg.rpc_cred = clp->cl_cb_cred;
|
||||
rpc_call_async(clnt, &cb->cb_msg, RPC_TASK_SOFT | RPC_TASK_SOFTCONN,
|
||||
cb->cb_ops, cb);
|
||||
}
|
||||
|
||||
void nfsd4_init_callback(struct nfsd4_callback *cb)
|
||||
{
|
||||
INIT_WORK(&cb->cb_work, nfsd4_do_callback_rpc);
|
||||
}
|
||||
|
||||
void nfsd4_cb_recall(struct nfs4_delegation *dp)
|
||||
{
|
||||
struct nfsd4_callback *cb = &dp->dl_recall;
|
||||
@@ -1025,7 +1053,6 @@ void nfsd4_cb_recall(struct nfs4_delegation *dp)
|
||||
cb->cb_msg.rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL];
|
||||
cb->cb_msg.rpc_argp = cb;
|
||||
cb->cb_msg.rpc_resp = cb;
|
||||
cb->cb_msg.rpc_cred = callback_cred;
|
||||
|
||||
cb->cb_ops = &nfsd4_cb_recall_ops;
|
||||
|
||||
|
||||
+61
-13
@@ -40,6 +40,7 @@
|
||||
#include "xdr4.h"
|
||||
#include "vfs.h"
|
||||
#include "current_stateid.h"
|
||||
#include "netns.h"
|
||||
|
||||
#define NFSDDBG_FACILITY NFSDDBG_PROC
|
||||
|
||||
@@ -194,6 +195,7 @@ static __be32
|
||||
do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
|
||||
{
|
||||
struct svc_fh *resfh;
|
||||
int accmode;
|
||||
__be32 status;
|
||||
|
||||
resfh = kmalloc(sizeof(struct svc_fh), GFP_KERNEL);
|
||||
@@ -253,9 +255,10 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o
|
||||
/* set reply cache */
|
||||
fh_copy_shallow(&open->op_openowner->oo_owner.so_replay.rp_openfh,
|
||||
&resfh->fh_handle);
|
||||
if (!open->op_created)
|
||||
status = do_open_permission(rqstp, resfh, open,
|
||||
NFSD_MAY_NOP);
|
||||
accmode = NFSD_MAY_NOP;
|
||||
if (open->op_created)
|
||||
accmode |= NFSD_MAY_OWNER_OVERRIDE;
|
||||
status = do_open_permission(rqstp, resfh, open, accmode);
|
||||
set_change_info(&open->op_cinfo, current_fh);
|
||||
fh_dup2(current_fh, resfh);
|
||||
out:
|
||||
@@ -304,6 +307,8 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
{
|
||||
__be32 status;
|
||||
struct nfsd4_compoundres *resp;
|
||||
struct net *net = SVC_NET(rqstp);
|
||||
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
||||
|
||||
dprintk("NFSD: nfsd4_open filename %.*s op_openowner %p\n",
|
||||
(int)open->op_fname.len, open->op_fname.data,
|
||||
@@ -331,7 +336,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
|
||||
/* check seqid for replay. set nfs4_owner */
|
||||
resp = rqstp->rq_resp;
|
||||
status = nfsd4_process_open1(&resp->cstate, open);
|
||||
status = nfsd4_process_open1(&resp->cstate, open, nn);
|
||||
if (status == nfserr_replay_me) {
|
||||
struct nfs4_replay *rp = &open->op_openowner->oo_owner.so_replay;
|
||||
fh_put(&cstate->current_fh);
|
||||
@@ -354,10 +359,10 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
/* Openowner is now set, so sequence id will get bumped. Now we need
|
||||
* these checks before we do any creates: */
|
||||
status = nfserr_grace;
|
||||
if (locks_in_grace(SVC_NET(rqstp)) && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS)
|
||||
if (locks_in_grace(net) && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS)
|
||||
goto out;
|
||||
status = nfserr_no_grace;
|
||||
if (!locks_in_grace(SVC_NET(rqstp)) && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
|
||||
if (!locks_in_grace(net) && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
|
||||
goto out;
|
||||
|
||||
switch (open->op_claim_type) {
|
||||
@@ -370,7 +375,9 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
break;
|
||||
case NFS4_OPEN_CLAIM_PREVIOUS:
|
||||
open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED;
|
||||
status = nfs4_check_open_reclaim(&open->op_clientid, cstate->minorversion);
|
||||
status = nfs4_check_open_reclaim(&open->op_clientid,
|
||||
cstate->minorversion,
|
||||
nn);
|
||||
if (status)
|
||||
goto out;
|
||||
case NFS4_OPEN_CLAIM_FH:
|
||||
@@ -490,12 +497,13 @@ nfsd4_access(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
&access->ac_supported);
|
||||
}
|
||||
|
||||
static void gen_boot_verifier(nfs4_verifier *verifier)
|
||||
static void gen_boot_verifier(nfs4_verifier *verifier, struct net *net)
|
||||
{
|
||||
__be32 verf[2];
|
||||
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
||||
|
||||
verf[0] = (__be32)nfssvc_boot.tv_sec;
|
||||
verf[1] = (__be32)nfssvc_boot.tv_usec;
|
||||
verf[0] = (__be32)nn->nfssvc_boot.tv_sec;
|
||||
verf[1] = (__be32)nn->nfssvc_boot.tv_usec;
|
||||
memcpy(verifier->data, verf, sizeof(verifier->data));
|
||||
}
|
||||
|
||||
@@ -503,7 +511,7 @@ static __be32
|
||||
nfsd4_commit(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
struct nfsd4_commit *commit)
|
||||
{
|
||||
gen_boot_verifier(&commit->co_verf);
|
||||
gen_boot_verifier(&commit->co_verf, SVC_NET(rqstp));
|
||||
return nfsd_commit(rqstp, &cstate->current_fh, commit->co_offset,
|
||||
commit->co_count);
|
||||
}
|
||||
@@ -684,6 +692,17 @@ nfsd4_read(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
if (read->rd_offset >= OFFSET_MAX)
|
||||
return nfserr_inval;
|
||||
|
||||
/*
|
||||
* If we do a zero copy read, then a client will see read data
|
||||
* that reflects the state of the file *after* performing the
|
||||
* following compound.
|
||||
*
|
||||
* To ensure proper ordering, we therefore turn off zero copy if
|
||||
* the client wants us to do more in this compound:
|
||||
*/
|
||||
if (!nfsd4_last_compound_op(rqstp))
|
||||
rqstp->rq_splice_ok = false;
|
||||
|
||||
nfs4_lock_state();
|
||||
/* check stateid */
|
||||
if ((status = nfs4_preprocess_stateid_op(SVC_NET(rqstp),
|
||||
@@ -876,6 +895,24 @@ out:
|
||||
return status;
|
||||
}
|
||||
|
||||
static int fill_in_write_vector(struct kvec *vec, struct nfsd4_write *write)
|
||||
{
|
||||
int i = 1;
|
||||
int buflen = write->wr_buflen;
|
||||
|
||||
vec[0].iov_base = write->wr_head.iov_base;
|
||||
vec[0].iov_len = min_t(int, buflen, write->wr_head.iov_len);
|
||||
buflen -= vec[0].iov_len;
|
||||
|
||||
while (buflen) {
|
||||
vec[i].iov_base = page_address(write->wr_pagelist[i - 1]);
|
||||
vec[i].iov_len = min_t(int, PAGE_SIZE, buflen);
|
||||
buflen -= vec[i].iov_len;
|
||||
i++;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
static __be32
|
||||
nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
struct nfsd4_write *write)
|
||||
@@ -884,6 +921,7 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
struct file *filp = NULL;
|
||||
__be32 status = nfs_ok;
|
||||
unsigned long cnt;
|
||||
int nvecs;
|
||||
|
||||
/* no need to check permission - this will be done in nfsd_write() */
|
||||
|
||||
@@ -904,10 +942,13 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
|
||||
cnt = write->wr_buflen;
|
||||
write->wr_how_written = write->wr_stable_how;
|
||||
gen_boot_verifier(&write->wr_verifier);
|
||||
gen_boot_verifier(&write->wr_verifier, SVC_NET(rqstp));
|
||||
|
||||
nvecs = fill_in_write_vector(rqstp->rq_vec, write);
|
||||
WARN_ON_ONCE(nvecs > ARRAY_SIZE(rqstp->rq_vec));
|
||||
|
||||
status = nfsd_write(rqstp, &cstate->current_fh, filp,
|
||||
write->wr_offset, rqstp->rq_vec, write->wr_vlen,
|
||||
write->wr_offset, rqstp->rq_vec, nvecs,
|
||||
&cnt, &write->wr_how_written);
|
||||
if (filp)
|
||||
fput(filp);
|
||||
@@ -1666,6 +1707,12 @@ static struct nfsd4_operation nfsd4_ops[] = {
|
||||
.op_name = "OP_EXCHANGE_ID",
|
||||
.op_rsize_bop = (nfsd4op_rsize)nfsd4_exchange_id_rsize,
|
||||
},
|
||||
[OP_BACKCHANNEL_CTL] = {
|
||||
.op_func = (nfsd4op_func)nfsd4_backchannel_ctl,
|
||||
.op_flags = ALLOWED_WITHOUT_FH | OP_MODIFIES_SOMETHING,
|
||||
.op_name = "OP_BACKCHANNEL_CTL",
|
||||
.op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
|
||||
},
|
||||
[OP_BIND_CONN_TO_SESSION] = {
|
||||
.op_func = (nfsd4op_func)nfsd4_bind_conn_to_session,
|
||||
.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP
|
||||
@@ -1719,6 +1766,7 @@ static struct nfsd4_operation nfsd4_ops[] = {
|
||||
.op_func = (nfsd4op_func)nfsd4_free_stateid,
|
||||
.op_flags = ALLOWED_WITHOUT_FH | OP_MODIFIES_SOMETHING,
|
||||
.op_name = "OP_FREE_STATEID",
|
||||
.op_get_currentstateid = (stateid_getter)nfsd4_get_freestateid,
|
||||
.op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
|
||||
},
|
||||
};
|
||||
|
||||
+461
-100
File diff suppressed because it is too large
Load Diff
+615
-440
File diff suppressed because it is too large
Load Diff
+156
-168
File diff suppressed because it is too large
Load Diff
+59
-41
@@ -19,7 +19,7 @@
|
||||
#include "idmap.h"
|
||||
#include "nfsd.h"
|
||||
#include "cache.h"
|
||||
#include "fault_inject.h"
|
||||
#include "state.h"
|
||||
#include "netns.h"
|
||||
|
||||
/*
|
||||
@@ -186,9 +186,6 @@ static struct file_operations supported_enctypes_ops = {
|
||||
};
|
||||
#endif /* CONFIG_SUNRPC_GSS or CONFIG_SUNRPC_GSS_MODULE */
|
||||
|
||||
extern int nfsd_pool_stats_open(struct inode *inode, struct file *file);
|
||||
extern int nfsd_pool_stats_release(struct inode *inode, struct file *file);
|
||||
|
||||
static const struct file_operations pool_stats_operations = {
|
||||
.open = nfsd_pool_stats_open,
|
||||
.read = seq_read,
|
||||
@@ -399,6 +396,8 @@ static ssize_t write_threads(struct file *file, char *buf, size_t size)
|
||||
{
|
||||
char *mesg = buf;
|
||||
int rv;
|
||||
struct net *net = &init_net;
|
||||
|
||||
if (size > 0) {
|
||||
int newthreads;
|
||||
rv = get_int(&mesg, &newthreads);
|
||||
@@ -406,11 +405,11 @@ static ssize_t write_threads(struct file *file, char *buf, size_t size)
|
||||
return rv;
|
||||
if (newthreads < 0)
|
||||
return -EINVAL;
|
||||
rv = nfsd_svc(newthreads);
|
||||
rv = nfsd_svc(newthreads, net);
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
} else
|
||||
rv = nfsd_nrthreads();
|
||||
rv = nfsd_nrthreads(net);
|
||||
|
||||
return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%d\n", rv);
|
||||
}
|
||||
@@ -448,9 +447,10 @@ static ssize_t write_pool_threads(struct file *file, char *buf, size_t size)
|
||||
int len;
|
||||
int npools;
|
||||
int *nthreads;
|
||||
struct net *net = &init_net;
|
||||
|
||||
mutex_lock(&nfsd_mutex);
|
||||
npools = nfsd_nrpools();
|
||||
npools = nfsd_nrpools(net);
|
||||
if (npools == 0) {
|
||||
/*
|
||||
* NFS is shut down. The admin can start it by
|
||||
@@ -478,12 +478,12 @@ static ssize_t write_pool_threads(struct file *file, char *buf, size_t size)
|
||||
if (nthreads[i] < 0)
|
||||
goto out_free;
|
||||
}
|
||||
rv = nfsd_set_nrthreads(i, nthreads);
|
||||
rv = nfsd_set_nrthreads(i, nthreads, net);
|
||||
if (rv)
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
rv = nfsd_get_nrthreads(npools, nthreads);
|
||||
rv = nfsd_get_nrthreads(npools, nthreads, net);
|
||||
if (rv)
|
||||
goto out_free;
|
||||
|
||||
@@ -510,11 +510,13 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size)
|
||||
unsigned minor;
|
||||
ssize_t tlen = 0;
|
||||
char *sep;
|
||||
struct net *net = &init_net;
|
||||
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
||||
|
||||
if (size>0) {
|
||||
if (nfsd_serv)
|
||||
if (nn->nfsd_serv)
|
||||
/* Cannot change versions without updating
|
||||
* nfsd_serv->sv_xdrsize, and reallocing
|
||||
* nn->nfsd_serv->sv_xdrsize, and reallocing
|
||||
* rq_argp and rq_resp
|
||||
*/
|
||||
return -EBUSY;
|
||||
@@ -645,11 +647,13 @@ static ssize_t write_versions(struct file *file, char *buf, size_t size)
|
||||
* Zero-length write. Return a list of NFSD's current listener
|
||||
* transports.
|
||||
*/
|
||||
static ssize_t __write_ports_names(char *buf)
|
||||
static ssize_t __write_ports_names(char *buf, struct net *net)
|
||||
{
|
||||
if (nfsd_serv == NULL)
|
||||
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
||||
|
||||
if (nn->nfsd_serv == NULL)
|
||||
return 0;
|
||||
return svc_xprt_names(nfsd_serv, buf, SIMPLE_TRANSACTION_LIMIT);
|
||||
return svc_xprt_names(nn->nfsd_serv, buf, SIMPLE_TRANSACTION_LIMIT);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -657,28 +661,28 @@ static ssize_t __write_ports_names(char *buf)
|
||||
* a socket of a supported family/protocol, and we use it as an
|
||||
* nfsd listener.
|
||||
*/
|
||||
static ssize_t __write_ports_addfd(char *buf)
|
||||
static ssize_t __write_ports_addfd(char *buf, struct net *net)
|
||||
{
|
||||
char *mesg = buf;
|
||||
int fd, err;
|
||||
struct net *net = &init_net;
|
||||
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
||||
|
||||
err = get_int(&mesg, &fd);
|
||||
if (err != 0 || fd < 0)
|
||||
return -EINVAL;
|
||||
|
||||
err = nfsd_create_serv();
|
||||
err = nfsd_create_serv(net);
|
||||
if (err != 0)
|
||||
return err;
|
||||
|
||||
err = svc_addsock(nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT);
|
||||
err = svc_addsock(nn->nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT);
|
||||
if (err < 0) {
|
||||
nfsd_destroy(net);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Decrease the count, but don't shut down the service */
|
||||
nfsd_serv->sv_nrthreads--;
|
||||
nn->nfsd_serv->sv_nrthreads--;
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -686,12 +690,12 @@ static ssize_t __write_ports_addfd(char *buf)
|
||||
* A transport listener is added by writing it's transport name and
|
||||
* a port number.
|
||||
*/
|
||||
static ssize_t __write_ports_addxprt(char *buf)
|
||||
static ssize_t __write_ports_addxprt(char *buf, struct net *net)
|
||||
{
|
||||
char transport[16];
|
||||
struct svc_xprt *xprt;
|
||||
int port, err;
|
||||
struct net *net = &init_net;
|
||||
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
||||
|
||||
if (sscanf(buf, "%15s %5u", transport, &port) != 2)
|
||||
return -EINVAL;
|
||||
@@ -699,25 +703,25 @@ static ssize_t __write_ports_addxprt(char *buf)
|
||||
if (port < 1 || port > USHRT_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
err = nfsd_create_serv();
|
||||
err = nfsd_create_serv(net);
|
||||
if (err != 0)
|
||||
return err;
|
||||
|
||||
err = svc_create_xprt(nfsd_serv, transport, net,
|
||||
err = svc_create_xprt(nn->nfsd_serv, transport, net,
|
||||
PF_INET, port, SVC_SOCK_ANONYMOUS);
|
||||
if (err < 0)
|
||||
goto out_err;
|
||||
|
||||
err = svc_create_xprt(nfsd_serv, transport, net,
|
||||
err = svc_create_xprt(nn->nfsd_serv, transport, net,
|
||||
PF_INET6, port, SVC_SOCK_ANONYMOUS);
|
||||
if (err < 0 && err != -EAFNOSUPPORT)
|
||||
goto out_close;
|
||||
|
||||
/* Decrease the count, but don't shut down the service */
|
||||
nfsd_serv->sv_nrthreads--;
|
||||
nn->nfsd_serv->sv_nrthreads--;
|
||||
return 0;
|
||||
out_close:
|
||||
xprt = svc_find_xprt(nfsd_serv, transport, net, PF_INET, port);
|
||||
xprt = svc_find_xprt(nn->nfsd_serv, transport, net, PF_INET, port);
|
||||
if (xprt != NULL) {
|
||||
svc_close_xprt(xprt);
|
||||
svc_xprt_put(xprt);
|
||||
@@ -727,16 +731,17 @@ out_err:
|
||||
return err;
|
||||
}
|
||||
|
||||
static ssize_t __write_ports(struct file *file, char *buf, size_t size)
|
||||
static ssize_t __write_ports(struct file *file, char *buf, size_t size,
|
||||
struct net *net)
|
||||
{
|
||||
if (size == 0)
|
||||
return __write_ports_names(buf);
|
||||
return __write_ports_names(buf, net);
|
||||
|
||||
if (isdigit(buf[0]))
|
||||
return __write_ports_addfd(buf);
|
||||
return __write_ports_addfd(buf, net);
|
||||
|
||||
if (isalpha(buf[0]))
|
||||
return __write_ports_addxprt(buf);
|
||||
return __write_ports_addxprt(buf, net);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -787,9 +792,10 @@ static ssize_t __write_ports(struct file *file, char *buf, size_t size)
|
||||
static ssize_t write_ports(struct file *file, char *buf, size_t size)
|
||||
{
|
||||
ssize_t rv;
|
||||
struct net *net = &init_net;
|
||||
|
||||
mutex_lock(&nfsd_mutex);
|
||||
rv = __write_ports(file, buf, size);
|
||||
rv = __write_ports(file, buf, size, net);
|
||||
mutex_unlock(&nfsd_mutex);
|
||||
return rv;
|
||||
}
|
||||
@@ -821,6 +827,9 @@ int nfsd_max_blksize;
|
||||
static ssize_t write_maxblksize(struct file *file, char *buf, size_t size)
|
||||
{
|
||||
char *mesg = buf;
|
||||
struct net *net = &init_net;
|
||||
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
||||
|
||||
if (size > 0) {
|
||||
int bsize;
|
||||
int rv = get_int(&mesg, &bsize);
|
||||
@@ -835,7 +844,7 @@ static ssize_t write_maxblksize(struct file *file, char *buf, size_t size)
|
||||
bsize = NFSSVC_MAXBLKSIZE;
|
||||
bsize &= ~(1024-1);
|
||||
mutex_lock(&nfsd_mutex);
|
||||
if (nfsd_serv) {
|
||||
if (nn->nfsd_serv) {
|
||||
mutex_unlock(&nfsd_mutex);
|
||||
return -EBUSY;
|
||||
}
|
||||
@@ -848,13 +857,14 @@ static ssize_t write_maxblksize(struct file *file, char *buf, size_t size)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NFSD_V4
|
||||
static ssize_t __nfsd4_write_time(struct file *file, char *buf, size_t size, time_t *time)
|
||||
static ssize_t __nfsd4_write_time(struct file *file, char *buf, size_t size,
|
||||
time_t *time, struct nfsd_net *nn)
|
||||
{
|
||||
char *mesg = buf;
|
||||
int rv, i;
|
||||
|
||||
if (size > 0) {
|
||||
if (nfsd_serv)
|
||||
if (nn->nfsd_serv)
|
||||
return -EBUSY;
|
||||
rv = get_int(&mesg, &i);
|
||||
if (rv)
|
||||
@@ -879,12 +889,13 @@ static ssize_t __nfsd4_write_time(struct file *file, char *buf, size_t size, tim
|
||||
return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%ld\n", *time);
|
||||
}
|
||||
|
||||
static ssize_t nfsd4_write_time(struct file *file, char *buf, size_t size, time_t *time)
|
||||
static ssize_t nfsd4_write_time(struct file *file, char *buf, size_t size,
|
||||
time_t *time, struct nfsd_net *nn)
|
||||
{
|
||||
ssize_t rv;
|
||||
|
||||
mutex_lock(&nfsd_mutex);
|
||||
rv = __nfsd4_write_time(file, buf, size, time);
|
||||
rv = __nfsd4_write_time(file, buf, size, time, nn);
|
||||
mutex_unlock(&nfsd_mutex);
|
||||
return rv;
|
||||
}
|
||||
@@ -912,7 +923,8 @@ static ssize_t nfsd4_write_time(struct file *file, char *buf, size_t size, time_
|
||||
*/
|
||||
static ssize_t write_leasetime(struct file *file, char *buf, size_t size)
|
||||
{
|
||||
return nfsd4_write_time(file, buf, size, &nfsd4_lease);
|
||||
struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id);
|
||||
return nfsd4_write_time(file, buf, size, &nn->nfsd4_lease, nn);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -927,17 +939,19 @@ static ssize_t write_leasetime(struct file *file, char *buf, size_t size)
|
||||
*/
|
||||
static ssize_t write_gracetime(struct file *file, char *buf, size_t size)
|
||||
{
|
||||
return nfsd4_write_time(file, buf, size, &nfsd4_grace);
|
||||
struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id);
|
||||
return nfsd4_write_time(file, buf, size, &nn->nfsd4_grace, nn);
|
||||
}
|
||||
|
||||
static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size)
|
||||
static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size,
|
||||
struct nfsd_net *nn)
|
||||
{
|
||||
char *mesg = buf;
|
||||
char *recdir;
|
||||
int len, status;
|
||||
|
||||
if (size > 0) {
|
||||
if (nfsd_serv)
|
||||
if (nn->nfsd_serv)
|
||||
return -EBUSY;
|
||||
if (size > PATH_MAX || buf[size-1] != '\n')
|
||||
return -EINVAL;
|
||||
@@ -981,9 +995,10 @@ static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size)
|
||||
static ssize_t write_recoverydir(struct file *file, char *buf, size_t size)
|
||||
{
|
||||
ssize_t rv;
|
||||
struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id);
|
||||
|
||||
mutex_lock(&nfsd_mutex);
|
||||
rv = __write_recoverydir(file, buf, size);
|
||||
rv = __write_recoverydir(file, buf, size, nn);
|
||||
mutex_unlock(&nfsd_mutex);
|
||||
return rv;
|
||||
}
|
||||
@@ -1063,6 +1078,7 @@ int nfsd_net_id;
|
||||
static __net_init int nfsd_init_net(struct net *net)
|
||||
{
|
||||
int retval;
|
||||
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
||||
|
||||
retval = nfsd_export_init(net);
|
||||
if (retval)
|
||||
@@ -1070,6 +1086,8 @@ static __net_init int nfsd_init_net(struct net *net)
|
||||
retval = nfsd_idmap_init(net);
|
||||
if (retval)
|
||||
goto out_idmap_error;
|
||||
nn->nfsd4_lease = 90; /* default lease time */
|
||||
nn->nfsd4_grace = 90;
|
||||
return 0;
|
||||
|
||||
out_idmap_error:
|
||||
|
||||
+11
-25
@@ -55,7 +55,6 @@ extern struct svc_version nfsd_version2, nfsd_version3,
|
||||
nfsd_version4;
|
||||
extern u32 nfsd_supported_minorversion;
|
||||
extern struct mutex nfsd_mutex;
|
||||
extern struct svc_serv *nfsd_serv;
|
||||
extern spinlock_t nfsd_drc_lock;
|
||||
extern unsigned int nfsd_drc_max_mem;
|
||||
extern unsigned int nfsd_drc_mem_used;
|
||||
@@ -65,26 +64,17 @@ extern const struct seq_operations nfs_exports_op;
|
||||
/*
|
||||
* Function prototypes.
|
||||
*/
|
||||
int nfsd_svc(int nrservs);
|
||||
int nfsd_svc(int nrservs, struct net *net);
|
||||
int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp);
|
||||
|
||||
int nfsd_nrthreads(void);
|
||||
int nfsd_nrpools(void);
|
||||
int nfsd_get_nrthreads(int n, int *);
|
||||
int nfsd_set_nrthreads(int n, int *);
|
||||
int nfsd_nrthreads(struct net *);
|
||||
int nfsd_nrpools(struct net *);
|
||||
int nfsd_get_nrthreads(int n, int *, struct net *);
|
||||
int nfsd_set_nrthreads(int n, int *, struct net *);
|
||||
int nfsd_pool_stats_open(struct inode *, struct file *);
|
||||
int nfsd_pool_stats_release(struct inode *, struct file *);
|
||||
|
||||
static inline void nfsd_destroy(struct net *net)
|
||||
{
|
||||
int destroy = (nfsd_serv->sv_nrthreads == 1);
|
||||
|
||||
if (destroy)
|
||||
svc_shutdown_net(nfsd_serv, net);
|
||||
svc_destroy(nfsd_serv);
|
||||
if (destroy)
|
||||
nfsd_serv = NULL;
|
||||
}
|
||||
void nfsd_destroy(struct net *net);
|
||||
|
||||
#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
|
||||
#ifdef CONFIG_NFSD_V2_ACL
|
||||
@@ -103,7 +93,7 @@ enum vers_op {NFSD_SET, NFSD_CLEAR, NFSD_TEST, NFSD_AVAIL };
|
||||
int nfsd_vers(int vers, enum vers_op change);
|
||||
int nfsd_minorversion(u32 minorversion, enum vers_op change);
|
||||
void nfsd_reset_versions(void);
|
||||
int nfsd_create_serv(void);
|
||||
int nfsd_create_serv(struct net *net);
|
||||
|
||||
extern int nfsd_max_blksize;
|
||||
|
||||
@@ -121,7 +111,9 @@ void nfs4_state_init(void);
|
||||
int nfsd4_init_slabs(void);
|
||||
void nfsd4_free_slabs(void);
|
||||
int nfs4_state_start(void);
|
||||
int nfs4_state_start_net(struct net *net);
|
||||
void nfs4_state_shutdown(void);
|
||||
void nfs4_state_shutdown_net(struct net *net);
|
||||
void nfs4_reset_lease(time_t leasetime);
|
||||
int nfs4_reset_recoverydir(char *recdir);
|
||||
char * nfs4_recoverydir(void);
|
||||
@@ -130,7 +122,9 @@ static inline void nfs4_state_init(void) { }
|
||||
static inline int nfsd4_init_slabs(void) { return 0; }
|
||||
static inline void nfsd4_free_slabs(void) { }
|
||||
static inline int nfs4_state_start(void) { return 0; }
|
||||
static inline int nfs4_state_start_net(struct net *net) { return 0; }
|
||||
static inline void nfs4_state_shutdown(void) { }
|
||||
static inline void nfs4_state_shutdown_net(struct net *net) { }
|
||||
static inline void nfs4_reset_lease(time_t leasetime) { }
|
||||
static inline int nfs4_reset_recoverydir(char *recdir) { return 0; }
|
||||
static inline char * nfs4_recoverydir(void) {return NULL; }
|
||||
@@ -265,16 +259,8 @@ void nfsd_lockd_shutdown(void);
|
||||
/* Check for dir entries '.' and '..' */
|
||||
#define isdotent(n, l) (l < 3 && n[0] == '.' && (l == 1 || n[1] == '.'))
|
||||
|
||||
/*
|
||||
* Time of server startup
|
||||
*/
|
||||
extern struct timeval nfssvc_boot;
|
||||
|
||||
#ifdef CONFIG_NFSD_V4
|
||||
|
||||
extern time_t nfsd4_lease;
|
||||
extern time_t nfsd4_grace;
|
||||
|
||||
/* before processing a COMPOUND operation, we have to check that there
|
||||
* is enough space in the buffer for XDR encode to succeed. otherwise,
|
||||
* we might process an operation with side effects, and be unable to
|
||||
|
||||
+2
-2
@@ -572,7 +572,7 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry,
|
||||
|
||||
if (inode)
|
||||
_fh_update(fhp, exp, dentry);
|
||||
if (fhp->fh_handle.fh_fileid_type == 255) {
|
||||
if (fhp->fh_handle.fh_fileid_type == FILEID_INVALID) {
|
||||
fh_put(fhp);
|
||||
return nfserr_opnotsupp;
|
||||
}
|
||||
@@ -603,7 +603,7 @@ fh_update(struct svc_fh *fhp)
|
||||
goto out;
|
||||
|
||||
_fh_update(fhp, fhp->fh_export, dentry);
|
||||
if (fhp->fh_handle.fh_fileid_type == 255)
|
||||
if (fhp->fh_handle.fh_fileid_type == FILEID_INVALID)
|
||||
return nfserr_opnotsupp;
|
||||
}
|
||||
out:
|
||||
|
||||
+133
-74
@@ -11,7 +11,6 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/fs_struct.h>
|
||||
#include <linux/swap.h>
|
||||
#include <linux/nsproxy.h>
|
||||
|
||||
#include <linux/sunrpc/stats.h>
|
||||
#include <linux/sunrpc/svcsock.h>
|
||||
@@ -22,19 +21,19 @@
|
||||
#include "nfsd.h"
|
||||
#include "cache.h"
|
||||
#include "vfs.h"
|
||||
#include "netns.h"
|
||||
|
||||
#define NFSDDBG_FACILITY NFSDDBG_SVC
|
||||
|
||||
extern struct svc_program nfsd_program;
|
||||
static int nfsd(void *vrqstp);
|
||||
struct timeval nfssvc_boot;
|
||||
|
||||
/*
|
||||
* nfsd_mutex protects nfsd_serv -- both the pointer itself and the members
|
||||
* nfsd_mutex protects nn->nfsd_serv -- both the pointer itself and the members
|
||||
* of the svc_serv struct. In particular, ->sv_nrthreads but also to some
|
||||
* extent ->sv_temp_socks and ->sv_permsocks. It also protects nfsdstats.th_cnt
|
||||
*
|
||||
* If (out side the lock) nfsd_serv is non-NULL, then it must point to a
|
||||
* If (out side the lock) nn->nfsd_serv is non-NULL, then it must point to a
|
||||
* properly initialised 'struct svc_serv' with ->sv_nrthreads > 0. That number
|
||||
* of nfsd threads must exist and each must listed in ->sp_all_threads in each
|
||||
* entry of ->sv_pools[].
|
||||
@@ -52,7 +51,6 @@ struct timeval nfssvc_boot;
|
||||
* nfsd_versions
|
||||
*/
|
||||
DEFINE_MUTEX(nfsd_mutex);
|
||||
struct svc_serv *nfsd_serv;
|
||||
|
||||
/*
|
||||
* nfsd_drc_lock protects nfsd_drc_max_pages and nfsd_drc_pages_used.
|
||||
@@ -173,28 +171,32 @@ int nfsd_minorversion(u32 minorversion, enum vers_op change)
|
||||
*/
|
||||
#define NFSD_MAXSERVS 8192
|
||||
|
||||
int nfsd_nrthreads(void)
|
||||
int nfsd_nrthreads(struct net *net)
|
||||
{
|
||||
int rv = 0;
|
||||
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
||||
|
||||
mutex_lock(&nfsd_mutex);
|
||||
if (nfsd_serv)
|
||||
rv = nfsd_serv->sv_nrthreads;
|
||||
if (nn->nfsd_serv)
|
||||
rv = nn->nfsd_serv->sv_nrthreads;
|
||||
mutex_unlock(&nfsd_mutex);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int nfsd_init_socks(void)
|
||||
static int nfsd_init_socks(struct net *net)
|
||||
{
|
||||
int error;
|
||||
if (!list_empty(&nfsd_serv->sv_permsocks))
|
||||
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
||||
|
||||
if (!list_empty(&nn->nfsd_serv->sv_permsocks))
|
||||
return 0;
|
||||
|
||||
error = svc_create_xprt(nfsd_serv, "udp", &init_net, PF_INET, NFS_PORT,
|
||||
error = svc_create_xprt(nn->nfsd_serv, "udp", net, PF_INET, NFS_PORT,
|
||||
SVC_SOCK_DEFAULTS);
|
||||
if (error < 0)
|
||||
return error;
|
||||
|
||||
error = svc_create_xprt(nfsd_serv, "tcp", &init_net, PF_INET, NFS_PORT,
|
||||
error = svc_create_xprt(nn->nfsd_serv, "tcp", net, PF_INET, NFS_PORT,
|
||||
SVC_SOCK_DEFAULTS);
|
||||
if (error < 0)
|
||||
return error;
|
||||
@@ -202,14 +204,15 @@ static int nfsd_init_socks(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool nfsd_up = false;
|
||||
static int nfsd_users = 0;
|
||||
|
||||
static int nfsd_startup(int nrservs)
|
||||
static int nfsd_startup_generic(int nrservs)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (nfsd_up)
|
||||
if (nfsd_users++)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Readahead param cache - will no-op if it already exists.
|
||||
* (Note therefore results will be suboptimal if number of
|
||||
@@ -218,43 +221,79 @@ static int nfsd_startup(int nrservs)
|
||||
ret = nfsd_racache_init(2*nrservs);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = nfsd_init_socks();
|
||||
if (ret)
|
||||
goto out_racache;
|
||||
ret = lockd_up(&init_net);
|
||||
if (ret)
|
||||
goto out_racache;
|
||||
ret = nfs4_state_start();
|
||||
if (ret)
|
||||
goto out_lockd;
|
||||
nfsd_up = true;
|
||||
goto out_racache;
|
||||
return 0;
|
||||
out_lockd:
|
||||
lockd_down(&init_net);
|
||||
|
||||
out_racache:
|
||||
nfsd_racache_shutdown();
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void nfsd_shutdown(void)
|
||||
static void nfsd_shutdown_generic(void)
|
||||
{
|
||||
if (--nfsd_users)
|
||||
return;
|
||||
|
||||
nfs4_state_shutdown();
|
||||
nfsd_racache_shutdown();
|
||||
}
|
||||
|
||||
static int nfsd_startup_net(int nrservs, struct net *net)
|
||||
{
|
||||
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
||||
int ret;
|
||||
|
||||
if (nn->nfsd_net_up)
|
||||
return 0;
|
||||
|
||||
ret = nfsd_startup_generic(nrservs);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = nfsd_init_socks(net);
|
||||
if (ret)
|
||||
goto out_socks;
|
||||
ret = lockd_up(net);
|
||||
if (ret)
|
||||
goto out_socks;
|
||||
ret = nfs4_state_start_net(net);
|
||||
if (ret)
|
||||
goto out_lockd;
|
||||
|
||||
nn->nfsd_net_up = true;
|
||||
return 0;
|
||||
|
||||
out_lockd:
|
||||
lockd_down(net);
|
||||
out_socks:
|
||||
nfsd_shutdown_generic();
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void nfsd_shutdown_net(struct net *net)
|
||||
{
|
||||
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
||||
|
||||
nfs4_state_shutdown_net(net);
|
||||
lockd_down(net);
|
||||
nn->nfsd_net_up = false;
|
||||
nfsd_shutdown_generic();
|
||||
}
|
||||
|
||||
static void nfsd_last_thread(struct svc_serv *serv, struct net *net)
|
||||
{
|
||||
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
||||
|
||||
/*
|
||||
* write_ports can create the server without actually starting
|
||||
* any threads--if we get shut down before any threads are
|
||||
* started, then nfsd_last_thread will be run before any of this
|
||||
* other initialization has been done.
|
||||
*/
|
||||
if (!nfsd_up)
|
||||
if (!nn->nfsd_net_up)
|
||||
return;
|
||||
nfs4_state_shutdown();
|
||||
lockd_down(&init_net);
|
||||
nfsd_racache_shutdown();
|
||||
nfsd_up = false;
|
||||
}
|
||||
|
||||
static void nfsd_last_thread(struct svc_serv *serv, struct net *net)
|
||||
{
|
||||
nfsd_shutdown();
|
||||
nfsd_shutdown_net(net);
|
||||
|
||||
svc_rpcb_cleanup(serv, net);
|
||||
|
||||
@@ -327,69 +366,84 @@ static int nfsd_get_default_max_blksize(void)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int nfsd_create_serv(void)
|
||||
int nfsd_create_serv(struct net *net)
|
||||
{
|
||||
int error;
|
||||
struct net *net = current->nsproxy->net_ns;
|
||||
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
||||
|
||||
WARN_ON(!mutex_is_locked(&nfsd_mutex));
|
||||
if (nfsd_serv) {
|
||||
svc_get(nfsd_serv);
|
||||
if (nn->nfsd_serv) {
|
||||
svc_get(nn->nfsd_serv);
|
||||
return 0;
|
||||
}
|
||||
if (nfsd_max_blksize == 0)
|
||||
nfsd_max_blksize = nfsd_get_default_max_blksize();
|
||||
nfsd_reset_versions();
|
||||
nfsd_serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize,
|
||||
nn->nfsd_serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize,
|
||||
nfsd_last_thread, nfsd, THIS_MODULE);
|
||||
if (nfsd_serv == NULL)
|
||||
if (nn->nfsd_serv == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
error = svc_bind(nfsd_serv, net);
|
||||
error = svc_bind(nn->nfsd_serv, net);
|
||||
if (error < 0) {
|
||||
svc_destroy(nfsd_serv);
|
||||
svc_destroy(nn->nfsd_serv);
|
||||
return error;
|
||||
}
|
||||
|
||||
set_max_drc();
|
||||
do_gettimeofday(&nfssvc_boot); /* record boot time */
|
||||
do_gettimeofday(&nn->nfssvc_boot); /* record boot time */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nfsd_nrpools(void)
|
||||
int nfsd_nrpools(struct net *net)
|
||||
{
|
||||
if (nfsd_serv == NULL)
|
||||
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
||||
|
||||
if (nn->nfsd_serv == NULL)
|
||||
return 0;
|
||||
else
|
||||
return nfsd_serv->sv_nrpools;
|
||||
return nn->nfsd_serv->sv_nrpools;
|
||||
}
|
||||
|
||||
int nfsd_get_nrthreads(int n, int *nthreads)
|
||||
int nfsd_get_nrthreads(int n, int *nthreads, struct net *net)
|
||||
{
|
||||
int i = 0;
|
||||
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
||||
|
||||
if (nfsd_serv != NULL) {
|
||||
for (i = 0; i < nfsd_serv->sv_nrpools && i < n; i++)
|
||||
nthreads[i] = nfsd_serv->sv_pools[i].sp_nrthreads;
|
||||
if (nn->nfsd_serv != NULL) {
|
||||
for (i = 0; i < nn->nfsd_serv->sv_nrpools && i < n; i++)
|
||||
nthreads[i] = nn->nfsd_serv->sv_pools[i].sp_nrthreads;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nfsd_set_nrthreads(int n, int *nthreads)
|
||||
void nfsd_destroy(struct net *net)
|
||||
{
|
||||
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
||||
int destroy = (nn->nfsd_serv->sv_nrthreads == 1);
|
||||
|
||||
if (destroy)
|
||||
svc_shutdown_net(nn->nfsd_serv, net);
|
||||
svc_destroy(nn->nfsd_serv);
|
||||
if (destroy)
|
||||
nn->nfsd_serv = NULL;
|
||||
}
|
||||
|
||||
int nfsd_set_nrthreads(int n, int *nthreads, struct net *net)
|
||||
{
|
||||
int i = 0;
|
||||
int tot = 0;
|
||||
int err = 0;
|
||||
struct net *net = &init_net;
|
||||
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
||||
|
||||
WARN_ON(!mutex_is_locked(&nfsd_mutex));
|
||||
|
||||
if (nfsd_serv == NULL || n <= 0)
|
||||
if (nn->nfsd_serv == NULL || n <= 0)
|
||||
return 0;
|
||||
|
||||
if (n > nfsd_serv->sv_nrpools)
|
||||
n = nfsd_serv->sv_nrpools;
|
||||
if (n > nn->nfsd_serv->sv_nrpools)
|
||||
n = nn->nfsd_serv->sv_nrpools;
|
||||
|
||||
/* enforce a global maximum number of threads */
|
||||
tot = 0;
|
||||
@@ -419,9 +473,9 @@ int nfsd_set_nrthreads(int n, int *nthreads)
|
||||
nthreads[0] = 1;
|
||||
|
||||
/* apply the new numbers */
|
||||
svc_get(nfsd_serv);
|
||||
svc_get(nn->nfsd_serv);
|
||||
for (i = 0; i < n; i++) {
|
||||
err = svc_set_num_threads(nfsd_serv, &nfsd_serv->sv_pools[i],
|
||||
err = svc_set_num_threads(nn->nfsd_serv, &nn->nfsd_serv->sv_pools[i],
|
||||
nthreads[i]);
|
||||
if (err)
|
||||
break;
|
||||
@@ -436,11 +490,11 @@ int nfsd_set_nrthreads(int n, int *nthreads)
|
||||
* this is the first time nrservs is nonzero.
|
||||
*/
|
||||
int
|
||||
nfsd_svc(int nrservs)
|
||||
nfsd_svc(int nrservs, struct net *net)
|
||||
{
|
||||
int error;
|
||||
bool nfsd_up_before;
|
||||
struct net *net = &init_net;
|
||||
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
||||
|
||||
mutex_lock(&nfsd_mutex);
|
||||
dprintk("nfsd: creating service\n");
|
||||
@@ -449,29 +503,29 @@ nfsd_svc(int nrservs)
|
||||
if (nrservs > NFSD_MAXSERVS)
|
||||
nrservs = NFSD_MAXSERVS;
|
||||
error = 0;
|
||||
if (nrservs == 0 && nfsd_serv == NULL)
|
||||
if (nrservs == 0 && nn->nfsd_serv == NULL)
|
||||
goto out;
|
||||
|
||||
error = nfsd_create_serv();
|
||||
error = nfsd_create_serv(net);
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
nfsd_up_before = nfsd_up;
|
||||
nfsd_up_before = nn->nfsd_net_up;
|
||||
|
||||
error = nfsd_startup(nrservs);
|
||||
error = nfsd_startup_net(nrservs, net);
|
||||
if (error)
|
||||
goto out_destroy;
|
||||
error = svc_set_num_threads(nfsd_serv, NULL, nrservs);
|
||||
error = svc_set_num_threads(nn->nfsd_serv, NULL, nrservs);
|
||||
if (error)
|
||||
goto out_shutdown;
|
||||
/* We are holding a reference to nfsd_serv which
|
||||
/* We are holding a reference to nn->nfsd_serv which
|
||||
* we don't want to count in the return value,
|
||||
* so subtract 1
|
||||
*/
|
||||
error = nfsd_serv->sv_nrthreads - 1;
|
||||
error = nn->nfsd_serv->sv_nrthreads - 1;
|
||||
out_shutdown:
|
||||
if (error < 0 && !nfsd_up_before)
|
||||
nfsd_shutdown();
|
||||
nfsd_shutdown_net(net);
|
||||
out_destroy:
|
||||
nfsd_destroy(net); /* Release server */
|
||||
out:
|
||||
@@ -487,6 +541,8 @@ static int
|
||||
nfsd(void *vrqstp)
|
||||
{
|
||||
struct svc_rqst *rqstp = (struct svc_rqst *) vrqstp;
|
||||
struct svc_xprt *perm_sock = list_entry(rqstp->rq_server->sv_permsocks.next, typeof(struct svc_xprt), xpt_list);
|
||||
struct net *net = perm_sock->xpt_net;
|
||||
int err;
|
||||
|
||||
/* Lock module and set up kernel thread */
|
||||
@@ -551,7 +607,7 @@ out:
|
||||
/* Release the thread */
|
||||
svc_exit_thread(rqstp);
|
||||
|
||||
nfsd_destroy(&init_net);
|
||||
nfsd_destroy(net);
|
||||
|
||||
/* Release module */
|
||||
mutex_unlock(&nfsd_mutex);
|
||||
@@ -640,21 +696,24 @@ nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp)
|
||||
}
|
||||
|
||||
/* Store reply in cache. */
|
||||
nfsd_cache_update(rqstp, proc->pc_cachetype, statp + 1);
|
||||
nfsd_cache_update(rqstp, rqstp->rq_cachetype, statp + 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int nfsd_pool_stats_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
int ret;
|
||||
struct net *net = &init_net;
|
||||
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
||||
|
||||
mutex_lock(&nfsd_mutex);
|
||||
if (nfsd_serv == NULL) {
|
||||
if (nn->nfsd_serv == NULL) {
|
||||
mutex_unlock(&nfsd_mutex);
|
||||
return -ENODEV;
|
||||
}
|
||||
/* bump up the psudo refcount while traversing */
|
||||
svc_get(nfsd_serv);
|
||||
ret = svc_pool_stats_open(nfsd_serv, file);
|
||||
svc_get(nn->nfsd_serv);
|
||||
ret = svc_pool_stats_open(nn->nfsd_serv, file);
|
||||
mutex_unlock(&nfsd_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
+6
-5
@@ -246,7 +246,7 @@ nfssvc_decode_readargs(struct svc_rqst *rqstp, __be32 *p,
|
||||
struct nfsd_readargs *args)
|
||||
{
|
||||
unsigned int len;
|
||||
int v,pn;
|
||||
int v;
|
||||
if (!(p = decode_fh(p, &args->fh)))
|
||||
return 0;
|
||||
|
||||
@@ -262,8 +262,9 @@ nfssvc_decode_readargs(struct svc_rqst *rqstp, __be32 *p,
|
||||
*/
|
||||
v=0;
|
||||
while (len > 0) {
|
||||
pn = rqstp->rq_resused++;
|
||||
rqstp->rq_vec[v].iov_base = page_address(rqstp->rq_respages[pn]);
|
||||
struct page *p = *(rqstp->rq_next_page++);
|
||||
|
||||
rqstp->rq_vec[v].iov_base = page_address(p);
|
||||
rqstp->rq_vec[v].iov_len = len < PAGE_SIZE?len:PAGE_SIZE;
|
||||
len -= rqstp->rq_vec[v].iov_len;
|
||||
v++;
|
||||
@@ -355,7 +356,7 @@ nfssvc_decode_readlinkargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd_readli
|
||||
{
|
||||
if (!(p = decode_fh(p, &args->fh)))
|
||||
return 0;
|
||||
args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused++]);
|
||||
args->buffer = page_address(*(rqstp->rq_next_page++));
|
||||
|
||||
return xdr_argsize_check(rqstp, p);
|
||||
}
|
||||
@@ -396,7 +397,7 @@ nfssvc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p,
|
||||
if (args->count > PAGE_SIZE)
|
||||
args->count = PAGE_SIZE;
|
||||
|
||||
args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused++]);
|
||||
args->buffer = page_address(*(rqstp->rq_next_page++));
|
||||
|
||||
return xdr_argsize_check(rqstp, p);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user