diff options
32 files changed, 1911 insertions, 1067 deletions
diff --git a/Documentation/filesystems/nfs/nfs41-server.txt b/Documentation/filesystems/nfs/nfs41-server.txt index 092fad92a3f0..01c2db769791 100644 --- a/Documentation/filesystems/nfs/nfs41-server.txt +++ b/Documentation/filesystems/nfs/nfs41-server.txt | |||
| @@ -39,21 +39,10 @@ interoperability problems with future clients. Known issues: | |||
| 39 | from a linux client are possible, but we aren't really | 39 | from a linux client are possible, but we aren't really |
| 40 | conformant with the spec (for example, we don't use kerberos | 40 | conformant with the spec (for example, we don't use kerberos |
| 41 | on the backchannel correctly). | 41 | on the backchannel correctly). |
| 42 | - Incomplete backchannel support: incomplete backchannel gss | ||
| 43 | support and no support for BACKCHANNEL_CTL mean that | ||
| 44 | callbacks (hence delegations and layouts) may not be | ||
| 45 | available and clients confused by the incomplete | ||
| 46 | implementation may fail. | ||
| 47 | - We do not support SSV, which provides security for shared | 42 | - We do not support SSV, which provides security for shared |
| 48 | client-server state (thus preventing unauthorized tampering | 43 | client-server state (thus preventing unauthorized tampering |
| 49 | with locks and opens, for example). It is mandatory for | 44 | with locks and opens, for example). It is mandatory for |
| 50 | servers to support this, though no clients use it yet. | 45 | servers to support this, though no clients use it yet. |
| 51 | - Mandatory operations which we do not support, such as | ||
| 52 | DESTROY_CLIENTID, are not currently used by clients, but will be | ||
| 53 | (and the spec recommends their uses in common cases), and | ||
| 54 | clients should not be expected to know how to recover from the | ||
| 55 | case where they are not supported. This will eventually cause | ||
| 56 | interoperability failures. | ||
| 57 | 46 | ||
| 58 | In addition, some limitations are inherited from the current NFSv4 | 47 | In addition, some limitations are inherited from the current NFSv4 |
| 59 | implementation: | 48 | implementation: |
| @@ -89,7 +78,7 @@ Operations | |||
| 89 | | | MNI | or OPT) | | | 78 | | | MNI | or OPT) | | |
| 90 | +----------------------+------------+--------------+----------------+ | 79 | +----------------------+------------+--------------+----------------+ |
| 91 | | ACCESS | REQ | | Section 18.1 | | 80 | | ACCESS | REQ | | Section 18.1 | |
| 92 | NS | BACKCHANNEL_CTL | REQ | | Section 18.33 | | 81 | I | BACKCHANNEL_CTL | REQ | | Section 18.33 | |
| 93 | I | BIND_CONN_TO_SESSION | REQ | | Section 18.34 | | 82 | I | BIND_CONN_TO_SESSION | REQ | | Section 18.34 | |
| 94 | | CLOSE | REQ | | Section 18.2 | | 83 | | CLOSE | REQ | | Section 18.2 | |
| 95 | | COMMIT | REQ | | Section 18.3 | | 84 | | COMMIT | REQ | | Section 18.3 | |
| @@ -99,7 +88,7 @@ NS*| DELEGPURGE | OPT | FDELG (REQ) | Section 18.5 | | |||
| 99 | | DELEGRETURN | OPT | FDELG, | Section 18.6 | | 88 | | DELEGRETURN | OPT | FDELG, | Section 18.6 | |
| 100 | | | | DDELG, pNFS | | | 89 | | | | DDELG, pNFS | | |
| 101 | | | | (REQ) | | | 90 | | | | (REQ) | | |
| 102 | NS | DESTROY_CLIENTID | REQ | | Section 18.50 | | 91 | I | DESTROY_CLIENTID | REQ | | Section 18.50 | |
| 103 | I | DESTROY_SESSION | REQ | | Section 18.37 | | 92 | I | DESTROY_SESSION | REQ | | Section 18.37 | |
| 104 | I | EXCHANGE_ID | REQ | | Section 18.35 | | 93 | I | EXCHANGE_ID | REQ | | Section 18.35 | |
| 105 | I | FREE_STATEID | REQ | | Section 18.38 | | 94 | I | FREE_STATEID | REQ | | Section 18.38 | |
| @@ -192,7 +181,6 @@ EXCHANGE_ID: | |||
| 192 | 181 | ||
| 193 | CREATE_SESSION: | 182 | CREATE_SESSION: |
| 194 | * backchannel attributes are ignored | 183 | * backchannel attributes are ignored |
| 195 | * backchannel security parameters are ignored | ||
| 196 | 184 | ||
| 197 | SEQUENCE: | 185 | SEQUENCE: |
| 198 | * no support for dynamic slot table renegotiation (optional) | 186 | * no support for dynamic slot table renegotiation (optional) |
| @@ -202,7 +190,7 @@ Nonstandard compound limitations: | |||
| 202 | ca_maxrequestsize request and a ca_maxresponsesize reply, so we may | 190 | ca_maxrequestsize request and a ca_maxresponsesize reply, so we may |
| 203 | fail to live up to the promise we made in CREATE_SESSION fore channel | 191 | fail to live up to the promise we made in CREATE_SESSION fore channel |
| 204 | negotiation. | 192 | negotiation. |
| 205 | * No more than one IO operation (read, write, readdir) allowed per | 193 | * No more than one read-like operation allowed per compound; encoding |
| 206 | compound. | 194 | replies that cross page boundaries (except for read data) not handled. |
| 207 | 195 | ||
| 208 | See also http://wiki.linux-nfs.org/wiki/index.php/Server_4.0_and_4.1_issues. | 196 | See also http://wiki.linux-nfs.org/wiki/index.php/Server_4.0_and_4.1_issues. |
diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c index 606bb074c501..5df4bb4aab14 100644 --- a/fs/exportfs/expfs.c +++ b/fs/exportfs/expfs.c | |||
| @@ -322,10 +322,10 @@ static int export_encode_fh(struct inode *inode, struct fid *fid, | |||
| 322 | 322 | ||
| 323 | if (parent && (len < 4)) { | 323 | if (parent && (len < 4)) { |
| 324 | *max_len = 4; | 324 | *max_len = 4; |
| 325 | return 255; | 325 | return FILEID_INVALID; |
| 326 | } else if (len < 2) { | 326 | } else if (len < 2) { |
| 327 | *max_len = 2; | 327 | *max_len = 2; |
| 328 | return 255; | 328 | return FILEID_INVALID; |
| 329 | } | 329 | } |
| 330 | 330 | ||
| 331 | len = 2; | 331 | len = 2; |
diff --git a/fs/fhandle.c b/fs/fhandle.c index cccdc874bb55..999ff5c3cab0 100644 --- a/fs/fhandle.c +++ b/fs/fhandle.c | |||
| @@ -52,7 +52,7 @@ static long do_sys_name_to_handle(struct path *path, | |||
| 52 | handle_bytes = handle_dwords * sizeof(u32); | 52 | handle_bytes = handle_dwords * sizeof(u32); |
| 53 | handle->handle_bytes = handle_bytes; | 53 | handle->handle_bytes = handle_bytes; |
| 54 | if ((handle->handle_bytes > f_handle.handle_bytes) || | 54 | if ((handle->handle_bytes > f_handle.handle_bytes) || |
| 55 | (retval == 255) || (retval == -ENOSPC)) { | 55 | (retval == FILEID_INVALID) || (retval == -ENOSPC)) { |
| 56 | /* As per old exportfs_encode_fh documentation | 56 | /* As per old exportfs_encode_fh documentation |
| 57 | * we could return ENOSPC to indicate overflow | 57 | * we could return ENOSPC to indicate overflow |
| 58 | * But file system returned 255 always. So handle | 58 | * But file system returned 255 always. So handle |
diff --git a/fs/nfsd/fault_inject.c b/fs/nfsd/fault_inject.c index e6c38159622f..e761ee95617f 100644 --- a/fs/nfsd/fault_inject.c +++ b/fs/nfsd/fault_inject.c | |||
| @@ -8,61 +8,144 @@ | |||
| 8 | #include <linux/fs.h> | 8 | #include <linux/fs.h> |
| 9 | #include <linux/debugfs.h> | 9 | #include <linux/debugfs.h> |
| 10 | #include <linux/module.h> | 10 | #include <linux/module.h> |
| 11 | #include <linux/nsproxy.h> | ||
| 12 | #include <linux/sunrpc/clnt.h> | ||
| 13 | #include <asm/uaccess.h> | ||
| 11 | 14 | ||
| 12 | #include "state.h" | 15 | #include "state.h" |
| 13 | #include "fault_inject.h" | 16 | #include "netns.h" |
| 14 | 17 | ||
| 15 | struct nfsd_fault_inject_op { | 18 | struct nfsd_fault_inject_op { |
| 16 | char *file; | 19 | char *file; |
| 17 | void (*func)(u64); | 20 | u64 (*forget)(struct nfs4_client *, u64); |
| 21 | u64 (*print)(struct nfs4_client *, u64); | ||
| 18 | }; | 22 | }; |
| 19 | 23 | ||
| 20 | static struct nfsd_fault_inject_op inject_ops[] = { | 24 | static struct nfsd_fault_inject_op inject_ops[] = { |
| 21 | { | 25 | { |
| 22 | .file = "forget_clients", | 26 | .file = "forget_clients", |
| 23 | .func = nfsd_forget_clients, | 27 | .forget = nfsd_forget_client, |
| 28 | .print = nfsd_print_client, | ||
| 24 | }, | 29 | }, |
| 25 | { | 30 | { |
| 26 | .file = "forget_locks", | 31 | .file = "forget_locks", |
| 27 | .func = nfsd_forget_locks, | 32 | .forget = nfsd_forget_client_locks, |
| 33 | .print = nfsd_print_client_locks, | ||
| 28 | }, | 34 | }, |
| 29 | { | 35 | { |
| 30 | .file = "forget_openowners", | 36 | .file = "forget_openowners", |
| 31 | .func = nfsd_forget_openowners, | 37 | .forget = nfsd_forget_client_openowners, |
| 38 | .print = nfsd_print_client_openowners, | ||
| 32 | }, | 39 | }, |
| 33 | { | 40 | { |
| 34 | .file = "forget_delegations", | 41 | .file = "forget_delegations", |
| 35 | .func = nfsd_forget_delegations, | 42 | .forget = nfsd_forget_client_delegations, |
| 43 | .print = nfsd_print_client_delegations, | ||
| 36 | }, | 44 | }, |
| 37 | { | 45 | { |
| 38 | .file = "recall_delegations", | 46 | .file = "recall_delegations", |
| 39 | .func = nfsd_recall_delegations, | 47 | .forget = nfsd_recall_client_delegations, |
| 48 | .print = nfsd_print_client_delegations, | ||
| 40 | }, | 49 | }, |
| 41 | }; | 50 | }; |
| 42 | 51 | ||
| 43 | static long int NUM_INJECT_OPS = sizeof(inject_ops) / sizeof(struct nfsd_fault_inject_op); | 52 | static long int NUM_INJECT_OPS = sizeof(inject_ops) / sizeof(struct nfsd_fault_inject_op); |
| 44 | static struct dentry *debug_dir; | 53 | static struct dentry *debug_dir; |
| 45 | 54 | ||
| 46 | static int nfsd_inject_set(void *op_ptr, u64 val) | 55 | static void nfsd_inject_set(struct nfsd_fault_inject_op *op, u64 val) |
| 47 | { | 56 | { |
| 48 | struct nfsd_fault_inject_op *op = op_ptr; | 57 | u64 count = 0; |
| 49 | 58 | ||
| 50 | if (val == 0) | 59 | if (val == 0) |
| 51 | printk(KERN_INFO "NFSD Fault Injection: %s (all)", op->file); | 60 | printk(KERN_INFO "NFSD Fault Injection: %s (all)", op->file); |
| 52 | else | 61 | else |
| 53 | printk(KERN_INFO "NFSD Fault Injection: %s (n = %llu)", op->file, val); | 62 | printk(KERN_INFO "NFSD Fault Injection: %s (n = %llu)", op->file, val); |
| 54 | 63 | ||
| 55 | op->func(val); | 64 | nfs4_lock_state(); |
| 56 | return 0; | 65 | count = nfsd_for_n_state(val, op->forget); |
| 66 | nfs4_unlock_state(); | ||
| 67 | printk(KERN_INFO "NFSD: %s: found %llu", op->file, count); | ||
| 57 | } | 68 | } |
| 58 | 69 | ||
| 59 | static int nfsd_inject_get(void *data, u64 *val) | 70 | static void nfsd_inject_set_client(struct nfsd_fault_inject_op *op, |
| 71 | struct sockaddr_storage *addr, | ||
| 72 | size_t addr_size) | ||
| 60 | { | 73 | { |
| 61 | *val = 0; | 74 | char buf[INET6_ADDRSTRLEN]; |
| 62 | return 0; | 75 | struct nfs4_client *clp; |
| 76 | u64 count; | ||
| 77 | |||
| 78 | nfs4_lock_state(); | ||
| 79 | clp = nfsd_find_client(addr, addr_size); | ||
| 80 | if (clp) { | ||
| 81 | count = op->forget(clp, 0); | ||
| 82 | rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf)); | ||
| 83 | printk(KERN_INFO "NFSD [%s]: Client %s had %llu state object(s)\n", op->file, buf, count); | ||
| 84 | } | ||
| 85 | nfs4_unlock_state(); | ||
| 86 | } | ||
| 87 | |||
| 88 | static void nfsd_inject_get(struct nfsd_fault_inject_op *op, u64 *val) | ||
| 89 | { | ||
| 90 | nfs4_lock_state(); | ||
| 91 | *val = nfsd_for_n_state(0, op->print); | ||
| 92 | nfs4_unlock_state(); | ||
| 63 | } | 93 | } |
| 64 | 94 | ||
| 65 | DEFINE_SIMPLE_ATTRIBUTE(fops_nfsd, nfsd_inject_get, nfsd_inject_set, "%llu\n"); | 95 | static ssize_t fault_inject_read(struct file *file, char __user *buf, |
| 96 | size_t len, loff_t *ppos) | ||
| 97 | { | ||
| 98 | static u64 val; | ||
| 99 | char read_buf[25]; | ||
| 100 | size_t size, ret; | ||
| 101 | loff_t pos = *ppos; | ||
| 102 | |||
| 103 | if (!pos) | ||
| 104 | nfsd_inject_get(file->f_dentry->d_inode->i_private, &val); | ||
| 105 | size = scnprintf(read_buf, sizeof(read_buf), "%llu\n", val); | ||
| 106 | |||
| 107 | if (pos < 0) | ||
| 108 | return -EINVAL; | ||
| 109 | if (pos >= size || !len) | ||
| 110 | return 0; | ||
| 111 | if (len > size - pos) | ||
| 112 | len = size - pos; | ||
| 113 | ret = copy_to_user(buf, read_buf + pos, len); | ||
| 114 | if (ret == len) | ||
| 115 | return -EFAULT; | ||
| 116 | len -= ret; | ||
| 117 | *ppos = pos + len; | ||
| 118 | return len; | ||
| 119 | } | ||
| 120 | |||
| 121 | static ssize_t fault_inject_write(struct file *file, const char __user *buf, | ||
| 122 | size_t len, loff_t *ppos) | ||
| 123 | { | ||
| 124 | char write_buf[INET6_ADDRSTRLEN]; | ||
| 125 | size_t size = min(sizeof(write_buf) - 1, len); | ||
| 126 | struct net *net = current->nsproxy->net_ns; | ||
| 127 | struct sockaddr_storage sa; | ||
| 128 | u64 val; | ||
| 129 | |||
| 130 | if (copy_from_user(write_buf, buf, size)) | ||
| 131 | return -EFAULT; | ||
| 132 | write_buf[size] = '\0'; | ||
| 133 | |||
| 134 | size = rpc_pton(net, write_buf, size, (struct sockaddr *)&sa, sizeof(sa)); | ||
| 135 | if (size > 0) | ||
| 136 | nfsd_inject_set_client(file->f_dentry->d_inode->i_private, &sa, size); | ||
| 137 | else { | ||
| 138 | val = simple_strtoll(write_buf, NULL, 0); | ||
| 139 | nfsd_inject_set(file->f_dentry->d_inode->i_private, val); | ||
| 140 | } | ||
| 141 | return len; /* on success, claim we got the whole input */ | ||
| 142 | } | ||
| 143 | |||
| 144 | static const struct file_operations fops_nfsd = { | ||
| 145 | .owner = THIS_MODULE, | ||
| 146 | .read = fault_inject_read, | ||
| 147 | .write = fault_inject_write, | ||
| 148 | }; | ||
| 66 | 149 | ||
| 67 | void nfsd_fault_inject_cleanup(void) | 150 | void nfsd_fault_inject_cleanup(void) |
| 68 | { | 151 | { |
diff --git a/fs/nfsd/fault_inject.h b/fs/nfsd/fault_inject.h deleted file mode 100644 index 90bd0570956c..000000000000 --- a/fs/nfsd/fault_inject.h +++ /dev/null | |||
| @@ -1,28 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2011 Bryan Schumaker <bjschuma@netapp.com> | ||
| 3 | * | ||
| 4 | * Function definitions for fault injection | ||
| 5 | */ | ||
| 6 | |||
| 7 | #ifndef LINUX_NFSD_FAULT_INJECT_H | ||
| 8 | #define LINUX_NFSD_FAULT_INJECT_H | ||
| 9 | |||
| 10 | #ifdef CONFIG_NFSD_FAULT_INJECTION | ||
| 11 | int nfsd_fault_inject_init(void); | ||
| 12 | void nfsd_fault_inject_cleanup(void); | ||
| 13 | void nfsd_forget_clients(u64); | ||
| 14 | void nfsd_forget_locks(u64); | ||
| 15 | void nfsd_forget_openowners(u64); | ||
| 16 | void nfsd_forget_delegations(u64); | ||
| 17 | void nfsd_recall_delegations(u64); | ||
| 18 | #else /* CONFIG_NFSD_FAULT_INJECTION */ | ||
| 19 | static inline int nfsd_fault_inject_init(void) { return 0; } | ||
| 20 | static inline void nfsd_fault_inject_cleanup(void) {} | ||
| 21 | static inline void nfsd_forget_clients(u64 num) {} | ||
| 22 | static inline void nfsd_forget_locks(u64 num) {} | ||
| 23 | static inline void nfsd_forget_openowners(u64 num) {} | ||
| 24 | static inline void nfsd_forget_delegations(u64 num) {} | ||
| 25 | static inline void nfsd_recall_delegations(u64 num) {} | ||
| 26 | #endif /* CONFIG_NFSD_FAULT_INJECTION */ | ||
| 27 | |||
| 28 | #endif /* LINUX_NFSD_FAULT_INJECT_H */ | ||
diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h index 65c2431ea32f..1051bebff1b0 100644 --- a/fs/nfsd/netns.h +++ b/fs/nfsd/netns.h | |||
| @@ -24,7 +24,18 @@ | |||
| 24 | #include <net/net_namespace.h> | 24 | #include <net/net_namespace.h> |
| 25 | #include <net/netns/generic.h> | 25 | #include <net/netns/generic.h> |
| 26 | 26 | ||
| 27 | /* Hash tables for nfs4_clientid state */ | ||
| 28 | #define CLIENT_HASH_BITS 4 | ||
| 29 | #define CLIENT_HASH_SIZE (1 << CLIENT_HASH_BITS) | ||
| 30 | #define CLIENT_HASH_MASK (CLIENT_HASH_SIZE - 1) | ||
| 31 | |||
| 32 | #define LOCKOWNER_INO_HASH_BITS 8 | ||
| 33 | #define LOCKOWNER_INO_HASH_SIZE (1 << LOCKOWNER_INO_HASH_BITS) | ||
| 34 | |||
| 35 | #define SESSION_HASH_SIZE 512 | ||
| 36 | |||
| 27 | struct cld_net; | 37 | struct cld_net; |
| 38 | struct nfsd4_client_tracking_ops; | ||
| 28 | 39 | ||
| 29 | struct nfsd_net { | 40 | struct nfsd_net { |
| 30 | struct cld_net *cld_net; | 41 | struct cld_net *cld_net; |
| @@ -38,7 +49,62 @@ struct nfsd_net { | |||
| 38 | struct lock_manager nfsd4_manager; | 49 | struct lock_manager nfsd4_manager; |
| 39 | bool grace_ended; | 50 | bool grace_ended; |
| 40 | time_t boot_time; | 51 | time_t boot_time; |
| 52 | |||
| 53 | /* | ||
| 54 | * reclaim_str_hashtbl[] holds known client info from previous reset/reboot | ||
| 55 | * used in reboot/reset lease grace period processing | ||
| 56 | * | ||
| 57 | * conf_id_hashtbl[], and conf_name_tree hold confirmed | ||
| 58 | * setclientid_confirmed info. | ||
| 59 | * | ||
| 60 | * unconf_str_hastbl[] and unconf_name_tree hold unconfirmed | ||
| 61 | * setclientid info. | ||
| 62 | */ | ||
| 63 | struct list_head *reclaim_str_hashtbl; | ||
| 64 | int reclaim_str_hashtbl_size; | ||
| 65 | struct list_head *conf_id_hashtbl; | ||
| 66 | struct rb_root conf_name_tree; | ||
| 67 | struct list_head *unconf_id_hashtbl; | ||
| 68 | struct rb_root unconf_name_tree; | ||
| 69 | struct list_head *ownerstr_hashtbl; | ||
| 70 | struct list_head *lockowner_ino_hashtbl; | ||
| 71 | struct list_head *sessionid_hashtbl; | ||
| 72 | /* | ||
| 73 | * client_lru holds client queue ordered by nfs4_client.cl_time | ||
| 74 | * for lease renewal. | ||
| 75 | * | ||
| 76 | * close_lru holds (open) stateowner queue ordered by nfs4_stateowner.so_time | ||
| 77 | * for last close replay. | ||
| 78 | * | ||
| 79 | * All of the above fields are protected by the client_mutex. | ||
| 80 | */ | ||
| 81 | struct list_head client_lru; | ||
| 82 | struct list_head close_lru; | ||
| 83 | |||
| 84 | struct delayed_work laundromat_work; | ||
| 85 | |||
| 86 | /* client_lock protects the client lru list and session hash table */ | ||
| 87 | spinlock_t client_lock; | ||
| 88 | |||
| 89 | struct file *rec_file; | ||
| 90 | bool in_grace; | ||
| 91 | struct nfsd4_client_tracking_ops *client_tracking_ops; | ||
| 92 | |||
| 93 | time_t nfsd4_lease; | ||
| 94 | time_t nfsd4_grace; | ||
| 95 | |||
| 96 | bool nfsd_net_up; | ||
| 97 | |||
| 98 | /* | ||
| 99 | * Time of server startup | ||
| 100 | */ | ||
| 101 | struct timeval nfssvc_boot; | ||
| 102 | |||
| 103 | struct svc_serv *nfsd_serv; | ||
| 41 | }; | 104 | }; |
| 42 | 105 | ||
| 106 | /* Simple check to find out if a given net was properly initialized */ | ||
| 107 | #define nfsd_netns_ready(nn) ((nn)->sessionid_hashtbl) | ||
| 108 | |||
| 43 | extern int nfsd_net_id; | 109 | extern int nfsd_net_id; |
| 44 | #endif /* __NFSD_NETNS_H__ */ | 110 | #endif /* __NFSD_NETNS_H__ */ |
diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c index b314888825d5..9170861c804a 100644 --- a/fs/nfsd/nfs2acl.c +++ b/fs/nfsd/nfs2acl.c | |||
| @@ -253,7 +253,7 @@ static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p, | |||
| 253 | (resp->mask & NFS_ACL) ? resp->acl_access : NULL, | 253 | (resp->mask & NFS_ACL) ? resp->acl_access : NULL, |
| 254 | (resp->mask & NFS_DFACL) ? resp->acl_default : NULL); | 254 | (resp->mask & NFS_DFACL) ? resp->acl_default : NULL); |
| 255 | while (w > 0) { | 255 | while (w > 0) { |
| 256 | if (!rqstp->rq_respages[rqstp->rq_resused++]) | 256 | if (!*(rqstp->rq_next_page++)) |
| 257 | return 0; | 257 | return 0; |
| 258 | w -= PAGE_SIZE; | 258 | w -= PAGE_SIZE; |
| 259 | } | 259 | } |
diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c index a596e9d987e4..9cbc1a841f87 100644 --- a/fs/nfsd/nfs3acl.c +++ b/fs/nfsd/nfs3acl.c | |||
| @@ -184,7 +184,7 @@ static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p, | |||
| 184 | (resp->mask & NFS_ACL) ? resp->acl_access : NULL, | 184 | (resp->mask & NFS_ACL) ? resp->acl_access : NULL, |
| 185 | (resp->mask & NFS_DFACL) ? resp->acl_default : NULL); | 185 | (resp->mask & NFS_DFACL) ? resp->acl_default : NULL); |
| 186 | while (w > 0) { | 186 | while (w > 0) { |
| 187 | if (!rqstp->rq_respages[rqstp->rq_resused++]) | 187 | if (!*(rqstp->rq_next_page++)) |
| 188 | return 0; | 188 | return 0; |
| 189 | w -= PAGE_SIZE; | 189 | w -= PAGE_SIZE; |
| 190 | } | 190 | } |
diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c index 97d90d1c8608..1fc02dfdc5c4 100644 --- a/fs/nfsd/nfs3proc.c +++ b/fs/nfsd/nfs3proc.c | |||
| @@ -460,7 +460,7 @@ nfsd3_proc_readdirplus(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp, | |||
| 460 | __be32 nfserr; | 460 | __be32 nfserr; |
| 461 | int count = 0; | 461 | int count = 0; |
| 462 | loff_t offset; | 462 | loff_t offset; |
| 463 | int i; | 463 | struct page **p; |
| 464 | caddr_t page_addr = NULL; | 464 | caddr_t page_addr = NULL; |
| 465 | 465 | ||
| 466 | dprintk("nfsd: READDIR+(3) %s %d bytes at %d\n", | 466 | 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, | |||
| 484 | &resp->common, | 484 | &resp->common, |
| 485 | nfs3svc_encode_entry_plus); | 485 | nfs3svc_encode_entry_plus); |
| 486 | memcpy(resp->verf, argp->verf, 8); | 486 | memcpy(resp->verf, argp->verf, 8); |
| 487 | for (i=1; i<rqstp->rq_resused ; i++) { | 487 | for (p = rqstp->rq_respages + 1; p < rqstp->rq_next_page; p++) { |
| 488 | page_addr = page_address(rqstp->rq_respages[i]); | 488 | page_addr = page_address(*p); |
| 489 | 489 | ||
| 490 | if (((caddr_t)resp->buffer >= page_addr) && | 490 | if (((caddr_t)resp->buffer >= page_addr) && |
| 491 | ((caddr_t)resp->buffer < page_addr + PAGE_SIZE)) { | 491 | ((caddr_t)resp->buffer < page_addr + PAGE_SIZE)) { |
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index 43f46cd9edea..324c0baf7cda 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c | |||
| @@ -7,8 +7,10 @@ | |||
| 7 | */ | 7 | */ |
| 8 | 8 | ||
| 9 | #include <linux/namei.h> | 9 | #include <linux/namei.h> |
| 10 | #include <linux/sunrpc/svc_xprt.h> | ||
| 10 | #include "xdr3.h" | 11 | #include "xdr3.h" |
| 11 | #include "auth.h" | 12 | #include "auth.h" |
| 13 | #include "netns.h" | ||
| 12 | 14 | ||
| 13 | #define NFSDDBG_FACILITY NFSDDBG_XDR | 15 | #define NFSDDBG_FACILITY NFSDDBG_XDR |
| 14 | 16 | ||
| @@ -323,7 +325,7 @@ nfs3svc_decode_readargs(struct svc_rqst *rqstp, __be32 *p, | |||
| 323 | struct nfsd3_readargs *args) | 325 | struct nfsd3_readargs *args) |
| 324 | { | 326 | { |
| 325 | unsigned int len; | 327 | unsigned int len; |
| 326 | int v,pn; | 328 | int v; |
| 327 | u32 max_blocksize = svc_max_payload(rqstp); | 329 | u32 max_blocksize = svc_max_payload(rqstp); |
| 328 | 330 | ||
| 329 | if (!(p = decode_fh(p, &args->fh))) | 331 | if (!(p = decode_fh(p, &args->fh))) |
| @@ -338,8 +340,9 @@ nfs3svc_decode_readargs(struct svc_rqst *rqstp, __be32 *p, | |||
| 338 | /* set up the kvec */ | 340 | /* set up the kvec */ |
| 339 | v=0; | 341 | v=0; |
| 340 | while (len > 0) { | 342 | while (len > 0) { |
| 341 | pn = rqstp->rq_resused++; | 343 | struct page *p = *(rqstp->rq_next_page++); |
| 342 | rqstp->rq_vec[v].iov_base = page_address(rqstp->rq_respages[pn]); | 344 | |
| 345 | rqstp->rq_vec[v].iov_base = page_address(p); | ||
| 343 | rqstp->rq_vec[v].iov_len = len < PAGE_SIZE? len : PAGE_SIZE; | 346 | rqstp->rq_vec[v].iov_len = len < PAGE_SIZE? len : PAGE_SIZE; |
| 344 | len -= rqstp->rq_vec[v].iov_len; | 347 | len -= rqstp->rq_vec[v].iov_len; |
| 345 | v++; | 348 | v++; |
| @@ -461,8 +464,7 @@ nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p, | |||
| 461 | len = ntohl(*p++); | 464 | len = ntohl(*p++); |
| 462 | if (len == 0 || len > NFS3_MAXPATHLEN || len >= PAGE_SIZE) | 465 | if (len == 0 || len > NFS3_MAXPATHLEN || len >= PAGE_SIZE) |
| 463 | return 0; | 466 | return 0; |
| 464 | args->tname = new = | 467 | args->tname = new = page_address(*(rqstp->rq_next_page++)); |
| 465 | page_address(rqstp->rq_respages[rqstp->rq_resused++]); | ||
| 466 | args->tlen = len; | 468 | args->tlen = len; |
| 467 | /* first copy and check from the first page */ | 469 | /* first copy and check from the first page */ |
| 468 | old = (char*)p; | 470 | old = (char*)p; |
| @@ -533,8 +535,7 @@ nfs3svc_decode_readlinkargs(struct svc_rqst *rqstp, __be32 *p, | |||
| 533 | { | 535 | { |
| 534 | if (!(p = decode_fh(p, &args->fh))) | 536 | if (!(p = decode_fh(p, &args->fh))) |
| 535 | return 0; | 537 | return 0; |
| 536 | args->buffer = | 538 | args->buffer = page_address(*(rqstp->rq_next_page++)); |
| 537 | page_address(rqstp->rq_respages[rqstp->rq_resused++]); | ||
| 538 | 539 | ||
| 539 | return xdr_argsize_check(rqstp, p); | 540 | return xdr_argsize_check(rqstp, p); |
| 540 | } | 541 | } |
| @@ -565,8 +566,7 @@ nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p, | |||
| 565 | if (args->count > PAGE_SIZE) | 566 | if (args->count > PAGE_SIZE) |
| 566 | args->count = PAGE_SIZE; | 567 | args->count = PAGE_SIZE; |
| 567 | 568 | ||
| 568 | args->buffer = | 569 | args->buffer = page_address(*(rqstp->rq_next_page++)); |
| 569 | page_address(rqstp->rq_respages[rqstp->rq_resused++]); | ||
| 570 | 570 | ||
| 571 | return xdr_argsize_check(rqstp, p); | 571 | return xdr_argsize_check(rqstp, p); |
| 572 | } | 572 | } |
| @@ -575,7 +575,7 @@ int | |||
| 575 | nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, __be32 *p, | 575 | nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, __be32 *p, |
| 576 | struct nfsd3_readdirargs *args) | 576 | struct nfsd3_readdirargs *args) |
| 577 | { | 577 | { |
| 578 | int len, pn; | 578 | int len; |
| 579 | u32 max_blocksize = svc_max_payload(rqstp); | 579 | u32 max_blocksize = svc_max_payload(rqstp); |
| 580 | 580 | ||
| 581 | if (!(p = decode_fh(p, &args->fh))) | 581 | if (!(p = decode_fh(p, &args->fh))) |
| @@ -590,9 +590,9 @@ nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, __be32 *p, | |||
| 590 | args->count = len; | 590 | args->count = len; |
| 591 | 591 | ||
| 592 | while (len > 0) { | 592 | while (len > 0) { |
| 593 | pn = rqstp->rq_resused++; | 593 | struct page *p = *(rqstp->rq_next_page++); |
| 594 | if (!args->buffer) | 594 | if (!args->buffer) |
| 595 | args->buffer = page_address(rqstp->rq_respages[pn]); | 595 | args->buffer = page_address(p); |
| 596 | len -= PAGE_SIZE; | 596 | len -= PAGE_SIZE; |
| 597 | } | 597 | } |
| 598 | 598 | ||
| @@ -720,12 +720,14 @@ int | |||
| 720 | nfs3svc_encode_writeres(struct svc_rqst *rqstp, __be32 *p, | 720 | nfs3svc_encode_writeres(struct svc_rqst *rqstp, __be32 *p, |
| 721 | struct nfsd3_writeres *resp) | 721 | struct nfsd3_writeres *resp) |
| 722 | { | 722 | { |
| 723 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | ||
| 724 | |||
| 723 | p = encode_wcc_data(rqstp, p, &resp->fh); | 725 | p = encode_wcc_data(rqstp, p, &resp->fh); |
| 724 | if (resp->status == 0) { | 726 | if (resp->status == 0) { |
| 725 | *p++ = htonl(resp->count); | 727 | *p++ = htonl(resp->count); |
| 726 | *p++ = htonl(resp->committed); | 728 | *p++ = htonl(resp->committed); |
| 727 | *p++ = htonl(nfssvc_boot.tv_sec); | 729 | *p++ = htonl(nn->nfssvc_boot.tv_sec); |
| 728 | *p++ = htonl(nfssvc_boot.tv_usec); | 730 | *p++ = htonl(nn->nfssvc_boot.tv_usec); |
| 729 | } | 731 | } |
| 730 | return xdr_ressize_check(rqstp, p); | 732 | return xdr_ressize_check(rqstp, p); |
| 731 | } | 733 | } |
| @@ -876,7 +878,7 @@ encode_entry(struct readdir_cd *ccd, const char *name, int namlen, | |||
| 876 | common); | 878 | common); |
| 877 | __be32 *p = cd->buffer; | 879 | __be32 *p = cd->buffer; |
| 878 | caddr_t curr_page_addr = NULL; | 880 | caddr_t curr_page_addr = NULL; |
| 879 | int pn; /* current page number */ | 881 | struct page ** page; |
| 880 | int slen; /* string (name) length */ | 882 | int slen; /* string (name) length */ |
| 881 | int elen; /* estimated entry length in words */ | 883 | int elen; /* estimated entry length in words */ |
| 882 | int num_entry_words = 0; /* actual number of words */ | 884 | int num_entry_words = 0; /* actual number of words */ |
| @@ -913,8 +915,9 @@ encode_entry(struct readdir_cd *ccd, const char *name, int namlen, | |||
| 913 | } | 915 | } |
| 914 | 916 | ||
| 915 | /* determine which page in rq_respages[] we are currently filling */ | 917 | /* determine which page in rq_respages[] we are currently filling */ |
| 916 | for (pn=1; pn < cd->rqstp->rq_resused; pn++) { | 918 | for (page = cd->rqstp->rq_respages + 1; |
| 917 | curr_page_addr = page_address(cd->rqstp->rq_respages[pn]); | 919 | page < cd->rqstp->rq_next_page; page++) { |
| 920 | curr_page_addr = page_address(*page); | ||
| 918 | 921 | ||
| 919 | if (((caddr_t)cd->buffer >= curr_page_addr) && | 922 | if (((caddr_t)cd->buffer >= curr_page_addr) && |
| 920 | ((caddr_t)cd->buffer < curr_page_addr + PAGE_SIZE)) | 923 | ((caddr_t)cd->buffer < curr_page_addr + PAGE_SIZE)) |
| @@ -929,14 +932,14 @@ encode_entry(struct readdir_cd *ccd, const char *name, int namlen, | |||
| 929 | if (plus) | 932 | if (plus) |
| 930 | p = encode_entryplus_baggage(cd, p, name, namlen); | 933 | p = encode_entryplus_baggage(cd, p, name, namlen); |
| 931 | num_entry_words = p - cd->buffer; | 934 | num_entry_words = p - cd->buffer; |
| 932 | } else if (cd->rqstp->rq_respages[pn+1] != NULL) { | 935 | } else if (*(page+1) != NULL) { |
| 933 | /* temporarily encode entry into next page, then move back to | 936 | /* temporarily encode entry into next page, then move back to |
| 934 | * current and next page in rq_respages[] */ | 937 | * current and next page in rq_respages[] */ |
| 935 | __be32 *p1, *tmp; | 938 | __be32 *p1, *tmp; |
| 936 | int len1, len2; | 939 | int len1, len2; |
| 937 | 940 | ||
| 938 | /* grab next page for temporary storage of entry */ | 941 | /* grab next page for temporary storage of entry */ |
| 939 | p1 = tmp = page_address(cd->rqstp->rq_respages[pn+1]); | 942 | p1 = tmp = page_address(*(page+1)); |
| 940 | 943 | ||
| 941 | p1 = encode_entry_baggage(cd, p1, name, namlen, ino); | 944 | p1 = encode_entry_baggage(cd, p1, name, namlen, ino); |
| 942 | 945 | ||
| @@ -1082,11 +1085,13 @@ int | |||
| 1082 | nfs3svc_encode_commitres(struct svc_rqst *rqstp, __be32 *p, | 1085 | nfs3svc_encode_commitres(struct svc_rqst *rqstp, __be32 *p, |
| 1083 | struct nfsd3_commitres *resp) | 1086 | struct nfsd3_commitres *resp) |
| 1084 | { | 1087 | { |
| 1088 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | ||
| 1089 | |||
| 1085 | p = encode_wcc_data(rqstp, p, &resp->fh); | 1090 | p = encode_wcc_data(rqstp, p, &resp->fh); |
| 1086 | /* Write verifier */ | 1091 | /* Write verifier */ |
| 1087 | if (resp->status == 0) { | 1092 | if (resp->status == 0) { |
| 1088 | *p++ = htonl(nfssvc_boot.tv_sec); | 1093 | *p++ = htonl(nn->nfssvc_boot.tv_sec); |
| 1089 | *p++ = htonl(nfssvc_boot.tv_usec); | 1094 | *p++ = htonl(nn->nfssvc_boot.tv_usec); |
| 1090 | } | 1095 | } |
| 1091 | return xdr_ressize_check(rqstp, p); | 1096 | return xdr_ressize_check(rqstp, p); |
| 1092 | } | 1097 | } |
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index bdf29c96e4cd..99bc85ff0217 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c | |||
| @@ -36,6 +36,7 @@ | |||
| 36 | #include <linux/slab.h> | 36 | #include <linux/slab.h> |
| 37 | #include "nfsd.h" | 37 | #include "nfsd.h" |
| 38 | #include "state.h" | 38 | #include "state.h" |
| 39 | #include "netns.h" | ||
| 39 | 40 | ||
| 40 | #define NFSDDBG_FACILITY NFSDDBG_PROC | 41 | #define NFSDDBG_FACILITY NFSDDBG_PROC |
| 41 | 42 | ||
| @@ -625,20 +626,46 @@ static const struct rpc_program cb_program = { | |||
| 625 | .pipe_dir_name = "nfsd4_cb", | 626 | .pipe_dir_name = "nfsd4_cb", |
| 626 | }; | 627 | }; |
| 627 | 628 | ||
| 628 | static int max_cb_time(void) | 629 | static int max_cb_time(struct net *net) |
| 629 | { | 630 | { |
| 630 | return max(nfsd4_lease/10, (time_t)1) * HZ; | 631 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); |
| 632 | return max(nn->nfsd4_lease/10, (time_t)1) * HZ; | ||
| 631 | } | 633 | } |
| 632 | 634 | ||
| 635 | static struct rpc_cred *callback_cred; | ||
| 636 | |||
| 637 | int set_callback_cred(void) | ||
| 638 | { | ||
| 639 | if (callback_cred) | ||
| 640 | return 0; | ||
| 641 | callback_cred = rpc_lookup_machine_cred("nfs"); | ||
| 642 | if (!callback_cred) | ||
| 643 | return -ENOMEM; | ||
| 644 | return 0; | ||
| 645 | } | ||
| 646 | |||
| 647 | static struct rpc_cred *get_backchannel_cred(struct nfs4_client *clp, struct rpc_clnt *client, struct nfsd4_session *ses) | ||
| 648 | { | ||
| 649 | if (clp->cl_minorversion == 0) { | ||
| 650 | return get_rpccred(callback_cred); | ||
| 651 | } else { | ||
| 652 | struct rpc_auth *auth = client->cl_auth; | ||
| 653 | struct auth_cred acred = {}; | ||
| 654 | |||
| 655 | acred.uid = ses->se_cb_sec.uid; | ||
| 656 | acred.gid = ses->se_cb_sec.gid; | ||
| 657 | return auth->au_ops->lookup_cred(client->cl_auth, &acred, 0); | ||
| 658 | } | ||
| 659 | } | ||
| 633 | 660 | ||
| 634 | static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *conn, struct nfsd4_session *ses) | 661 | static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *conn, struct nfsd4_session *ses) |
| 635 | { | 662 | { |
| 636 | struct rpc_timeout timeparms = { | 663 | struct rpc_timeout timeparms = { |
| 637 | .to_initval = max_cb_time(), | 664 | .to_initval = max_cb_time(clp->net), |
| 638 | .to_retries = 0, | 665 | .to_retries = 0, |
| 639 | }; | 666 | }; |
| 640 | struct rpc_create_args args = { | 667 | struct rpc_create_args args = { |
| 641 | .net = &init_net, | 668 | .net = clp->net, |
| 642 | .address = (struct sockaddr *) &conn->cb_addr, | 669 | .address = (struct sockaddr *) &conn->cb_addr, |
| 643 | .addrsize = conn->cb_addrlen, | 670 | .addrsize = conn->cb_addrlen, |
| 644 | .saddress = (struct sockaddr *) &conn->cb_saddr, | 671 | .saddress = (struct sockaddr *) &conn->cb_saddr, |
| @@ -648,6 +675,7 @@ static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *c | |||
| 648 | .flags = (RPC_CLNT_CREATE_NOPING | RPC_CLNT_CREATE_QUIET), | 675 | .flags = (RPC_CLNT_CREATE_NOPING | RPC_CLNT_CREATE_QUIET), |
| 649 | }; | 676 | }; |
| 650 | struct rpc_clnt *client; | 677 | struct rpc_clnt *client; |
| 678 | struct rpc_cred *cred; | ||
| 651 | 679 | ||
| 652 | if (clp->cl_minorversion == 0) { | 680 | if (clp->cl_minorversion == 0) { |
| 653 | if (!clp->cl_cred.cr_principal && | 681 | if (!clp->cl_cred.cr_principal && |
| @@ -666,7 +694,7 @@ static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *c | |||
| 666 | args.bc_xprt = conn->cb_xprt; | 694 | args.bc_xprt = conn->cb_xprt; |
| 667 | args.prognumber = clp->cl_cb_session->se_cb_prog; | 695 | args.prognumber = clp->cl_cb_session->se_cb_prog; |
| 668 | args.protocol = XPRT_TRANSPORT_BC_TCP; | 696 | args.protocol = XPRT_TRANSPORT_BC_TCP; |
| 669 | args.authflavor = RPC_AUTH_UNIX; | 697 | args.authflavor = ses->se_cb_sec.flavor; |
| 670 | } | 698 | } |
| 671 | /* Create RPC client */ | 699 | /* Create RPC client */ |
| 672 | client = rpc_create(&args); | 700 | client = rpc_create(&args); |
| @@ -675,9 +703,14 @@ static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *c | |||
| 675 | PTR_ERR(client)); | 703 | PTR_ERR(client)); |
| 676 | return PTR_ERR(client); | 704 | return PTR_ERR(client); |
| 677 | } | 705 | } |
| 706 | cred = get_backchannel_cred(clp, client, ses); | ||
| 707 | if (IS_ERR(cred)) { | ||
| 708 | rpc_shutdown_client(client); | ||
| 709 | return PTR_ERR(cred); | ||
| 710 | } | ||
| 678 | clp->cl_cb_client = client; | 711 | clp->cl_cb_client = client; |
| 712 | clp->cl_cb_cred = cred; | ||
| 679 | return 0; | 713 | return 0; |
| 680 | |||
| 681 | } | 714 | } |
| 682 | 715 | ||
| 683 | static void warn_no_callback_path(struct nfs4_client *clp, int reason) | 716 | 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 = { | |||
| 714 | .rpc_call_done = nfsd4_cb_probe_done, | 747 | .rpc_call_done = nfsd4_cb_probe_done, |
| 715 | }; | 748 | }; |
| 716 | 749 | ||
| 717 | static struct rpc_cred *callback_cred; | ||
| 718 | |||
| 719 | int set_callback_cred(void) | ||
| 720 | { | ||
| 721 | if (callback_cred) | ||
| 722 | return 0; | ||
| 723 | callback_cred = rpc_lookup_machine_cred("nfs"); | ||
| 724 | if (!callback_cred) | ||
| 725 | return -ENOMEM; | ||
| 726 | return 0; | ||
| 727 | } | ||
| 728 | |||
| 729 | static struct workqueue_struct *callback_wq; | 750 | static struct workqueue_struct *callback_wq; |
| 730 | 751 | ||
| 731 | static void run_nfsd4_cb(struct nfsd4_callback *cb) | 752 | static void run_nfsd4_cb(struct nfsd4_callback *cb) |
| @@ -743,7 +764,6 @@ static void do_probe_callback(struct nfs4_client *clp) | |||
| 743 | cb->cb_msg.rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL]; | 764 | cb->cb_msg.rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL]; |
| 744 | cb->cb_msg.rpc_argp = NULL; | 765 | cb->cb_msg.rpc_argp = NULL; |
| 745 | cb->cb_msg.rpc_resp = NULL; | 766 | cb->cb_msg.rpc_resp = NULL; |
| 746 | cb->cb_msg.rpc_cred = callback_cred; | ||
| 747 | 767 | ||
| 748 | cb->cb_ops = &nfsd4_cb_probe_ops; | 768 | cb->cb_ops = &nfsd4_cb_probe_ops; |
| 749 | 769 | ||
| @@ -962,6 +982,8 @@ static void nfsd4_process_cb_update(struct nfsd4_callback *cb) | |||
| 962 | if (clp->cl_cb_client) { | 982 | if (clp->cl_cb_client) { |
| 963 | rpc_shutdown_client(clp->cl_cb_client); | 983 | rpc_shutdown_client(clp->cl_cb_client); |
| 964 | clp->cl_cb_client = NULL; | 984 | clp->cl_cb_client = NULL; |
| 985 | put_rpccred(clp->cl_cb_cred); | ||
| 986 | clp->cl_cb_cred = NULL; | ||
| 965 | } | 987 | } |
| 966 | if (clp->cl_cb_conn.cb_xprt) { | 988 | if (clp->cl_cb_conn.cb_xprt) { |
| 967 | svc_xprt_put(clp->cl_cb_conn.cb_xprt); | 989 | svc_xprt_put(clp->cl_cb_conn.cb_xprt); |
| @@ -995,7 +1017,7 @@ static void nfsd4_process_cb_update(struct nfsd4_callback *cb) | |||
| 995 | run_nfsd4_cb(cb); | 1017 | run_nfsd4_cb(cb); |
| 996 | } | 1018 | } |
| 997 | 1019 | ||
| 998 | void nfsd4_do_callback_rpc(struct work_struct *w) | 1020 | static void nfsd4_do_callback_rpc(struct work_struct *w) |
| 999 | { | 1021 | { |
| 1000 | struct nfsd4_callback *cb = container_of(w, struct nfsd4_callback, cb_work); | 1022 | struct nfsd4_callback *cb = container_of(w, struct nfsd4_callback, cb_work); |
| 1001 | struct nfs4_client *clp = cb->cb_clp; | 1023 | struct nfs4_client *clp = cb->cb_clp; |
| @@ -1010,10 +1032,16 @@ void nfsd4_do_callback_rpc(struct work_struct *w) | |||
| 1010 | nfsd4_release_cb(cb); | 1032 | nfsd4_release_cb(cb); |
| 1011 | return; | 1033 | return; |
| 1012 | } | 1034 | } |
| 1035 | cb->cb_msg.rpc_cred = clp->cl_cb_cred; | ||
| 1013 | rpc_call_async(clnt, &cb->cb_msg, RPC_TASK_SOFT | RPC_TASK_SOFTCONN, | 1036 | rpc_call_async(clnt, &cb->cb_msg, RPC_TASK_SOFT | RPC_TASK_SOFTCONN, |
| 1014 | cb->cb_ops, cb); | 1037 | cb->cb_ops, cb); |
| 1015 | } | 1038 | } |
| 1016 | 1039 | ||
| 1040 | void nfsd4_init_callback(struct nfsd4_callback *cb) | ||
| 1041 | { | ||
| 1042 | INIT_WORK(&cb->cb_work, nfsd4_do_callback_rpc); | ||
| 1043 | } | ||
| 1044 | |||
| 1017 | void nfsd4_cb_recall(struct nfs4_delegation *dp) | 1045 | void nfsd4_cb_recall(struct nfs4_delegation *dp) |
| 1018 | { | 1046 | { |
| 1019 | struct nfsd4_callback *cb = &dp->dl_recall; | 1047 | struct nfsd4_callback *cb = &dp->dl_recall; |
| @@ -1025,7 +1053,6 @@ void nfsd4_cb_recall(struct nfs4_delegation *dp) | |||
| 1025 | cb->cb_msg.rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL]; | 1053 | cb->cb_msg.rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL]; |
| 1026 | cb->cb_msg.rpc_argp = cb; | 1054 | cb->cb_msg.rpc_argp = cb; |
| 1027 | cb->cb_msg.rpc_resp = cb; | 1055 | cb->cb_msg.rpc_resp = cb; |
| 1028 | cb->cb_msg.rpc_cred = callback_cred; | ||
| 1029 | 1056 | ||
| 1030 | cb->cb_ops = &nfsd4_cb_recall_ops; | 1057 | cb->cb_ops = &nfsd4_cb_recall_ops; |
| 1031 | 1058 | ||
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 6c9a4b291dba..9d1c5dba2bbb 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c | |||
| @@ -40,6 +40,7 @@ | |||
| 40 | #include "xdr4.h" | 40 | #include "xdr4.h" |
| 41 | #include "vfs.h" | 41 | #include "vfs.h" |
| 42 | #include "current_stateid.h" | 42 | #include "current_stateid.h" |
| 43 | #include "netns.h" | ||
| 43 | 44 | ||
| 44 | #define NFSDDBG_FACILITY NFSDDBG_PROC | 45 | #define NFSDDBG_FACILITY NFSDDBG_PROC |
| 45 | 46 | ||
| @@ -194,6 +195,7 @@ static __be32 | |||
| 194 | do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) | 195 | do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) |
| 195 | { | 196 | { |
| 196 | struct svc_fh *resfh; | 197 | struct svc_fh *resfh; |
| 198 | int accmode; | ||
| 197 | __be32 status; | 199 | __be32 status; |
| 198 | 200 | ||
| 199 | resfh = kmalloc(sizeof(struct svc_fh), GFP_KERNEL); | 201 | 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 | |||
| 253 | /* set reply cache */ | 255 | /* set reply cache */ |
| 254 | fh_copy_shallow(&open->op_openowner->oo_owner.so_replay.rp_openfh, | 256 | fh_copy_shallow(&open->op_openowner->oo_owner.so_replay.rp_openfh, |
| 255 | &resfh->fh_handle); | 257 | &resfh->fh_handle); |
| 256 | if (!open->op_created) | 258 | accmode = NFSD_MAY_NOP; |
| 257 | status = do_open_permission(rqstp, resfh, open, | 259 | if (open->op_created) |
| 258 | NFSD_MAY_NOP); | 260 | accmode |= NFSD_MAY_OWNER_OVERRIDE; |
| 261 | status = do_open_permission(rqstp, resfh, open, accmode); | ||
| 259 | set_change_info(&open->op_cinfo, current_fh); | 262 | set_change_info(&open->op_cinfo, current_fh); |
| 260 | fh_dup2(current_fh, resfh); | 263 | fh_dup2(current_fh, resfh); |
| 261 | out: | 264 | out: |
| @@ -304,6 +307,8 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
| 304 | { | 307 | { |
| 305 | __be32 status; | 308 | __be32 status; |
| 306 | struct nfsd4_compoundres *resp; | 309 | struct nfsd4_compoundres *resp; |
| 310 | struct net *net = SVC_NET(rqstp); | ||
| 311 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
| 307 | 312 | ||
| 308 | dprintk("NFSD: nfsd4_open filename %.*s op_openowner %p\n", | 313 | dprintk("NFSD: nfsd4_open filename %.*s op_openowner %p\n", |
| 309 | (int)open->op_fname.len, open->op_fname.data, | 314 | (int)open->op_fname.len, open->op_fname.data, |
| @@ -331,7 +336,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
| 331 | 336 | ||
| 332 | /* check seqid for replay. set nfs4_owner */ | 337 | /* check seqid for replay. set nfs4_owner */ |
| 333 | resp = rqstp->rq_resp; | 338 | resp = rqstp->rq_resp; |
| 334 | status = nfsd4_process_open1(&resp->cstate, open); | 339 | status = nfsd4_process_open1(&resp->cstate, open, nn); |
| 335 | if (status == nfserr_replay_me) { | 340 | if (status == nfserr_replay_me) { |
| 336 | struct nfs4_replay *rp = &open->op_openowner->oo_owner.so_replay; | 341 | struct nfs4_replay *rp = &open->op_openowner->oo_owner.so_replay; |
| 337 | fh_put(&cstate->current_fh); | 342 | fh_put(&cstate->current_fh); |
| @@ -354,10 +359,10 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
| 354 | /* Openowner is now set, so sequence id will get bumped. Now we need | 359 | /* Openowner is now set, so sequence id will get bumped. Now we need |
| 355 | * these checks before we do any creates: */ | 360 | * these checks before we do any creates: */ |
| 356 | status = nfserr_grace; | 361 | status = nfserr_grace; |
| 357 | if (locks_in_grace(SVC_NET(rqstp)) && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS) | 362 | if (locks_in_grace(net) && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS) |
| 358 | goto out; | 363 | goto out; |
| 359 | status = nfserr_no_grace; | 364 | status = nfserr_no_grace; |
| 360 | if (!locks_in_grace(SVC_NET(rqstp)) && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) | 365 | if (!locks_in_grace(net) && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) |
| 361 | goto out; | 366 | goto out; |
| 362 | 367 | ||
| 363 | switch (open->op_claim_type) { | 368 | switch (open->op_claim_type) { |
| @@ -370,7 +375,9 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
| 370 | break; | 375 | break; |
| 371 | case NFS4_OPEN_CLAIM_PREVIOUS: | 376 | case NFS4_OPEN_CLAIM_PREVIOUS: |
| 372 | open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; | 377 | open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; |
| 373 | status = nfs4_check_open_reclaim(&open->op_clientid, cstate->minorversion); | 378 | status = nfs4_check_open_reclaim(&open->op_clientid, |
| 379 | cstate->minorversion, | ||
| 380 | nn); | ||
| 374 | if (status) | 381 | if (status) |
| 375 | goto out; | 382 | goto out; |
| 376 | case NFS4_OPEN_CLAIM_FH: | 383 | case NFS4_OPEN_CLAIM_FH: |
| @@ -490,12 +497,13 @@ nfsd4_access(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
| 490 | &access->ac_supported); | 497 | &access->ac_supported); |
| 491 | } | 498 | } |
| 492 | 499 | ||
| 493 | static void gen_boot_verifier(nfs4_verifier *verifier) | 500 | static void gen_boot_verifier(nfs4_verifier *verifier, struct net *net) |
| 494 | { | 501 | { |
| 495 | __be32 verf[2]; | 502 | __be32 verf[2]; |
| 503 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
| 496 | 504 | ||
| 497 | verf[0] = (__be32)nfssvc_boot.tv_sec; | 505 | verf[0] = (__be32)nn->nfssvc_boot.tv_sec; |
| 498 | verf[1] = (__be32)nfssvc_boot.tv_usec; | 506 | verf[1] = (__be32)nn->nfssvc_boot.tv_usec; |
| 499 | memcpy(verifier->data, verf, sizeof(verifier->data)); | 507 | memcpy(verifier->data, verf, sizeof(verifier->data)); |
| 500 | } | 508 | } |
| 501 | 509 | ||
| @@ -503,7 +511,7 @@ static __be32 | |||
| 503 | nfsd4_commit(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 511 | nfsd4_commit(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
| 504 | struct nfsd4_commit *commit) | 512 | struct nfsd4_commit *commit) |
| 505 | { | 513 | { |
| 506 | gen_boot_verifier(&commit->co_verf); | 514 | gen_boot_verifier(&commit->co_verf, SVC_NET(rqstp)); |
| 507 | return nfsd_commit(rqstp, &cstate->current_fh, commit->co_offset, | 515 | return nfsd_commit(rqstp, &cstate->current_fh, commit->co_offset, |
| 508 | commit->co_count); | 516 | commit->co_count); |
| 509 | } | 517 | } |
| @@ -684,6 +692,17 @@ nfsd4_read(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
| 684 | if (read->rd_offset >= OFFSET_MAX) | 692 | if (read->rd_offset >= OFFSET_MAX) |
| 685 | return nfserr_inval; | 693 | return nfserr_inval; |
| 686 | 694 | ||
| 695 | /* | ||
| 696 | * If we do a zero copy read, then a client will see read data | ||
| 697 | * that reflects the state of the file *after* performing the | ||
| 698 | * following compound. | ||
| 699 | * | ||
| 700 | * To ensure proper ordering, we therefore turn off zero copy if | ||
| 701 | * the client wants us to do more in this compound: | ||
| 702 | */ | ||
| 703 | if (!nfsd4_last_compound_op(rqstp)) | ||
| 704 | rqstp->rq_splice_ok = false; | ||
| 705 | |||
| 687 | nfs4_lock_state(); | 706 | nfs4_lock_state(); |
| 688 | /* check stateid */ | 707 | /* check stateid */ |
| 689 | if ((status = nfs4_preprocess_stateid_op(SVC_NET(rqstp), | 708 | if ((status = nfs4_preprocess_stateid_op(SVC_NET(rqstp), |
| @@ -876,6 +895,24 @@ out: | |||
| 876 | return status; | 895 | return status; |
| 877 | } | 896 | } |
| 878 | 897 | ||
| 898 | static int fill_in_write_vector(struct kvec *vec, struct nfsd4_write *write) | ||
| 899 | { | ||
| 900 | int i = 1; | ||
| 901 | int buflen = write->wr_buflen; | ||
| 902 | |||
| 903 | vec[0].iov_base = write->wr_head.iov_base; | ||
| 904 | vec[0].iov_len = min_t(int, buflen, write->wr_head.iov_len); | ||
| 905 | buflen -= vec[0].iov_len; | ||
| 906 | |||
| 907 | while (buflen) { | ||
| 908 | vec[i].iov_base = page_address(write->wr_pagelist[i - 1]); | ||
| 909 | vec[i].iov_len = min_t(int, PAGE_SIZE, buflen); | ||
| 910 | buflen -= vec[i].iov_len; | ||
| 911 | i++; | ||
| 912 | } | ||
| 913 | return i; | ||
| 914 | } | ||
| 915 | |||
| 879 | static __be32 | 916 | static __be32 |
| 880 | nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 917 | nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
| 881 | struct nfsd4_write *write) | 918 | struct nfsd4_write *write) |
| @@ -884,6 +921,7 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
| 884 | struct file *filp = NULL; | 921 | struct file *filp = NULL; |
| 885 | __be32 status = nfs_ok; | 922 | __be32 status = nfs_ok; |
| 886 | unsigned long cnt; | 923 | unsigned long cnt; |
| 924 | int nvecs; | ||
| 887 | 925 | ||
| 888 | /* no need to check permission - this will be done in nfsd_write() */ | 926 | /* no need to check permission - this will be done in nfsd_write() */ |
| 889 | 927 | ||
| @@ -904,10 +942,13 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
| 904 | 942 | ||
| 905 | cnt = write->wr_buflen; | 943 | cnt = write->wr_buflen; |
| 906 | write->wr_how_written = write->wr_stable_how; | 944 | write->wr_how_written = write->wr_stable_how; |
| 907 | gen_boot_verifier(&write->wr_verifier); | 945 | gen_boot_verifier(&write->wr_verifier, SVC_NET(rqstp)); |
| 946 | |||
| 947 | nvecs = fill_in_write_vector(rqstp->rq_vec, write); | ||
| 948 | WARN_ON_ONCE(nvecs > ARRAY_SIZE(rqstp->rq_vec)); | ||
| 908 | 949 | ||
| 909 | status = nfsd_write(rqstp, &cstate->current_fh, filp, | 950 | status = nfsd_write(rqstp, &cstate->current_fh, filp, |
| 910 | write->wr_offset, rqstp->rq_vec, write->wr_vlen, | 951 | write->wr_offset, rqstp->rq_vec, nvecs, |
| 911 | &cnt, &write->wr_how_written); | 952 | &cnt, &write->wr_how_written); |
| 912 | if (filp) | 953 | if (filp) |
| 913 | fput(filp); | 954 | fput(filp); |
| @@ -1666,6 +1707,12 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
| 1666 | .op_name = "OP_EXCHANGE_ID", | 1707 | .op_name = "OP_EXCHANGE_ID", |
| 1667 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_exchange_id_rsize, | 1708 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_exchange_id_rsize, |
| 1668 | }, | 1709 | }, |
| 1710 | [OP_BACKCHANNEL_CTL] = { | ||
| 1711 | .op_func = (nfsd4op_func)nfsd4_backchannel_ctl, | ||
| 1712 | .op_flags = ALLOWED_WITHOUT_FH | OP_MODIFIES_SOMETHING, | ||
| 1713 | .op_name = "OP_BACKCHANNEL_CTL", | ||
| 1714 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | ||
| 1715 | }, | ||
| 1669 | [OP_BIND_CONN_TO_SESSION] = { | 1716 | [OP_BIND_CONN_TO_SESSION] = { |
| 1670 | .op_func = (nfsd4op_func)nfsd4_bind_conn_to_session, | 1717 | .op_func = (nfsd4op_func)nfsd4_bind_conn_to_session, |
| 1671 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP | 1718 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP |
| @@ -1719,6 +1766,7 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
| 1719 | .op_func = (nfsd4op_func)nfsd4_free_stateid, | 1766 | .op_func = (nfsd4op_func)nfsd4_free_stateid, |
| 1720 | .op_flags = ALLOWED_WITHOUT_FH | OP_MODIFIES_SOMETHING, | 1767 | .op_flags = ALLOWED_WITHOUT_FH | OP_MODIFIES_SOMETHING, |
| 1721 | .op_name = "OP_FREE_STATEID", | 1768 | .op_name = "OP_FREE_STATEID", |
| 1769 | .op_get_currentstateid = (stateid_getter)nfsd4_get_freestateid, | ||
| 1722 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | 1770 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, |
| 1723 | }, | 1771 | }, |
| 1724 | }; | 1772 | }; |
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index 43295d45cc2b..ba6fdd4a0455 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c | |||
| @@ -58,13 +58,11 @@ struct nfsd4_client_tracking_ops { | |||
| 58 | void (*create)(struct nfs4_client *); | 58 | void (*create)(struct nfs4_client *); |
| 59 | void (*remove)(struct nfs4_client *); | 59 | void (*remove)(struct nfs4_client *); |
| 60 | int (*check)(struct nfs4_client *); | 60 | int (*check)(struct nfs4_client *); |
| 61 | void (*grace_done)(struct net *, time_t); | 61 | void (*grace_done)(struct nfsd_net *, time_t); |
| 62 | }; | 62 | }; |
| 63 | 63 | ||
| 64 | /* Globals */ | 64 | /* Globals */ |
| 65 | static struct file *rec_file; | ||
| 66 | static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery"; | 65 | static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery"; |
| 67 | static struct nfsd4_client_tracking_ops *client_tracking_ops; | ||
| 68 | 66 | ||
| 69 | static int | 67 | static int |
| 70 | nfs4_save_creds(const struct cred **original_creds) | 68 | nfs4_save_creds(const struct cred **original_creds) |
| @@ -102,33 +100,39 @@ md5_to_hex(char *out, char *md5) | |||
| 102 | *out = '\0'; | 100 | *out = '\0'; |
| 103 | } | 101 | } |
| 104 | 102 | ||
| 105 | __be32 | 103 | static int |
| 106 | nfs4_make_rec_clidname(char *dname, struct xdr_netobj *clname) | 104 | nfs4_make_rec_clidname(char *dname, const struct xdr_netobj *clname) |
| 107 | { | 105 | { |
| 108 | struct xdr_netobj cksum; | 106 | struct xdr_netobj cksum; |
| 109 | struct hash_desc desc; | 107 | struct hash_desc desc; |
| 110 | struct scatterlist sg; | 108 | struct scatterlist sg; |
| 111 | __be32 status = nfserr_jukebox; | 109 | int status; |
| 112 | 110 | ||
| 113 | dprintk("NFSD: nfs4_make_rec_clidname for %.*s\n", | 111 | dprintk("NFSD: nfs4_make_rec_clidname for %.*s\n", |
| 114 | clname->len, clname->data); | 112 | clname->len, clname->data); |
| 115 | desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP; | 113 | desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP; |
| 116 | desc.tfm = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC); | 114 | desc.tfm = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC); |
| 117 | if (IS_ERR(desc.tfm)) | 115 | if (IS_ERR(desc.tfm)) { |
| 116 | status = PTR_ERR(desc.tfm); | ||
| 118 | goto out_no_tfm; | 117 | goto out_no_tfm; |
| 118 | } | ||
| 119 | |||
| 119 | cksum.len = crypto_hash_digestsize(desc.tfm); | 120 | cksum.len = crypto_hash_digestsize(desc.tfm); |
| 120 | cksum.data = kmalloc(cksum.len, GFP_KERNEL); | 121 | cksum.data = kmalloc(cksum.len, GFP_KERNEL); |
| 121 | if (cksum.data == NULL) | 122 | if (cksum.data == NULL) { |
| 123 | status = -ENOMEM; | ||
| 122 | goto out; | 124 | goto out; |
| 125 | } | ||
| 123 | 126 | ||
| 124 | sg_init_one(&sg, clname->data, clname->len); | 127 | sg_init_one(&sg, clname->data, clname->len); |
| 125 | 128 | ||
| 126 | if (crypto_hash_digest(&desc, &sg, sg.length, cksum.data)) | 129 | status = crypto_hash_digest(&desc, &sg, sg.length, cksum.data); |
| 130 | if (status) | ||
| 127 | goto out; | 131 | goto out; |
| 128 | 132 | ||
| 129 | md5_to_hex(dname, cksum.data); | 133 | md5_to_hex(dname, cksum.data); |
| 130 | 134 | ||
| 131 | status = nfs_ok; | 135 | status = 0; |
| 132 | out: | 136 | out: |
| 133 | kfree(cksum.data); | 137 | kfree(cksum.data); |
| 134 | crypto_free_hash(desc.tfm); | 138 | crypto_free_hash(desc.tfm); |
| @@ -136,29 +140,61 @@ out_no_tfm: | |||
| 136 | return status; | 140 | return status; |
| 137 | } | 141 | } |
| 138 | 142 | ||
| 143 | /* | ||
| 144 | * If we had an error generating the recdir name for the legacy tracker | ||
| 145 | * then warn the admin. If the error doesn't appear to be transient, | ||
| 146 | * then disable recovery tracking. | ||
| 147 | */ | ||
| 148 | static void | ||
| 149 | legacy_recdir_name_error(int error) | ||
| 150 | { | ||
| 151 | printk(KERN_ERR "NFSD: unable to generate recoverydir " | ||
| 152 | "name (%d).\n", error); | ||
| 153 | |||
| 154 | /* | ||
| 155 | * if the algorithm just doesn't exist, then disable the recovery | ||
| 156 | * tracker altogether. The crypto libs will generally return this if | ||
| 157 | * FIPS is enabled as well. | ||
| 158 | */ | ||
| 159 | if (error == -ENOENT) { | ||
| 160 | printk(KERN_ERR "NFSD: disabling legacy clientid tracking. " | ||
| 161 | "Reboot recovery will not function correctly!\n"); | ||
| 162 | |||
| 163 | /* the argument is ignored by the legacy exit function */ | ||
| 164 | nfsd4_client_tracking_exit(NULL); | ||
| 165 | } | ||
| 166 | } | ||
| 167 | |||
| 139 | static void | 168 | static void |
| 140 | nfsd4_create_clid_dir(struct nfs4_client *clp) | 169 | nfsd4_create_clid_dir(struct nfs4_client *clp) |
| 141 | { | 170 | { |
| 142 | const struct cred *original_cred; | 171 | const struct cred *original_cred; |
| 143 | char *dname = clp->cl_recdir; | 172 | char dname[HEXDIR_LEN]; |
| 144 | struct dentry *dir, *dentry; | 173 | struct dentry *dir, *dentry; |
| 174 | struct nfs4_client_reclaim *crp; | ||
| 145 | int status; | 175 | int status; |
| 176 | struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); | ||
| 146 | 177 | ||
| 147 | dprintk("NFSD: nfsd4_create_clid_dir for \"%s\"\n", dname); | 178 | dprintk("NFSD: nfsd4_create_clid_dir for \"%s\"\n", dname); |
| 148 | 179 | ||
| 149 | if (test_and_set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) | 180 | if (test_and_set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) |
| 150 | return; | 181 | return; |
| 151 | if (!rec_file) | 182 | if (!nn->rec_file) |
| 152 | return; | 183 | return; |
| 184 | |||
| 185 | status = nfs4_make_rec_clidname(dname, &clp->cl_name); | ||
| 186 | if (status) | ||
| 187 | return legacy_recdir_name_error(status); | ||
| 188 | |||
| 153 | status = nfs4_save_creds(&original_cred); | 189 | status = nfs4_save_creds(&original_cred); |
| 154 | if (status < 0) | 190 | if (status < 0) |
| 155 | return; | 191 | return; |
| 156 | 192 | ||
| 157 | status = mnt_want_write_file(rec_file); | 193 | status = mnt_want_write_file(nn->rec_file); |
| 158 | if (status) | 194 | if (status) |
| 159 | return; | 195 | return; |
| 160 | 196 | ||
| 161 | dir = rec_file->f_path.dentry; | 197 | dir = nn->rec_file->f_path.dentry; |
| 162 | /* lock the parent */ | 198 | /* lock the parent */ |
| 163 | mutex_lock(&dir->d_inode->i_mutex); | 199 | mutex_lock(&dir->d_inode->i_mutex); |
| 164 | 200 | ||
| @@ -182,18 +218,24 @@ out_put: | |||
| 182 | dput(dentry); | 218 | dput(dentry); |
| 183 | out_unlock: | 219 | out_unlock: |
| 184 | mutex_unlock(&dir->d_inode->i_mutex); | 220 | mutex_unlock(&dir->d_inode->i_mutex); |
| 185 | if (status == 0) | 221 | if (status == 0) { |
| 186 | vfs_fsync(rec_file, 0); | 222 | if (nn->in_grace) { |
| 187 | else | 223 | crp = nfs4_client_to_reclaim(dname, nn); |
| 224 | if (crp) | ||
| 225 | crp->cr_clp = clp; | ||
| 226 | } | ||
| 227 | vfs_fsync(nn->rec_file, 0); | ||
| 228 | } else { | ||
| 188 | printk(KERN_ERR "NFSD: failed to write recovery record" | 229 | printk(KERN_ERR "NFSD: failed to write recovery record" |
| 189 | " (err %d); please check that %s exists" | 230 | " (err %d); please check that %s exists" |
| 190 | " and is writeable", status, | 231 | " and is writeable", status, |
| 191 | user_recovery_dirname); | 232 | user_recovery_dirname); |
| 192 | mnt_drop_write_file(rec_file); | 233 | } |
| 234 | mnt_drop_write_file(nn->rec_file); | ||
| 193 | nfs4_reset_creds(original_cred); | 235 | nfs4_reset_creds(original_cred); |
| 194 | } | 236 | } |
| 195 | 237 | ||
| 196 | typedef int (recdir_func)(struct dentry *, struct dentry *); | 238 | typedef int (recdir_func)(struct dentry *, struct dentry *, struct nfsd_net *); |
| 197 | 239 | ||
| 198 | struct name_list { | 240 | struct name_list { |
| 199 | char name[HEXDIR_LEN]; | 241 | char name[HEXDIR_LEN]; |
| @@ -219,10 +261,10 @@ nfsd4_build_namelist(void *arg, const char *name, int namlen, | |||
| 219 | } | 261 | } |
| 220 | 262 | ||
| 221 | static int | 263 | static int |
| 222 | nfsd4_list_rec_dir(recdir_func *f) | 264 | nfsd4_list_rec_dir(recdir_func *f, struct nfsd_net *nn) |
| 223 | { | 265 | { |
| 224 | const struct cred *original_cred; | 266 | const struct cred *original_cred; |
| 225 | struct dentry *dir = rec_file->f_path.dentry; | 267 | struct dentry *dir = nn->rec_file->f_path.dentry; |
| 226 | LIST_HEAD(names); | 268 | LIST_HEAD(names); |
| 227 | int status; | 269 | int status; |
| 228 | 270 | ||
| @@ -230,13 +272,13 @@ nfsd4_list_rec_dir(recdir_func *f) | |||
| 230 | if (status < 0) | 272 | if (status < 0) |
| 231 | return status; | 273 | return status; |
| 232 | 274 | ||
| 233 | status = vfs_llseek(rec_file, 0, SEEK_SET); | 275 | status = vfs_llseek(nn->rec_file, 0, SEEK_SET); |
| 234 | if (status < 0) { | 276 | if (status < 0) { |
| 235 | nfs4_reset_creds(original_cred); | 277 | nfs4_reset_creds(original_cred); |
| 236 | return status; | 278 | return status; |
| 237 | } | 279 | } |
| 238 | 280 | ||
| 239 | status = vfs_readdir(rec_file, nfsd4_build_namelist, &names); | 281 | status = vfs_readdir(nn->rec_file, nfsd4_build_namelist, &names); |
| 240 | mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT); | 282 | mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT); |
| 241 | while (!list_empty(&names)) { | 283 | while (!list_empty(&names)) { |
| 242 | struct name_list *entry; | 284 | struct name_list *entry; |
| @@ -248,7 +290,7 @@ nfsd4_list_rec_dir(recdir_func *f) | |||
| 248 | status = PTR_ERR(dentry); | 290 | status = PTR_ERR(dentry); |
| 249 | break; | 291 | break; |
| 250 | } | 292 | } |
| 251 | status = f(dir, dentry); | 293 | status = f(dir, dentry, nn); |
| 252 | dput(dentry); | 294 | dput(dentry); |
| 253 | } | 295 | } |
| 254 | list_del(&entry->list); | 296 | list_del(&entry->list); |
| @@ -260,14 +302,14 @@ nfsd4_list_rec_dir(recdir_func *f) | |||
| 260 | } | 302 | } |
| 261 | 303 | ||
| 262 | static int | 304 | static int |
| 263 | nfsd4_unlink_clid_dir(char *name, int namlen) | 305 | nfsd4_unlink_clid_dir(char *name, int namlen, struct nfsd_net *nn) |
| 264 | { | 306 | { |
| 265 | struct dentry *dir, *dentry; | 307 | struct dentry *dir, *dentry; |
| 266 | int status; | 308 | int status; |
| 267 | 309 | ||
| 268 | dprintk("NFSD: nfsd4_unlink_clid_dir. name %.*s\n", namlen, name); | 310 | dprintk("NFSD: nfsd4_unlink_clid_dir. name %.*s\n", namlen, name); |
| 269 | 311 | ||
| 270 | dir = rec_file->f_path.dentry; | 312 | dir = nn->rec_file->f_path.dentry; |
| 271 | mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT); | 313 | mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT); |
| 272 | dentry = lookup_one_len(name, dir, namlen); | 314 | dentry = lookup_one_len(name, dir, namlen); |
| 273 | if (IS_ERR(dentry)) { | 315 | if (IS_ERR(dentry)) { |
| @@ -289,37 +331,52 @@ static void | |||
| 289 | nfsd4_remove_clid_dir(struct nfs4_client *clp) | 331 | nfsd4_remove_clid_dir(struct nfs4_client *clp) |
| 290 | { | 332 | { |
| 291 | const struct cred *original_cred; | 333 | const struct cred *original_cred; |
| 334 | struct nfs4_client_reclaim *crp; | ||
| 335 | char dname[HEXDIR_LEN]; | ||
| 292 | int status; | 336 | int status; |
| 337 | struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); | ||
| 293 | 338 | ||
| 294 | if (!rec_file || !test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) | 339 | if (!nn->rec_file || !test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) |
| 295 | return; | 340 | return; |
| 296 | 341 | ||
| 297 | status = mnt_want_write_file(rec_file); | 342 | status = nfs4_make_rec_clidname(dname, &clp->cl_name); |
| 343 | if (status) | ||
| 344 | return legacy_recdir_name_error(status); | ||
| 345 | |||
| 346 | status = mnt_want_write_file(nn->rec_file); | ||
| 298 | if (status) | 347 | if (status) |
| 299 | goto out; | 348 | goto out; |
| 300 | clear_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags); | 349 | clear_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags); |
| 301 | 350 | ||
| 302 | status = nfs4_save_creds(&original_cred); | 351 | status = nfs4_save_creds(&original_cred); |
| 303 | if (status < 0) | 352 | if (status < 0) |
| 304 | goto out; | 353 | goto out_drop_write; |
| 305 | 354 | ||
| 306 | status = nfsd4_unlink_clid_dir(clp->cl_recdir, HEXDIR_LEN-1); | 355 | status = nfsd4_unlink_clid_dir(dname, HEXDIR_LEN-1, nn); |
| 307 | nfs4_reset_creds(original_cred); | 356 | nfs4_reset_creds(original_cred); |
| 308 | if (status == 0) | 357 | if (status == 0) { |
| 309 | vfs_fsync(rec_file, 0); | 358 | vfs_fsync(nn->rec_file, 0); |
| 310 | mnt_drop_write_file(rec_file); | 359 | if (nn->in_grace) { |
| 360 | /* remove reclaim record */ | ||
| 361 | crp = nfsd4_find_reclaim_client(dname, nn); | ||
| 362 | if (crp) | ||
| 363 | nfs4_remove_reclaim_record(crp, nn); | ||
| 364 | } | ||
| 365 | } | ||
| 366 | out_drop_write: | ||
| 367 | mnt_drop_write_file(nn->rec_file); | ||
| 311 | out: | 368 | out: |
| 312 | if (status) | 369 | if (status) |
| 313 | printk("NFSD: Failed to remove expired client state directory" | 370 | printk("NFSD: Failed to remove expired client state directory" |
| 314 | " %.*s\n", HEXDIR_LEN, clp->cl_recdir); | 371 | " %.*s\n", HEXDIR_LEN, dname); |
| 315 | } | 372 | } |
| 316 | 373 | ||
| 317 | static int | 374 | static int |
| 318 | purge_old(struct dentry *parent, struct dentry *child) | 375 | purge_old(struct dentry *parent, struct dentry *child, struct nfsd_net *nn) |
| 319 | { | 376 | { |
| 320 | int status; | 377 | int status; |
| 321 | 378 | ||
| 322 | if (nfs4_has_reclaimed_state(child->d_name.name, false)) | 379 | if (nfs4_has_reclaimed_state(child->d_name.name, nn)) |
| 323 | return 0; | 380 | return 0; |
| 324 | 381 | ||
| 325 | status = vfs_rmdir(parent->d_inode, child); | 382 | status = vfs_rmdir(parent->d_inode, child); |
| @@ -331,27 +388,29 @@ purge_old(struct dentry *parent, struct dentry *child) | |||
| 331 | } | 388 | } |
| 332 | 389 | ||
| 333 | static void | 390 | static void |
| 334 | nfsd4_recdir_purge_old(struct net *net, time_t boot_time) | 391 | nfsd4_recdir_purge_old(struct nfsd_net *nn, time_t boot_time) |
| 335 | { | 392 | { |
| 336 | int status; | 393 | int status; |
| 337 | 394 | ||
| 338 | if (!rec_file) | 395 | nn->in_grace = false; |
| 396 | if (!nn->rec_file) | ||
| 339 | return; | 397 | return; |
| 340 | status = mnt_want_write_file(rec_file); | 398 | status = mnt_want_write_file(nn->rec_file); |
| 341 | if (status) | 399 | if (status) |
| 342 | goto out; | 400 | goto out; |
| 343 | status = nfsd4_list_rec_dir(purge_old); | 401 | status = nfsd4_list_rec_dir(purge_old, nn); |
| 344 | if (status == 0) | 402 | if (status == 0) |
| 345 | vfs_fsync(rec_file, 0); | 403 | vfs_fsync(nn->rec_file, 0); |
| 346 | mnt_drop_write_file(rec_file); | 404 | mnt_drop_write_file(nn->rec_file); |
| 347 | out: | 405 | out: |
| 406 | nfs4_release_reclaim(nn); | ||
| 348 | if (status) | 407 | if (status) |
| 349 | printk("nfsd4: failed to purge old clients from recovery" | 408 | printk("nfsd4: failed to purge old clients from recovery" |
| 350 | " directory %s\n", rec_file->f_path.dentry->d_name.name); | 409 | " directory %s\n", nn->rec_file->f_path.dentry->d_name.name); |
| 351 | } | 410 | } |
| 352 | 411 | ||
| 353 | static int | 412 | static int |
| 354 | load_recdir(struct dentry *parent, struct dentry *child) | 413 | load_recdir(struct dentry *parent, struct dentry *child, struct nfsd_net *nn) |
| 355 | { | 414 | { |
| 356 | if (child->d_name.len != HEXDIR_LEN - 1) { | 415 | if (child->d_name.len != HEXDIR_LEN - 1) { |
| 357 | printk("nfsd4: illegal name %s in recovery directory\n", | 416 | printk("nfsd4: illegal name %s in recovery directory\n", |
| @@ -359,21 +418,22 @@ load_recdir(struct dentry *parent, struct dentry *child) | |||
| 359 | /* Keep trying; maybe the others are OK: */ | 418 | /* Keep trying; maybe the others are OK: */ |
| 360 | return 0; | 419 | return 0; |
| 361 | } | 420 | } |
| 362 | nfs4_client_to_reclaim(child->d_name.name); | 421 | nfs4_client_to_reclaim(child->d_name.name, nn); |
| 363 | return 0; | 422 | return 0; |
| 364 | } | 423 | } |
| 365 | 424 | ||
| 366 | static int | 425 | static int |
| 367 | nfsd4_recdir_load(void) { | 426 | nfsd4_recdir_load(struct net *net) { |
| 368 | int status; | 427 | int status; |
| 428 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
| 369 | 429 | ||
| 370 | if (!rec_file) | 430 | if (!nn->rec_file) |
| 371 | return 0; | 431 | return 0; |
| 372 | 432 | ||
| 373 | status = nfsd4_list_rec_dir(load_recdir); | 433 | status = nfsd4_list_rec_dir(load_recdir, nn); |
| 374 | if (status) | 434 | if (status) |
| 375 | printk("nfsd4: failed loading clients from recovery" | 435 | printk("nfsd4: failed loading clients from recovery" |
| 376 | " directory %s\n", rec_file->f_path.dentry->d_name.name); | 436 | " directory %s\n", nn->rec_file->f_path.dentry->d_name.name); |
| 377 | return status; | 437 | return status; |
| 378 | } | 438 | } |
| 379 | 439 | ||
| @@ -382,15 +442,16 @@ nfsd4_recdir_load(void) { | |||
| 382 | */ | 442 | */ |
| 383 | 443 | ||
| 384 | static int | 444 | static int |
| 385 | nfsd4_init_recdir(void) | 445 | nfsd4_init_recdir(struct net *net) |
| 386 | { | 446 | { |
| 447 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
| 387 | const struct cred *original_cred; | 448 | const struct cred *original_cred; |
| 388 | int status; | 449 | int status; |
| 389 | 450 | ||
| 390 | printk("NFSD: Using %s as the NFSv4 state recovery directory\n", | 451 | printk("NFSD: Using %s as the NFSv4 state recovery directory\n", |
| 391 | user_recovery_dirname); | 452 | user_recovery_dirname); |
| 392 | 453 | ||
| 393 | BUG_ON(rec_file); | 454 | BUG_ON(nn->rec_file); |
| 394 | 455 | ||
| 395 | status = nfs4_save_creds(&original_cred); | 456 | status = nfs4_save_creds(&original_cred); |
| 396 | if (status < 0) { | 457 | if (status < 0) { |
| @@ -400,23 +461,65 @@ nfsd4_init_recdir(void) | |||
| 400 | return status; | 461 | return status; |
| 401 | } | 462 | } |
| 402 | 463 | ||
| 403 | rec_file = filp_open(user_recovery_dirname, O_RDONLY | O_DIRECTORY, 0); | 464 | nn->rec_file = filp_open(user_recovery_dirname, O_RDONLY | O_DIRECTORY, 0); |
| 404 | if (IS_ERR(rec_file)) { | 465 | if (IS_ERR(nn->rec_file)) { |
| 405 | printk("NFSD: unable to find recovery directory %s\n", | 466 | printk("NFSD: unable to find recovery directory %s\n", |
| 406 | user_recovery_dirname); | 467 | user_recovery_dirname); |
| 407 | status = PTR_ERR(rec_file); | 468 | status = PTR_ERR(nn->rec_file); |
| 408 | rec_file = NULL; | 469 | nn->rec_file = NULL; |
| 409 | } | 470 | } |
| 410 | 471 | ||
| 411 | nfs4_reset_creds(original_cred); | 472 | nfs4_reset_creds(original_cred); |
| 473 | if (!status) | ||
| 474 | nn->in_grace = true; | ||
| 412 | return status; | 475 | return status; |
| 413 | } | 476 | } |
| 414 | 477 | ||
| 478 | |||
| 479 | static int | ||
| 480 | nfs4_legacy_state_init(struct net *net) | ||
| 481 | { | ||
| 482 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
| 483 | int i; | ||
| 484 | |||
| 485 | nn->reclaim_str_hashtbl = kmalloc(sizeof(struct list_head) * | ||
| 486 | CLIENT_HASH_SIZE, GFP_KERNEL); | ||
| 487 | if (!nn->reclaim_str_hashtbl) | ||
| 488 | return -ENOMEM; | ||
| 489 | |||
| 490 | for (i = 0; i < CLIENT_HASH_SIZE; i++) | ||
| 491 | INIT_LIST_HEAD(&nn->reclaim_str_hashtbl[i]); | ||
| 492 | nn->reclaim_str_hashtbl_size = 0; | ||
| 493 | |||
| 494 | return 0; | ||
| 495 | } | ||
| 496 | |||
| 497 | static void | ||
| 498 | nfs4_legacy_state_shutdown(struct net *net) | ||
| 499 | { | ||
| 500 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
| 501 | |||
| 502 | kfree(nn->reclaim_str_hashtbl); | ||
| 503 | } | ||
| 504 | |||
| 415 | static int | 505 | static int |
| 416 | nfsd4_load_reboot_recovery_data(struct net *net) | 506 | nfsd4_load_reboot_recovery_data(struct net *net) |
| 417 | { | 507 | { |
| 418 | int status; | 508 | int status; |
| 419 | 509 | ||
| 510 | status = nfsd4_init_recdir(net); | ||
| 511 | if (!status) | ||
| 512 | status = nfsd4_recdir_load(net); | ||
| 513 | if (status) | ||
| 514 | printk(KERN_ERR "NFSD: Failure reading reboot recovery data\n"); | ||
| 515 | return status; | ||
| 516 | } | ||
| 517 | |||
| 518 | static int | ||
| 519 | nfsd4_legacy_tracking_init(struct net *net) | ||
| 520 | { | ||
| 521 | int status; | ||
| 522 | |||
| 420 | /* XXX: The legacy code won't work in a container */ | 523 | /* XXX: The legacy code won't work in a container */ |
| 421 | if (net != &init_net) { | 524 | if (net != &init_net) { |
| 422 | WARN(1, KERN_ERR "NFSD: attempt to initialize legacy client " | 525 | WARN(1, KERN_ERR "NFSD: attempt to initialize legacy client " |
| @@ -424,30 +527,37 @@ nfsd4_load_reboot_recovery_data(struct net *net) | |||
| 424 | return -EINVAL; | 527 | return -EINVAL; |
| 425 | } | 528 | } |
| 426 | 529 | ||
| 427 | nfs4_lock_state(); | 530 | status = nfs4_legacy_state_init(net); |
| 428 | status = nfsd4_init_recdir(); | ||
| 429 | if (!status) | ||
| 430 | status = nfsd4_recdir_load(); | ||
| 431 | nfs4_unlock_state(); | ||
| 432 | if (status) | 531 | if (status) |
| 433 | printk(KERN_ERR "NFSD: Failure reading reboot recovery data\n"); | 532 | return status; |
| 533 | |||
| 534 | status = nfsd4_load_reboot_recovery_data(net); | ||
| 535 | if (status) | ||
| 536 | goto err; | ||
| 537 | return 0; | ||
| 538 | |||
| 539 | err: | ||
| 540 | nfs4_legacy_state_shutdown(net); | ||
| 434 | return status; | 541 | return status; |
| 435 | } | 542 | } |
| 436 | 543 | ||
| 437 | static void | 544 | static void |
| 438 | nfsd4_shutdown_recdir(void) | 545 | nfsd4_shutdown_recdir(struct nfsd_net *nn) |
| 439 | { | 546 | { |
| 440 | if (!rec_file) | 547 | if (!nn->rec_file) |
| 441 | return; | 548 | return; |
| 442 | fput(rec_file); | 549 | fput(nn->rec_file); |
| 443 | rec_file = NULL; | 550 | nn->rec_file = NULL; |
| 444 | } | 551 | } |
| 445 | 552 | ||
| 446 | static void | 553 | static void |
| 447 | nfsd4_legacy_tracking_exit(struct net *net) | 554 | nfsd4_legacy_tracking_exit(struct net *net) |
| 448 | { | 555 | { |
| 449 | nfs4_release_reclaim(); | 556 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); |
| 450 | nfsd4_shutdown_recdir(); | 557 | |
| 558 | nfs4_release_reclaim(nn); | ||
| 559 | nfsd4_shutdown_recdir(nn); | ||
| 560 | nfs4_legacy_state_shutdown(net); | ||
| 451 | } | 561 | } |
| 452 | 562 | ||
| 453 | /* | 563 | /* |
| @@ -480,13 +590,26 @@ nfs4_recoverydir(void) | |||
| 480 | static int | 590 | static int |
| 481 | nfsd4_check_legacy_client(struct nfs4_client *clp) | 591 | nfsd4_check_legacy_client(struct nfs4_client *clp) |
| 482 | { | 592 | { |
| 593 | int status; | ||
| 594 | char dname[HEXDIR_LEN]; | ||
| 595 | struct nfs4_client_reclaim *crp; | ||
| 596 | struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); | ||
| 597 | |||
| 483 | /* did we already find that this client is stable? */ | 598 | /* did we already find that this client is stable? */ |
| 484 | if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) | 599 | if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) |
| 485 | return 0; | 600 | return 0; |
| 486 | 601 | ||
| 602 | status = nfs4_make_rec_clidname(dname, &clp->cl_name); | ||
| 603 | if (status) { | ||
| 604 | legacy_recdir_name_error(status); | ||
| 605 | return status; | ||
| 606 | } | ||
| 607 | |||
| 487 | /* look for it in the reclaim hashtable otherwise */ | 608 | /* look for it in the reclaim hashtable otherwise */ |
| 488 | if (nfsd4_find_reclaim_client(clp)) { | 609 | crp = nfsd4_find_reclaim_client(dname, nn); |
| 610 | if (crp) { | ||
| 489 | set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags); | 611 | set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags); |
| 612 | crp->cr_clp = clp; | ||
| 490 | return 0; | 613 | return 0; |
| 491 | } | 614 | } |
| 492 | 615 | ||
| @@ -494,7 +617,7 @@ nfsd4_check_legacy_client(struct nfs4_client *clp) | |||
| 494 | } | 617 | } |
| 495 | 618 | ||
| 496 | static struct nfsd4_client_tracking_ops nfsd4_legacy_tracking_ops = { | 619 | static struct nfsd4_client_tracking_ops nfsd4_legacy_tracking_ops = { |
| 497 | .init = nfsd4_load_reboot_recovery_data, | 620 | .init = nfsd4_legacy_tracking_init, |
| 498 | .exit = nfsd4_legacy_tracking_exit, | 621 | .exit = nfsd4_legacy_tracking_exit, |
| 499 | .create = nfsd4_create_clid_dir, | 622 | .create = nfsd4_create_clid_dir, |
| 500 | .remove = nfsd4_remove_clid_dir, | 623 | .remove = nfsd4_remove_clid_dir, |
| @@ -785,8 +908,7 @@ nfsd4_cld_create(struct nfs4_client *clp) | |||
| 785 | { | 908 | { |
| 786 | int ret; | 909 | int ret; |
| 787 | struct cld_upcall *cup; | 910 | struct cld_upcall *cup; |
| 788 | /* FIXME: determine net from clp */ | 911 | struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); |
| 789 | struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); | ||
| 790 | struct cld_net *cn = nn->cld_net; | 912 | struct cld_net *cn = nn->cld_net; |
| 791 | 913 | ||
| 792 | /* Don't upcall if it's already stored */ | 914 | /* Don't upcall if it's already stored */ |
| @@ -823,8 +945,7 @@ nfsd4_cld_remove(struct nfs4_client *clp) | |||
| 823 | { | 945 | { |
| 824 | int ret; | 946 | int ret; |
| 825 | struct cld_upcall *cup; | 947 | struct cld_upcall *cup; |
| 826 | /* FIXME: determine net from clp */ | 948 | struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); |
| 827 | struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); | ||
| 828 | struct cld_net *cn = nn->cld_net; | 949 | struct cld_net *cn = nn->cld_net; |
| 829 | 950 | ||
| 830 | /* Don't upcall if it's already removed */ | 951 | /* Don't upcall if it's already removed */ |
| @@ -861,8 +982,7 @@ nfsd4_cld_check(struct nfs4_client *clp) | |||
| 861 | { | 982 | { |
| 862 | int ret; | 983 | int ret; |
| 863 | struct cld_upcall *cup; | 984 | struct cld_upcall *cup; |
| 864 | /* FIXME: determine net from clp */ | 985 | struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); |
| 865 | struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); | ||
| 866 | struct cld_net *cn = nn->cld_net; | 986 | struct cld_net *cn = nn->cld_net; |
| 867 | 987 | ||
| 868 | /* Don't upcall if one was already stored during this grace pd */ | 988 | /* Don't upcall if one was already stored during this grace pd */ |
| @@ -892,11 +1012,10 @@ nfsd4_cld_check(struct nfs4_client *clp) | |||
| 892 | } | 1012 | } |
| 893 | 1013 | ||
| 894 | static void | 1014 | static void |
| 895 | nfsd4_cld_grace_done(struct net *net, time_t boot_time) | 1015 | nfsd4_cld_grace_done(struct nfsd_net *nn, time_t boot_time) |
| 896 | { | 1016 | { |
| 897 | int ret; | 1017 | int ret; |
| 898 | struct cld_upcall *cup; | 1018 | struct cld_upcall *cup; |
| 899 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
| 900 | struct cld_net *cn = nn->cld_net; | 1019 | struct cld_net *cn = nn->cld_net; |
| 901 | 1020 | ||
| 902 | cup = alloc_cld_upcall(cn); | 1021 | cup = alloc_cld_upcall(cn); |
| @@ -926,28 +1045,261 @@ static struct nfsd4_client_tracking_ops nfsd4_cld_tracking_ops = { | |||
| 926 | .grace_done = nfsd4_cld_grace_done, | 1045 | .grace_done = nfsd4_cld_grace_done, |
| 927 | }; | 1046 | }; |
| 928 | 1047 | ||
| 1048 | /* upcall via usermodehelper */ | ||
| 1049 | static char cltrack_prog[PATH_MAX] = "/sbin/nfsdcltrack"; | ||
| 1050 | module_param_string(cltrack_prog, cltrack_prog, sizeof(cltrack_prog), | ||
| 1051 | S_IRUGO|S_IWUSR); | ||
| 1052 | MODULE_PARM_DESC(cltrack_prog, "Path to the nfsdcltrack upcall program"); | ||
| 1053 | |||
| 1054 | static bool cltrack_legacy_disable; | ||
| 1055 | module_param(cltrack_legacy_disable, bool, S_IRUGO|S_IWUSR); | ||
| 1056 | MODULE_PARM_DESC(cltrack_legacy_disable, | ||
| 1057 | "Disable legacy recoverydir conversion. Default: false"); | ||
| 1058 | |||
| 1059 | #define LEGACY_TOPDIR_ENV_PREFIX "NFSDCLTRACK_LEGACY_TOPDIR=" | ||
| 1060 | #define LEGACY_RECDIR_ENV_PREFIX "NFSDCLTRACK_LEGACY_RECDIR=" | ||
| 1061 | |||
| 1062 | static char * | ||
| 1063 | nfsd4_cltrack_legacy_topdir(void) | ||
| 1064 | { | ||
| 1065 | int copied; | ||
| 1066 | size_t len; | ||
| 1067 | char *result; | ||
| 1068 | |||
| 1069 | if (cltrack_legacy_disable) | ||
| 1070 | return NULL; | ||
| 1071 | |||
| 1072 | len = strlen(LEGACY_TOPDIR_ENV_PREFIX) + | ||
| 1073 | strlen(nfs4_recoverydir()) + 1; | ||
| 1074 | |||
| 1075 | result = kmalloc(len, GFP_KERNEL); | ||
| 1076 | if (!result) | ||
| 1077 | return result; | ||
| 1078 | |||
| 1079 | copied = snprintf(result, len, LEGACY_TOPDIR_ENV_PREFIX "%s", | ||
| 1080 | nfs4_recoverydir()); | ||
| 1081 | if (copied >= len) { | ||
| 1082 | /* just return nothing if output was truncated */ | ||
| 1083 | kfree(result); | ||
| 1084 | return NULL; | ||
| 1085 | } | ||
| 1086 | |||
| 1087 | return result; | ||
| 1088 | } | ||
| 1089 | |||
| 1090 | static char * | ||
| 1091 | nfsd4_cltrack_legacy_recdir(const struct xdr_netobj *name) | ||
| 1092 | { | ||
| 1093 | int copied; | ||
| 1094 | size_t len; | ||
| 1095 | char *result; | ||
| 1096 | |||
| 1097 | if (cltrack_legacy_disable) | ||
| 1098 | return NULL; | ||
| 1099 | |||
| 1100 | /* +1 is for '/' between "topdir" and "recdir" */ | ||
| 1101 | len = strlen(LEGACY_RECDIR_ENV_PREFIX) + | ||
| 1102 | strlen(nfs4_recoverydir()) + 1 + HEXDIR_LEN; | ||
| 1103 | |||
| 1104 | result = kmalloc(len, GFP_KERNEL); | ||
| 1105 | if (!result) | ||
| 1106 | return result; | ||
| 1107 | |||
| 1108 | copied = snprintf(result, len, LEGACY_RECDIR_ENV_PREFIX "%s/", | ||
| 1109 | nfs4_recoverydir()); | ||
| 1110 | if (copied > (len - HEXDIR_LEN)) { | ||
| 1111 | /* just return nothing if output will be truncated */ | ||
| 1112 | kfree(result); | ||
| 1113 | return NULL; | ||
| 1114 | } | ||
| 1115 | |||
| 1116 | copied = nfs4_make_rec_clidname(result + copied, name); | ||
| 1117 | if (copied) { | ||
| 1118 | kfree(result); | ||
| 1119 | return NULL; | ||
| 1120 | } | ||
| 1121 | |||
| 1122 | return result; | ||
| 1123 | } | ||
| 1124 | |||
| 1125 | static int | ||
| 1126 | nfsd4_umh_cltrack_upcall(char *cmd, char *arg, char *legacy) | ||
| 1127 | { | ||
| 1128 | char *envp[2]; | ||
| 1129 | char *argv[4]; | ||
| 1130 | int ret; | ||
| 1131 | |||
| 1132 | if (unlikely(!cltrack_prog[0])) { | ||
| 1133 | dprintk("%s: cltrack_prog is disabled\n", __func__); | ||
| 1134 | return -EACCES; | ||
| 1135 | } | ||
| 1136 | |||
| 1137 | dprintk("%s: cmd: %s\n", __func__, cmd); | ||
| 1138 | dprintk("%s: arg: %s\n", __func__, arg ? arg : "(null)"); | ||
| 1139 | dprintk("%s: legacy: %s\n", __func__, legacy ? legacy : "(null)"); | ||
| 1140 | |||
| 1141 | envp[0] = legacy; | ||
| 1142 | envp[1] = NULL; | ||
| 1143 | |||
| 1144 | argv[0] = (char *)cltrack_prog; | ||
| 1145 | argv[1] = cmd; | ||
| 1146 | argv[2] = arg; | ||
| 1147 | argv[3] = NULL; | ||
| 1148 | |||
| 1149 | ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC); | ||
| 1150 | /* | ||
| 1151 | * Disable the upcall mechanism if we're getting an ENOENT or EACCES | ||
| 1152 | * error. The admin can re-enable it on the fly by using sysfs | ||
| 1153 | * once the problem has been fixed. | ||
| 1154 | */ | ||
| 1155 | if (ret == -ENOENT || ret == -EACCES) { | ||
| 1156 | dprintk("NFSD: %s was not found or isn't executable (%d). " | ||
| 1157 | "Setting cltrack_prog to blank string!", | ||
| 1158 | cltrack_prog, ret); | ||
| 1159 | cltrack_prog[0] = '\0'; | ||
| 1160 | } | ||
| 1161 | dprintk("%s: %s return value: %d\n", __func__, cltrack_prog, ret); | ||
| 1162 | |||
| 1163 | return ret; | ||
| 1164 | } | ||
| 1165 | |||
| 1166 | static char * | ||
| 1167 | bin_to_hex_dup(const unsigned char *src, int srclen) | ||
| 1168 | { | ||
| 1169 | int i; | ||
| 1170 | char *buf, *hex; | ||
| 1171 | |||
| 1172 | /* +1 for terminating NULL */ | ||
| 1173 | buf = kmalloc((srclen * 2) + 1, GFP_KERNEL); | ||
| 1174 | if (!buf) | ||
| 1175 | return buf; | ||
| 1176 | |||
| 1177 | hex = buf; | ||
| 1178 | for (i = 0; i < srclen; i++) { | ||
| 1179 | sprintf(hex, "%2.2x", *src++); | ||
| 1180 | hex += 2; | ||
| 1181 | } | ||
| 1182 | return buf; | ||
| 1183 | } | ||
| 1184 | |||
| 1185 | static int | ||
| 1186 | nfsd4_umh_cltrack_init(struct net __attribute__((unused)) *net) | ||
| 1187 | { | ||
| 1188 | return nfsd4_umh_cltrack_upcall("init", NULL, NULL); | ||
| 1189 | } | ||
| 1190 | |||
| 1191 | static void | ||
| 1192 | nfsd4_umh_cltrack_create(struct nfs4_client *clp) | ||
| 1193 | { | ||
| 1194 | char *hexid; | ||
| 1195 | |||
| 1196 | hexid = bin_to_hex_dup(clp->cl_name.data, clp->cl_name.len); | ||
| 1197 | if (!hexid) { | ||
| 1198 | dprintk("%s: can't allocate memory for upcall!\n", __func__); | ||
| 1199 | return; | ||
| 1200 | } | ||
| 1201 | nfsd4_umh_cltrack_upcall("create", hexid, NULL); | ||
| 1202 | kfree(hexid); | ||
| 1203 | } | ||
| 1204 | |||
| 1205 | static void | ||
| 1206 | nfsd4_umh_cltrack_remove(struct nfs4_client *clp) | ||
| 1207 | { | ||
| 1208 | char *hexid; | ||
| 1209 | |||
| 1210 | hexid = bin_to_hex_dup(clp->cl_name.data, clp->cl_name.len); | ||
| 1211 | if (!hexid) { | ||
| 1212 | dprintk("%s: can't allocate memory for upcall!\n", __func__); | ||
| 1213 | return; | ||
| 1214 | } | ||
| 1215 | nfsd4_umh_cltrack_upcall("remove", hexid, NULL); | ||
| 1216 | kfree(hexid); | ||
| 1217 | } | ||
| 1218 | |||
| 1219 | static int | ||
| 1220 | nfsd4_umh_cltrack_check(struct nfs4_client *clp) | ||
| 1221 | { | ||
| 1222 | int ret; | ||
| 1223 | char *hexid, *legacy; | ||
| 1224 | |||
| 1225 | hexid = bin_to_hex_dup(clp->cl_name.data, clp->cl_name.len); | ||
| 1226 | if (!hexid) { | ||
| 1227 | dprintk("%s: can't allocate memory for upcall!\n", __func__); | ||
| 1228 | return -ENOMEM; | ||
| 1229 | } | ||
| 1230 | legacy = nfsd4_cltrack_legacy_recdir(&clp->cl_name); | ||
| 1231 | ret = nfsd4_umh_cltrack_upcall("check", hexid, legacy); | ||
| 1232 | kfree(legacy); | ||
| 1233 | kfree(hexid); | ||
| 1234 | return ret; | ||
| 1235 | } | ||
| 1236 | |||
| 1237 | static void | ||
| 1238 | nfsd4_umh_cltrack_grace_done(struct nfsd_net __attribute__((unused)) *nn, | ||
| 1239 | time_t boot_time) | ||
| 1240 | { | ||
| 1241 | char *legacy; | ||
| 1242 | char timestr[22]; /* FIXME: better way to determine max size? */ | ||
| 1243 | |||
| 1244 | sprintf(timestr, "%ld", boot_time); | ||
| 1245 | legacy = nfsd4_cltrack_legacy_topdir(); | ||
| 1246 | nfsd4_umh_cltrack_upcall("gracedone", timestr, legacy); | ||
| 1247 | kfree(legacy); | ||
| 1248 | } | ||
| 1249 | |||
| 1250 | static struct nfsd4_client_tracking_ops nfsd4_umh_tracking_ops = { | ||
| 1251 | .init = nfsd4_umh_cltrack_init, | ||
| 1252 | .exit = NULL, | ||
| 1253 | .create = nfsd4_umh_cltrack_create, | ||
| 1254 | .remove = nfsd4_umh_cltrack_remove, | ||
| 1255 | .check = nfsd4_umh_cltrack_check, | ||
| 1256 | .grace_done = nfsd4_umh_cltrack_grace_done, | ||
| 1257 | }; | ||
| 1258 | |||
| 929 | int | 1259 | int |
| 930 | nfsd4_client_tracking_init(struct net *net) | 1260 | nfsd4_client_tracking_init(struct net *net) |
| 931 | { | 1261 | { |
| 932 | int status; | 1262 | int status; |
| 933 | struct path path; | 1263 | struct path path; |
| 1264 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
| 934 | 1265 | ||
| 935 | if (!client_tracking_ops) { | 1266 | /* just run the init if it the method is already decided */ |
| 936 | client_tracking_ops = &nfsd4_cld_tracking_ops; | 1267 | if (nn->client_tracking_ops) |
| 937 | status = kern_path(nfs4_recoverydir(), LOOKUP_FOLLOW, &path); | 1268 | goto do_init; |
| 938 | if (!status) { | 1269 | |
| 939 | if (S_ISDIR(path.dentry->d_inode->i_mode)) | 1270 | /* |
| 940 | client_tracking_ops = | 1271 | * First, try a UMH upcall. It should succeed or fail quickly, so |
| 941 | &nfsd4_legacy_tracking_ops; | 1272 | * there's little harm in trying that first. |
| 942 | path_put(&path); | 1273 | */ |
| 943 | } | 1274 | nn->client_tracking_ops = &nfsd4_umh_tracking_ops; |
| 1275 | status = nn->client_tracking_ops->init(net); | ||
| 1276 | if (!status) | ||
| 1277 | return status; | ||
| 1278 | |||
| 1279 | /* | ||
| 1280 | * See if the recoverydir exists and is a directory. If it is, | ||
| 1281 | * then use the legacy ops. | ||
| 1282 | */ | ||
| 1283 | nn->client_tracking_ops = &nfsd4_legacy_tracking_ops; | ||
| 1284 | status = kern_path(nfs4_recoverydir(), LOOKUP_FOLLOW, &path); | ||
| 1285 | if (!status) { | ||
| 1286 | status = S_ISDIR(path.dentry->d_inode->i_mode); | ||
| 1287 | path_put(&path); | ||
| 1288 | if (status) | ||
| 1289 | goto do_init; | ||
| 944 | } | 1290 | } |
| 945 | 1291 | ||
| 946 | status = client_tracking_ops->init(net); | 1292 | /* Finally, try to use nfsdcld */ |
| 1293 | nn->client_tracking_ops = &nfsd4_cld_tracking_ops; | ||
| 1294 | printk(KERN_WARNING "NFSD: the nfsdcld client tracking upcall will be " | ||
| 1295 | "removed in 3.10. Please transition to using " | ||
| 1296 | "nfsdcltrack.\n"); | ||
| 1297 | do_init: | ||
| 1298 | status = nn->client_tracking_ops->init(net); | ||
| 947 | if (status) { | 1299 | if (status) { |
| 948 | printk(KERN_WARNING "NFSD: Unable to initialize client " | 1300 | printk(KERN_WARNING "NFSD: Unable to initialize client " |
| 949 | "recovery tracking! (%d)\n", status); | 1301 | "recovery tracking! (%d)\n", status); |
| 950 | client_tracking_ops = NULL; | 1302 | nn->client_tracking_ops = NULL; |
| 951 | } | 1303 | } |
| 952 | return status; | 1304 | return status; |
| 953 | } | 1305 | } |
| @@ -955,40 +1307,49 @@ nfsd4_client_tracking_init(struct net *net) | |||
| 955 | void | 1307 | void |
| 956 | nfsd4_client_tracking_exit(struct net *net) | 1308 | nfsd4_client_tracking_exit(struct net *net) |
| 957 | { | 1309 | { |
| 958 | if (client_tracking_ops) { | 1310 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); |
| 959 | client_tracking_ops->exit(net); | 1311 | |
| 960 | client_tracking_ops = NULL; | 1312 | if (nn->client_tracking_ops) { |
| 1313 | if (nn->client_tracking_ops->exit) | ||
| 1314 | nn->client_tracking_ops->exit(net); | ||
| 1315 | nn->client_tracking_ops = NULL; | ||
| 961 | } | 1316 | } |
| 962 | } | 1317 | } |
| 963 | 1318 | ||
| 964 | void | 1319 | void |
| 965 | nfsd4_client_record_create(struct nfs4_client *clp) | 1320 | nfsd4_client_record_create(struct nfs4_client *clp) |
| 966 | { | 1321 | { |
| 967 | if (client_tracking_ops) | 1322 | struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); |
| 968 | client_tracking_ops->create(clp); | 1323 | |
| 1324 | if (nn->client_tracking_ops) | ||
| 1325 | nn->client_tracking_ops->create(clp); | ||
| 969 | } | 1326 | } |
| 970 | 1327 | ||
| 971 | void | 1328 | void |
| 972 | nfsd4_client_record_remove(struct nfs4_client *clp) | 1329 | nfsd4_client_record_remove(struct nfs4_client *clp) |
| 973 | { | 1330 | { |
| 974 | if (client_tracking_ops) | 1331 | struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); |
| 975 | client_tracking_ops->remove(clp); | 1332 | |
| 1333 | if (nn->client_tracking_ops) | ||
| 1334 | nn->client_tracking_ops->remove(clp); | ||
| 976 | } | 1335 | } |
| 977 | 1336 | ||
| 978 | int | 1337 | int |
| 979 | nfsd4_client_record_check(struct nfs4_client *clp) | 1338 | nfsd4_client_record_check(struct nfs4_client *clp) |
| 980 | { | 1339 | { |
| 981 | if (client_tracking_ops) | 1340 | struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); |
| 982 | return client_tracking_ops->check(clp); | 1341 | |
| 1342 | if (nn->client_tracking_ops) | ||
| 1343 | return nn->client_tracking_ops->check(clp); | ||
| 983 | 1344 | ||
| 984 | return -EOPNOTSUPP; | 1345 | return -EOPNOTSUPP; |
| 985 | } | 1346 | } |
| 986 | 1347 | ||
| 987 | void | 1348 | void |
| 988 | nfsd4_record_grace_done(struct net *net, time_t boot_time) | 1349 | nfsd4_record_grace_done(struct nfsd_net *nn, time_t boot_time) |
| 989 | { | 1350 | { |
| 990 | if (client_tracking_ops) | 1351 | if (nn->client_tracking_ops) |
| 991 | client_tracking_ops->grace_done(net, boot_time); | 1352 | nn->client_tracking_ops->grace_done(nn, boot_time); |
| 992 | } | 1353 | } |
| 993 | 1354 | ||
| 994 | static int | 1355 | static int |
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index d0237f872cc4..ac8ed96c4199 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
| @@ -44,16 +44,11 @@ | |||
| 44 | #include "xdr4.h" | 44 | #include "xdr4.h" |
| 45 | #include "vfs.h" | 45 | #include "vfs.h" |
| 46 | #include "current_stateid.h" | 46 | #include "current_stateid.h" |
| 47 | #include "fault_inject.h" | ||
| 48 | 47 | ||
| 49 | #include "netns.h" | 48 | #include "netns.h" |
| 50 | 49 | ||
| 51 | #define NFSDDBG_FACILITY NFSDDBG_PROC | 50 | #define NFSDDBG_FACILITY NFSDDBG_PROC |
| 52 | 51 | ||
| 53 | /* Globals */ | ||
| 54 | time_t nfsd4_lease = 90; /* default lease time */ | ||
| 55 | time_t nfsd4_grace = 90; | ||
| 56 | |||
| 57 | #define all_ones {{~0,~0},~0} | 52 | #define all_ones {{~0,~0},~0} |
| 58 | static const stateid_t one_stateid = { | 53 | static const stateid_t one_stateid = { |
| 59 | .si_generation = ~0, | 54 | .si_generation = ~0, |
| @@ -176,8 +171,6 @@ static unsigned int ownerstr_hashval(u32 clientid, struct xdr_netobj *ownername) | |||
| 176 | return ret & OWNER_HASH_MASK; | 171 | return ret & OWNER_HASH_MASK; |
| 177 | } | 172 | } |
| 178 | 173 | ||
| 179 | static struct list_head ownerstr_hashtbl[OWNER_HASH_SIZE]; | ||
| 180 | |||
| 181 | /* hash table for nfs4_file */ | 174 | /* hash table for nfs4_file */ |
| 182 | #define FILE_HASH_BITS 8 | 175 | #define FILE_HASH_BITS 8 |
| 183 | #define FILE_HASH_SIZE (1 << FILE_HASH_BITS) | 176 | #define FILE_HASH_SIZE (1 << FILE_HASH_BITS) |
| @@ -192,7 +185,7 @@ static struct list_head file_hashtbl[FILE_HASH_SIZE]; | |||
| 192 | 185 | ||
| 193 | static void __nfs4_file_get_access(struct nfs4_file *fp, int oflag) | 186 | static void __nfs4_file_get_access(struct nfs4_file *fp, int oflag) |
| 194 | { | 187 | { |
| 195 | BUG_ON(!(fp->fi_fds[oflag] || fp->fi_fds[O_RDWR])); | 188 | WARN_ON_ONCE(!(fp->fi_fds[oflag] || fp->fi_fds[O_RDWR])); |
| 196 | atomic_inc(&fp->fi_access[oflag]); | 189 | atomic_inc(&fp->fi_access[oflag]); |
| 197 | } | 190 | } |
| 198 | 191 | ||
| @@ -251,7 +244,7 @@ static inline int get_new_stid(struct nfs4_stid *stid) | |||
| 251 | * preallocations that can exist at a time, but the state lock | 244 | * preallocations that can exist at a time, but the state lock |
| 252 | * prevents anyone from using ours before we get here: | 245 | * prevents anyone from using ours before we get here: |
| 253 | */ | 246 | */ |
| 254 | BUG_ON(error); | 247 | WARN_ON_ONCE(error); |
| 255 | /* | 248 | /* |
| 256 | * It shouldn't be a problem to reuse an opaque stateid value. | 249 | * It shouldn't be a problem to reuse an opaque stateid value. |
| 257 | * I don't think it is for 4.1. But with 4.0 I worry that, for | 250 | * I don't think it is for 4.1. But with 4.0 I worry that, for |
| @@ -340,7 +333,7 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct sv | |||
| 340 | fh_copy_shallow(&dp->dl_fh, ¤t_fh->fh_handle); | 333 | fh_copy_shallow(&dp->dl_fh, ¤t_fh->fh_handle); |
| 341 | dp->dl_time = 0; | 334 | dp->dl_time = 0; |
| 342 | atomic_set(&dp->dl_count, 1); | 335 | atomic_set(&dp->dl_count, 1); |
| 343 | INIT_WORK(&dp->dl_recall.cb_work, nfsd4_do_callback_rpc); | 336 | nfsd4_init_callback(&dp->dl_recall); |
| 344 | return dp; | 337 | return dp; |
| 345 | } | 338 | } |
| 346 | 339 | ||
| @@ -390,14 +383,6 @@ unhash_delegation(struct nfs4_delegation *dp) | |||
| 390 | * SETCLIENTID state | 383 | * SETCLIENTID state |
| 391 | */ | 384 | */ |
| 392 | 385 | ||
| 393 | /* client_lock protects the client lru list and session hash table */ | ||
| 394 | static DEFINE_SPINLOCK(client_lock); | ||
| 395 | |||
| 396 | /* Hash tables for nfs4_clientid state */ | ||
| 397 | #define CLIENT_HASH_BITS 4 | ||
| 398 | #define CLIENT_HASH_SIZE (1 << CLIENT_HASH_BITS) | ||
| 399 | #define CLIENT_HASH_MASK (CLIENT_HASH_SIZE - 1) | ||
| 400 | |||
| 401 | static unsigned int clientid_hashval(u32 id) | 386 | static unsigned int clientid_hashval(u32 id) |
| 402 | { | 387 | { |
| 403 | return id & CLIENT_HASH_MASK; | 388 | return id & CLIENT_HASH_MASK; |
| @@ -409,31 +394,6 @@ static unsigned int clientstr_hashval(const char *name) | |||
| 409 | } | 394 | } |
| 410 | 395 | ||
| 411 | /* | 396 | /* |
| 412 | * reclaim_str_hashtbl[] holds known client info from previous reset/reboot | ||
| 413 | * used in reboot/reset lease grace period processing | ||
| 414 | * | ||
| 415 | * conf_id_hashtbl[], and conf_str_hashtbl[] hold confirmed | ||
| 416 | * setclientid_confirmed info. | ||
| 417 | * | ||
| 418 | * unconf_str_hastbl[] and unconf_id_hashtbl[] hold unconfirmed | ||
| 419 | * setclientid info. | ||
| 420 | * | ||
| 421 | * client_lru holds client queue ordered by nfs4_client.cl_time | ||
| 422 | * for lease renewal. | ||
| 423 | * | ||
| 424 | * close_lru holds (open) stateowner queue ordered by nfs4_stateowner.so_time | ||
| 425 | * for last close replay. | ||
| 426 | */ | ||
| 427 | static struct list_head reclaim_str_hashtbl[CLIENT_HASH_SIZE]; | ||
| 428 | static int reclaim_str_hashtbl_size = 0; | ||
| 429 | static struct list_head conf_id_hashtbl[CLIENT_HASH_SIZE]; | ||
| 430 | static struct list_head conf_str_hashtbl[CLIENT_HASH_SIZE]; | ||
| 431 | static struct list_head unconf_str_hashtbl[CLIENT_HASH_SIZE]; | ||
| 432 | static struct list_head unconf_id_hashtbl[CLIENT_HASH_SIZE]; | ||
| 433 | static struct list_head client_lru; | ||
| 434 | static struct list_head close_lru; | ||
| 435 | |||
| 436 | /* | ||
| 437 | * We store the NONE, READ, WRITE, and BOTH bits separately in the | 397 | * We store the NONE, READ, WRITE, and BOTH bits separately in the |
| 438 | * st_{access,deny}_bmap field of the stateid, in order to track not | 398 | * st_{access,deny}_bmap field of the stateid, in order to track not |
| 439 | * only what share bits are currently in force, but also what | 399 | * only what share bits are currently in force, but also what |
| @@ -526,7 +486,8 @@ static int nfs4_access_to_omode(u32 access) | |||
| 526 | case NFS4_SHARE_ACCESS_BOTH: | 486 | case NFS4_SHARE_ACCESS_BOTH: |
| 527 | return O_RDWR; | 487 | return O_RDWR; |
| 528 | } | 488 | } |
| 529 | BUG(); | 489 | WARN_ON_ONCE(1); |
| 490 | return O_RDONLY; | ||
| 530 | } | 491 | } |
| 531 | 492 | ||
| 532 | /* release all access and file references for a given stateid */ | 493 | /* release all access and file references for a given stateid */ |
| @@ -652,9 +613,6 @@ static void release_openowner(struct nfs4_openowner *oo) | |||
| 652 | nfs4_free_openowner(oo); | 613 | nfs4_free_openowner(oo); |
| 653 | } | 614 | } |
| 654 | 615 | ||
| 655 | #define SESSION_HASH_SIZE 512 | ||
| 656 | static struct list_head sessionid_hashtbl[SESSION_HASH_SIZE]; | ||
| 657 | |||
| 658 | static inline int | 616 | static inline int |
| 659 | hash_sessionid(struct nfs4_sessionid *sessionid) | 617 | hash_sessionid(struct nfs4_sessionid *sessionid) |
| 660 | { | 618 | { |
| @@ -785,9 +743,12 @@ out_free: | |||
| 785 | return NULL; | 743 | return NULL; |
| 786 | } | 744 | } |
| 787 | 745 | ||
| 788 | static void init_forechannel_attrs(struct nfsd4_channel_attrs *new, struct nfsd4_channel_attrs *req, int numslots, int slotsize) | 746 | static void init_forechannel_attrs(struct nfsd4_channel_attrs *new, |
| 747 | struct nfsd4_channel_attrs *req, | ||
| 748 | int numslots, int slotsize, | ||
| 749 | struct nfsd_net *nn) | ||
| 789 | { | 750 | { |
| 790 | u32 maxrpc = nfsd_serv->sv_max_mesg; | 751 | u32 maxrpc = nn->nfsd_serv->sv_max_mesg; |
| 791 | 752 | ||
| 792 | new->maxreqs = numslots; | 753 | new->maxreqs = numslots; |
| 793 | new->maxresp_cached = min_t(u32, req->maxresp_cached, | 754 | new->maxresp_cached = min_t(u32, req->maxresp_cached, |
| @@ -906,21 +867,27 @@ static void __free_session(struct nfsd4_session *ses) | |||
| 906 | static void free_session(struct kref *kref) | 867 | static void free_session(struct kref *kref) |
| 907 | { | 868 | { |
| 908 | struct nfsd4_session *ses; | 869 | struct nfsd4_session *ses; |
| 870 | struct nfsd_net *nn; | ||
| 909 | 871 | ||
| 910 | lockdep_assert_held(&client_lock); | ||
| 911 | ses = container_of(kref, struct nfsd4_session, se_ref); | 872 | ses = container_of(kref, struct nfsd4_session, se_ref); |
| 873 | nn = net_generic(ses->se_client->net, nfsd_net_id); | ||
| 874 | |||
| 875 | lockdep_assert_held(&nn->client_lock); | ||
| 912 | nfsd4_del_conns(ses); | 876 | nfsd4_del_conns(ses); |
| 913 | __free_session(ses); | 877 | __free_session(ses); |
| 914 | } | 878 | } |
| 915 | 879 | ||
| 916 | void nfsd4_put_session(struct nfsd4_session *ses) | 880 | void nfsd4_put_session(struct nfsd4_session *ses) |
| 917 | { | 881 | { |
| 918 | spin_lock(&client_lock); | 882 | struct nfsd_net *nn = net_generic(ses->se_client->net, nfsd_net_id); |
| 883 | |||
| 884 | spin_lock(&nn->client_lock); | ||
| 919 | nfsd4_put_session_locked(ses); | 885 | nfsd4_put_session_locked(ses); |
| 920 | spin_unlock(&client_lock); | 886 | spin_unlock(&nn->client_lock); |
| 921 | } | 887 | } |
| 922 | 888 | ||
| 923 | static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fchan) | 889 | static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fchan, |
| 890 | struct nfsd_net *nn) | ||
| 924 | { | 891 | { |
| 925 | struct nfsd4_session *new; | 892 | struct nfsd4_session *new; |
| 926 | int numslots, slotsize; | 893 | int numslots, slotsize; |
| @@ -941,13 +908,14 @@ static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fchan) | |||
| 941 | nfsd4_put_drc_mem(slotsize, fchan->maxreqs); | 908 | nfsd4_put_drc_mem(slotsize, fchan->maxreqs); |
| 942 | return NULL; | 909 | return NULL; |
| 943 | } | 910 | } |
| 944 | init_forechannel_attrs(&new->se_fchannel, fchan, numslots, slotsize); | 911 | init_forechannel_attrs(&new->se_fchannel, fchan, numslots, slotsize, nn); |
| 945 | return new; | 912 | return new; |
| 946 | } | 913 | } |
| 947 | 914 | ||
| 948 | static struct nfsd4_session *init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, struct nfs4_client *clp, struct nfsd4_create_session *cses) | 915 | static void init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, struct nfs4_client *clp, struct nfsd4_create_session *cses) |
| 949 | { | 916 | { |
| 950 | int idx; | 917 | int idx; |
| 918 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | ||
| 951 | 919 | ||
| 952 | new->se_client = clp; | 920 | new->se_client = clp; |
| 953 | gen_sessionid(new); | 921 | gen_sessionid(new); |
| @@ -957,14 +925,15 @@ static struct nfsd4_session *init_session(struct svc_rqst *rqstp, struct nfsd4_s | |||
| 957 | new->se_cb_seq_nr = 1; | 925 | new->se_cb_seq_nr = 1; |
| 958 | new->se_flags = cses->flags; | 926 | new->se_flags = cses->flags; |
| 959 | new->se_cb_prog = cses->callback_prog; | 927 | new->se_cb_prog = cses->callback_prog; |
| 928 | new->se_cb_sec = cses->cb_sec; | ||
| 960 | kref_init(&new->se_ref); | 929 | kref_init(&new->se_ref); |
| 961 | idx = hash_sessionid(&new->se_sessionid); | 930 | idx = hash_sessionid(&new->se_sessionid); |
| 962 | spin_lock(&client_lock); | 931 | spin_lock(&nn->client_lock); |
| 963 | list_add(&new->se_hash, &sessionid_hashtbl[idx]); | 932 | list_add(&new->se_hash, &nn->sessionid_hashtbl[idx]); |
| 964 | spin_lock(&clp->cl_lock); | 933 | spin_lock(&clp->cl_lock); |
| 965 | list_add(&new->se_perclnt, &clp->cl_sessions); | 934 | list_add(&new->se_perclnt, &clp->cl_sessions); |
| 966 | spin_unlock(&clp->cl_lock); | 935 | spin_unlock(&clp->cl_lock); |
| 967 | spin_unlock(&client_lock); | 936 | spin_unlock(&nn->client_lock); |
| 968 | 937 | ||
| 969 | if (cses->flags & SESSION4_BACK_CHAN) { | 938 | if (cses->flags & SESSION4_BACK_CHAN) { |
| 970 | struct sockaddr *sa = svc_addr(rqstp); | 939 | struct sockaddr *sa = svc_addr(rqstp); |
| @@ -978,20 +947,20 @@ static struct nfsd4_session *init_session(struct svc_rqst *rqstp, struct nfsd4_s | |||
| 978 | rpc_copy_addr((struct sockaddr *)&clp->cl_cb_conn.cb_addr, sa); | 947 | rpc_copy_addr((struct sockaddr *)&clp->cl_cb_conn.cb_addr, sa); |
| 979 | clp->cl_cb_conn.cb_addrlen = svc_addr_len(sa); | 948 | clp->cl_cb_conn.cb_addrlen = svc_addr_len(sa); |
| 980 | } | 949 | } |
| 981 | return new; | ||
| 982 | } | 950 | } |
| 983 | 951 | ||
| 984 | /* caller must hold client_lock */ | 952 | /* caller must hold client_lock */ |
| 985 | static struct nfsd4_session * | 953 | static struct nfsd4_session * |
| 986 | find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid) | 954 | find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid, struct net *net) |
| 987 | { | 955 | { |
| 988 | struct nfsd4_session *elem; | 956 | struct nfsd4_session *elem; |
| 989 | int idx; | 957 | int idx; |
| 958 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
| 990 | 959 | ||
| 991 | dump_sessionid(__func__, sessionid); | 960 | dump_sessionid(__func__, sessionid); |
| 992 | idx = hash_sessionid(sessionid); | 961 | idx = hash_sessionid(sessionid); |
| 993 | /* Search in the appropriate list */ | 962 | /* Search in the appropriate list */ |
| 994 | list_for_each_entry(elem, &sessionid_hashtbl[idx], se_hash) { | 963 | list_for_each_entry(elem, &nn->sessionid_hashtbl[idx], se_hash) { |
| 995 | if (!memcmp(elem->se_sessionid.data, sessionid->data, | 964 | if (!memcmp(elem->se_sessionid.data, sessionid->data, |
| 996 | NFS4_MAX_SESSIONID_LEN)) { | 965 | NFS4_MAX_SESSIONID_LEN)) { |
| 997 | return elem; | 966 | return elem; |
| @@ -1016,6 +985,8 @@ unhash_session(struct nfsd4_session *ses) | |||
| 1016 | static inline void | 985 | static inline void |
| 1017 | renew_client_locked(struct nfs4_client *clp) | 986 | renew_client_locked(struct nfs4_client *clp) |
| 1018 | { | 987 | { |
| 988 | struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); | ||
| 989 | |||
| 1019 | if (is_client_expired(clp)) { | 990 | if (is_client_expired(clp)) { |
| 1020 | WARN_ON(1); | 991 | WARN_ON(1); |
| 1021 | printk("%s: client (clientid %08x/%08x) already expired\n", | 992 | printk("%s: client (clientid %08x/%08x) already expired\n", |
| @@ -1028,16 +999,18 @@ renew_client_locked(struct nfs4_client *clp) | |||
| 1028 | dprintk("renewing client (clientid %08x/%08x)\n", | 999 | dprintk("renewing client (clientid %08x/%08x)\n", |
| 1029 | clp->cl_clientid.cl_boot, | 1000 | clp->cl_clientid.cl_boot, |
| 1030 | clp->cl_clientid.cl_id); | 1001 | clp->cl_clientid.cl_id); |
| 1031 | list_move_tail(&clp->cl_lru, &client_lru); | 1002 | list_move_tail(&clp->cl_lru, &nn->client_lru); |
| 1032 | clp->cl_time = get_seconds(); | 1003 | clp->cl_time = get_seconds(); |
| 1033 | } | 1004 | } |
| 1034 | 1005 | ||
| 1035 | static inline void | 1006 | static inline void |
| 1036 | renew_client(struct nfs4_client *clp) | 1007 | renew_client(struct nfs4_client *clp) |
| 1037 | { | 1008 | { |
| 1038 | spin_lock(&client_lock); | 1009 | struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); |
| 1010 | |||
| 1011 | spin_lock(&nn->client_lock); | ||
| 1039 | renew_client_locked(clp); | 1012 | renew_client_locked(clp); |
| 1040 | spin_unlock(&client_lock); | 1013 | spin_unlock(&nn->client_lock); |
| 1041 | } | 1014 | } |
| 1042 | 1015 | ||
| 1043 | /* SETCLIENTID and SETCLIENTID_CONFIRM Helper functions */ | 1016 | /* SETCLIENTID and SETCLIENTID_CONFIRM Helper functions */ |
| @@ -1075,7 +1048,9 @@ static struct nfs4_client *alloc_client(struct xdr_netobj name) | |||
| 1075 | static inline void | 1048 | static inline void |
| 1076 | free_client(struct nfs4_client *clp) | 1049 | free_client(struct nfs4_client *clp) |
| 1077 | { | 1050 | { |
| 1078 | lockdep_assert_held(&client_lock); | 1051 | struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); |
| 1052 | |||
| 1053 | lockdep_assert_held(&nn->client_lock); | ||
| 1079 | while (!list_empty(&clp->cl_sessions)) { | 1054 | while (!list_empty(&clp->cl_sessions)) { |
| 1080 | struct nfsd4_session *ses; | 1055 | struct nfsd4_session *ses; |
| 1081 | ses = list_entry(clp->cl_sessions.next, struct nfsd4_session, | 1056 | ses = list_entry(clp->cl_sessions.next, struct nfsd4_session, |
| @@ -1092,15 +1067,16 @@ void | |||
| 1092 | release_session_client(struct nfsd4_session *session) | 1067 | release_session_client(struct nfsd4_session *session) |
| 1093 | { | 1068 | { |
| 1094 | struct nfs4_client *clp = session->se_client; | 1069 | struct nfs4_client *clp = session->se_client; |
| 1070 | struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); | ||
| 1095 | 1071 | ||
| 1096 | if (!atomic_dec_and_lock(&clp->cl_refcount, &client_lock)) | 1072 | if (!atomic_dec_and_lock(&clp->cl_refcount, &nn->client_lock)) |
| 1097 | return; | 1073 | return; |
| 1098 | if (is_client_expired(clp)) { | 1074 | if (is_client_expired(clp)) { |
| 1099 | free_client(clp); | 1075 | free_client(clp); |
| 1100 | session->se_client = NULL; | 1076 | session->se_client = NULL; |
| 1101 | } else | 1077 | } else |
| 1102 | renew_client_locked(clp); | 1078 | renew_client_locked(clp); |
| 1103 | spin_unlock(&client_lock); | 1079 | spin_unlock(&nn->client_lock); |
| 1104 | } | 1080 | } |
| 1105 | 1081 | ||
| 1106 | /* must be called under the client_lock */ | 1082 | /* must be called under the client_lock */ |
| @@ -1123,6 +1099,7 @@ destroy_client(struct nfs4_client *clp) | |||
| 1123 | struct nfs4_openowner *oo; | 1099 | struct nfs4_openowner *oo; |
| 1124 | struct nfs4_delegation *dp; | 1100 | struct nfs4_delegation *dp; |
| 1125 | struct list_head reaplist; | 1101 | struct list_head reaplist; |
| 1102 | struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); | ||
| 1126 | 1103 | ||
| 1127 | INIT_LIST_HEAD(&reaplist); | 1104 | INIT_LIST_HEAD(&reaplist); |
| 1128 | spin_lock(&recall_lock); | 1105 | spin_lock(&recall_lock); |
| @@ -1144,12 +1121,15 @@ destroy_client(struct nfs4_client *clp) | |||
| 1144 | if (clp->cl_cb_conn.cb_xprt) | 1121 | if (clp->cl_cb_conn.cb_xprt) |
| 1145 | svc_xprt_put(clp->cl_cb_conn.cb_xprt); | 1122 | svc_xprt_put(clp->cl_cb_conn.cb_xprt); |
| 1146 | list_del(&clp->cl_idhash); | 1123 | list_del(&clp->cl_idhash); |
| 1147 | list_del(&clp->cl_strhash); | 1124 | if (test_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags)) |
| 1148 | spin_lock(&client_lock); | 1125 | rb_erase(&clp->cl_namenode, &nn->conf_name_tree); |
| 1126 | else | ||
| 1127 | rb_erase(&clp->cl_namenode, &nn->unconf_name_tree); | ||
| 1128 | spin_lock(&nn->client_lock); | ||
| 1149 | unhash_client_locked(clp); | 1129 | unhash_client_locked(clp); |
| 1150 | if (atomic_read(&clp->cl_refcount) == 0) | 1130 | if (atomic_read(&clp->cl_refcount) == 0) |
| 1151 | free_client(clp); | 1131 | free_client(clp); |
| 1152 | spin_unlock(&client_lock); | 1132 | spin_unlock(&nn->client_lock); |
| 1153 | } | 1133 | } |
| 1154 | 1134 | ||
| 1155 | static void expire_client(struct nfs4_client *clp) | 1135 | static void expire_client(struct nfs4_client *clp) |
| @@ -1187,6 +1167,17 @@ static int copy_cred(struct svc_cred *target, struct svc_cred *source) | |||
| 1187 | return 0; | 1167 | return 0; |
| 1188 | } | 1168 | } |
| 1189 | 1169 | ||
| 1170 | static long long | ||
| 1171 | compare_blob(const struct xdr_netobj *o1, const struct xdr_netobj *o2) | ||
| 1172 | { | ||
| 1173 | long long res; | ||
| 1174 | |||
| 1175 | res = o1->len - o2->len; | ||
| 1176 | if (res) | ||
| 1177 | return res; | ||
| 1178 | return (long long)memcmp(o1->data, o2->data, o1->len); | ||
| 1179 | } | ||
| 1180 | |||
| 1190 | static int same_name(const char *n1, const char *n2) | 1181 | static int same_name(const char *n1, const char *n2) |
| 1191 | { | 1182 | { |
| 1192 | return 0 == memcmp(n1, n2, HEXDIR_LEN); | 1183 | return 0 == memcmp(n1, n2, HEXDIR_LEN); |
| @@ -1247,10 +1238,9 @@ same_creds(struct svc_cred *cr1, struct svc_cred *cr2) | |||
| 1247 | return 0 == strcmp(cr1->cr_principal, cr2->cr_principal); | 1238 | return 0 == strcmp(cr1->cr_principal, cr2->cr_principal); |
| 1248 | } | 1239 | } |
| 1249 | 1240 | ||
| 1250 | static void gen_clid(struct nfs4_client *clp) | 1241 | static void gen_clid(struct nfs4_client *clp, struct nfsd_net *nn) |
| 1251 | { | 1242 | { |
| 1252 | static u32 current_clientid = 1; | 1243 | static u32 current_clientid = 1; |
| 1253 | struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); | ||
| 1254 | 1244 | ||
| 1255 | clp->cl_clientid.cl_boot = nn->boot_time; | 1245 | clp->cl_clientid.cl_boot = nn->boot_time; |
| 1256 | clp->cl_clientid.cl_id = current_clientid++; | 1246 | clp->cl_clientid.cl_id = current_clientid++; |
| @@ -1283,12 +1273,14 @@ static struct nfs4_stid *find_stateid_by_type(struct nfs4_client *cl, stateid_t | |||
| 1283 | return NULL; | 1273 | return NULL; |
| 1284 | } | 1274 | } |
| 1285 | 1275 | ||
| 1286 | static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir, | 1276 | static struct nfs4_client *create_client(struct xdr_netobj name, |
| 1287 | struct svc_rqst *rqstp, nfs4_verifier *verf) | 1277 | struct svc_rqst *rqstp, nfs4_verifier *verf) |
| 1288 | { | 1278 | { |
| 1289 | struct nfs4_client *clp; | 1279 | struct nfs4_client *clp; |
| 1290 | struct sockaddr *sa = svc_addr(rqstp); | 1280 | struct sockaddr *sa = svc_addr(rqstp); |
| 1291 | int ret; | 1281 | int ret; |
| 1282 | struct net *net = SVC_NET(rqstp); | ||
| 1283 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
| 1292 | 1284 | ||
| 1293 | clp = alloc_client(name); | 1285 | clp = alloc_client(name); |
| 1294 | if (clp == NULL) | 1286 | if (clp == NULL) |
| @@ -1297,23 +1289,21 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir, | |||
| 1297 | INIT_LIST_HEAD(&clp->cl_sessions); | 1289 | INIT_LIST_HEAD(&clp->cl_sessions); |
| 1298 | ret = copy_cred(&clp->cl_cred, &rqstp->rq_cred); | 1290 | ret = copy_cred(&clp->cl_cred, &rqstp->rq_cred); |
| 1299 | if (ret) { | 1291 | if (ret) { |
| 1300 | spin_lock(&client_lock); | 1292 | spin_lock(&nn->client_lock); |
| 1301 | free_client(clp); | 1293 | free_client(clp); |
| 1302 | spin_unlock(&client_lock); | 1294 | spin_unlock(&nn->client_lock); |
| 1303 | return NULL; | 1295 | return NULL; |
| 1304 | } | 1296 | } |
| 1305 | idr_init(&clp->cl_stateids); | 1297 | idr_init(&clp->cl_stateids); |
| 1306 | memcpy(clp->cl_recdir, recdir, HEXDIR_LEN); | ||
| 1307 | atomic_set(&clp->cl_refcount, 0); | 1298 | atomic_set(&clp->cl_refcount, 0); |
| 1308 | clp->cl_cb_state = NFSD4_CB_UNKNOWN; | 1299 | clp->cl_cb_state = NFSD4_CB_UNKNOWN; |
| 1309 | INIT_LIST_HEAD(&clp->cl_idhash); | 1300 | INIT_LIST_HEAD(&clp->cl_idhash); |
| 1310 | INIT_LIST_HEAD(&clp->cl_strhash); | ||
| 1311 | INIT_LIST_HEAD(&clp->cl_openowners); | 1301 | INIT_LIST_HEAD(&clp->cl_openowners); |
| 1312 | INIT_LIST_HEAD(&clp->cl_delegations); | 1302 | INIT_LIST_HEAD(&clp->cl_delegations); |
| 1313 | INIT_LIST_HEAD(&clp->cl_lru); | 1303 | INIT_LIST_HEAD(&clp->cl_lru); |
| 1314 | INIT_LIST_HEAD(&clp->cl_callbacks); | 1304 | INIT_LIST_HEAD(&clp->cl_callbacks); |
| 1315 | spin_lock_init(&clp->cl_lock); | 1305 | spin_lock_init(&clp->cl_lock); |
| 1316 | INIT_WORK(&clp->cl_cb_null.cb_work, nfsd4_do_callback_rpc); | 1306 | nfsd4_init_callback(&clp->cl_cb_null); |
| 1317 | clp->cl_time = get_seconds(); | 1307 | clp->cl_time = get_seconds(); |
| 1318 | clear_bit(0, &clp->cl_cb_slot_busy); | 1308 | clear_bit(0, &clp->cl_cb_slot_busy); |
| 1319 | rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table"); | 1309 | rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table"); |
| @@ -1321,17 +1311,60 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir, | |||
| 1321 | rpc_copy_addr((struct sockaddr *) &clp->cl_addr, sa); | 1311 | rpc_copy_addr((struct sockaddr *) &clp->cl_addr, sa); |
| 1322 | gen_confirm(clp); | 1312 | gen_confirm(clp); |
| 1323 | clp->cl_cb_session = NULL; | 1313 | clp->cl_cb_session = NULL; |
| 1314 | clp->net = net; | ||
| 1324 | return clp; | 1315 | return clp; |
| 1325 | } | 1316 | } |
| 1326 | 1317 | ||
| 1327 | static void | 1318 | static void |
| 1328 | add_to_unconfirmed(struct nfs4_client *clp, unsigned int strhashval) | 1319 | add_clp_to_name_tree(struct nfs4_client *new_clp, struct rb_root *root) |
| 1320 | { | ||
| 1321 | struct rb_node **new = &(root->rb_node), *parent = NULL; | ||
| 1322 | struct nfs4_client *clp; | ||
| 1323 | |||
| 1324 | while (*new) { | ||
| 1325 | clp = rb_entry(*new, struct nfs4_client, cl_namenode); | ||
| 1326 | parent = *new; | ||
| 1327 | |||
| 1328 | if (compare_blob(&clp->cl_name, &new_clp->cl_name) > 0) | ||
| 1329 | new = &((*new)->rb_left); | ||
| 1330 | else | ||
| 1331 | new = &((*new)->rb_right); | ||
| 1332 | } | ||
| 1333 | |||
| 1334 | rb_link_node(&new_clp->cl_namenode, parent, new); | ||
| 1335 | rb_insert_color(&new_clp->cl_namenode, root); | ||
| 1336 | } | ||
| 1337 | |||
| 1338 | static struct nfs4_client * | ||
| 1339 | find_clp_in_name_tree(struct xdr_netobj *name, struct rb_root *root) | ||
| 1340 | { | ||
| 1341 | long long cmp; | ||
| 1342 | struct rb_node *node = root->rb_node; | ||
| 1343 | struct nfs4_client *clp; | ||
| 1344 | |||
| 1345 | while (node) { | ||
| 1346 | clp = rb_entry(node, struct nfs4_client, cl_namenode); | ||
| 1347 | cmp = compare_blob(&clp->cl_name, name); | ||
| 1348 | if (cmp > 0) | ||
| 1349 | node = node->rb_left; | ||
| 1350 | else if (cmp < 0) | ||
| 1351 | node = node->rb_right; | ||
| 1352 | else | ||
| 1353 | return clp; | ||
| 1354 | } | ||
| 1355 | return NULL; | ||
| 1356 | } | ||
| 1357 | |||
| 1358 | static void | ||
| 1359 | add_to_unconfirmed(struct nfs4_client *clp) | ||
| 1329 | { | 1360 | { |
| 1330 | unsigned int idhashval; | 1361 | unsigned int idhashval; |
| 1362 | struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); | ||
| 1331 | 1363 | ||
| 1332 | list_add(&clp->cl_strhash, &unconf_str_hashtbl[strhashval]); | 1364 | clear_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags); |
| 1365 | add_clp_to_name_tree(clp, &nn->unconf_name_tree); | ||
| 1333 | idhashval = clientid_hashval(clp->cl_clientid.cl_id); | 1366 | idhashval = clientid_hashval(clp->cl_clientid.cl_id); |
| 1334 | list_add(&clp->cl_idhash, &unconf_id_hashtbl[idhashval]); | 1367 | list_add(&clp->cl_idhash, &nn->unconf_id_hashtbl[idhashval]); |
| 1335 | renew_client(clp); | 1368 | renew_client(clp); |
| 1336 | } | 1369 | } |
| 1337 | 1370 | ||
| @@ -1339,22 +1372,23 @@ static void | |||
| 1339 | move_to_confirmed(struct nfs4_client *clp) | 1372 | move_to_confirmed(struct nfs4_client *clp) |
| 1340 | { | 1373 | { |
| 1341 | unsigned int idhashval = clientid_hashval(clp->cl_clientid.cl_id); | 1374 | unsigned int idhashval = clientid_hashval(clp->cl_clientid.cl_id); |
| 1342 | unsigned int strhashval; | 1375 | struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); |
| 1343 | 1376 | ||
| 1344 | dprintk("NFSD: move_to_confirm nfs4_client %p\n", clp); | 1377 | dprintk("NFSD: move_to_confirm nfs4_client %p\n", clp); |
| 1345 | list_move(&clp->cl_idhash, &conf_id_hashtbl[idhashval]); | 1378 | list_move(&clp->cl_idhash, &nn->conf_id_hashtbl[idhashval]); |
| 1346 | strhashval = clientstr_hashval(clp->cl_recdir); | 1379 | rb_erase(&clp->cl_namenode, &nn->unconf_name_tree); |
| 1347 | list_move(&clp->cl_strhash, &conf_str_hashtbl[strhashval]); | 1380 | add_clp_to_name_tree(clp, &nn->conf_name_tree); |
| 1381 | set_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags); | ||
| 1348 | renew_client(clp); | 1382 | renew_client(clp); |
| 1349 | } | 1383 | } |
| 1350 | 1384 | ||
| 1351 | static struct nfs4_client * | 1385 | static struct nfs4_client * |
| 1352 | find_confirmed_client(clientid_t *clid, bool sessions) | 1386 | find_confirmed_client(clientid_t *clid, bool sessions, struct nfsd_net *nn) |
| 1353 | { | 1387 | { |
| 1354 | struct nfs4_client *clp; | 1388 | struct nfs4_client *clp; |
| 1355 | unsigned int idhashval = clientid_hashval(clid->cl_id); | 1389 | unsigned int idhashval = clientid_hashval(clid->cl_id); |
| 1356 | 1390 | ||
| 1357 | list_for_each_entry(clp, &conf_id_hashtbl[idhashval], cl_idhash) { | 1391 | list_for_each_entry(clp, &nn->conf_id_hashtbl[idhashval], cl_idhash) { |
| 1358 | if (same_clid(&clp->cl_clientid, clid)) { | 1392 | if (same_clid(&clp->cl_clientid, clid)) { |
| 1359 | if ((bool)clp->cl_minorversion != sessions) | 1393 | if ((bool)clp->cl_minorversion != sessions) |
| 1360 | return NULL; | 1394 | return NULL; |
| @@ -1366,12 +1400,12 @@ find_confirmed_client(clientid_t *clid, bool sessions) | |||
| 1366 | } | 1400 | } |
| 1367 | 1401 | ||
| 1368 | static struct nfs4_client * | 1402 | static struct nfs4_client * |
| 1369 | find_unconfirmed_client(clientid_t *clid, bool sessions) | 1403 | find_unconfirmed_client(clientid_t *clid, bool sessions, struct nfsd_net *nn) |
| 1370 | { | 1404 | { |
| 1371 | struct nfs4_client *clp; | 1405 | struct nfs4_client *clp; |
| 1372 | unsigned int idhashval = clientid_hashval(clid->cl_id); | 1406 | unsigned int idhashval = clientid_hashval(clid->cl_id); |
| 1373 | 1407 | ||
| 1374 | list_for_each_entry(clp, &unconf_id_hashtbl[idhashval], cl_idhash) { | 1408 | list_for_each_entry(clp, &nn->unconf_id_hashtbl[idhashval], cl_idhash) { |
| 1375 | if (same_clid(&clp->cl_clientid, clid)) { | 1409 | if (same_clid(&clp->cl_clientid, clid)) { |
| 1376 | if ((bool)clp->cl_minorversion != sessions) | 1410 | if ((bool)clp->cl_minorversion != sessions) |
| 1377 | return NULL; | 1411 | return NULL; |
| @@ -1387,27 +1421,15 @@ static bool clp_used_exchangeid(struct nfs4_client *clp) | |||
| 1387 | } | 1421 | } |
| 1388 | 1422 | ||
| 1389 | static struct nfs4_client * | 1423 | static struct nfs4_client * |
| 1390 | find_confirmed_client_by_str(const char *dname, unsigned int hashval) | 1424 | find_confirmed_client_by_name(struct xdr_netobj *name, struct nfsd_net *nn) |
| 1391 | { | 1425 | { |
| 1392 | struct nfs4_client *clp; | 1426 | return find_clp_in_name_tree(name, &nn->conf_name_tree); |
| 1393 | |||
| 1394 | list_for_each_entry(clp, &conf_str_hashtbl[hashval], cl_strhash) { | ||
| 1395 | if (same_name(clp->cl_recdir, dname)) | ||
| 1396 | return clp; | ||
| 1397 | } | ||
| 1398 | return NULL; | ||
| 1399 | } | 1427 | } |
| 1400 | 1428 | ||
| 1401 | static struct nfs4_client * | 1429 | static struct nfs4_client * |
| 1402 | find_unconfirmed_client_by_str(const char *dname, unsigned int hashval) | 1430 | find_unconfirmed_client_by_name(struct xdr_netobj *name, struct nfsd_net *nn) |
| 1403 | { | 1431 | { |
| 1404 | struct nfs4_client *clp; | 1432 | return find_clp_in_name_tree(name, &nn->unconf_name_tree); |
| 1405 | |||
| 1406 | list_for_each_entry(clp, &unconf_str_hashtbl[hashval], cl_strhash) { | ||
| 1407 | if (same_name(clp->cl_recdir, dname)) | ||
| 1408 | return clp; | ||
| 1409 | } | ||
| 1410 | return NULL; | ||
| 1411 | } | 1433 | } |
| 1412 | 1434 | ||
| 1413 | static void | 1435 | static void |
| @@ -1428,7 +1450,7 @@ gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, struct svc_r | |||
| 1428 | else | 1450 | else |
| 1429 | goto out_err; | 1451 | goto out_err; |
| 1430 | 1452 | ||
| 1431 | conn->cb_addrlen = rpc_uaddr2sockaddr(&init_net, se->se_callback_addr_val, | 1453 | conn->cb_addrlen = rpc_uaddr2sockaddr(clp->net, se->se_callback_addr_val, |
| 1432 | se->se_callback_addr_len, | 1454 | se->se_callback_addr_len, |
| 1433 | (struct sockaddr *)&conn->cb_addr, | 1455 | (struct sockaddr *)&conn->cb_addr, |
| 1434 | sizeof(conn->cb_addr)); | 1456 | sizeof(conn->cb_addr)); |
| @@ -1572,12 +1594,11 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, | |||
| 1572 | { | 1594 | { |
| 1573 | struct nfs4_client *unconf, *conf, *new; | 1595 | struct nfs4_client *unconf, *conf, *new; |
| 1574 | __be32 status; | 1596 | __be32 status; |
| 1575 | unsigned int strhashval; | ||
| 1576 | char dname[HEXDIR_LEN]; | ||
| 1577 | char addr_str[INET6_ADDRSTRLEN]; | 1597 | char addr_str[INET6_ADDRSTRLEN]; |
| 1578 | nfs4_verifier verf = exid->verifier; | 1598 | nfs4_verifier verf = exid->verifier; |
| 1579 | struct sockaddr *sa = svc_addr(rqstp); | 1599 | struct sockaddr *sa = svc_addr(rqstp); |
| 1580 | bool update = exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A; | 1600 | bool update = exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A; |
| 1601 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | ||
| 1581 | 1602 | ||
| 1582 | rpc_ntop(sa, addr_str, sizeof(addr_str)); | 1603 | rpc_ntop(sa, addr_str, sizeof(addr_str)); |
| 1583 | dprintk("%s rqstp=%p exid=%p clname.len=%u clname.data=%p " | 1604 | dprintk("%s rqstp=%p exid=%p clname.len=%u clname.data=%p " |
| @@ -1592,24 +1613,16 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, | |||
| 1592 | switch (exid->spa_how) { | 1613 | switch (exid->spa_how) { |
| 1593 | case SP4_NONE: | 1614 | case SP4_NONE: |
| 1594 | break; | 1615 | break; |
| 1616 | default: /* checked by xdr code */ | ||
| 1617 | WARN_ON_ONCE(1); | ||
| 1595 | case SP4_SSV: | 1618 | case SP4_SSV: |
| 1596 | return nfserr_serverfault; | ||
| 1597 | default: | ||
| 1598 | BUG(); /* checked by xdr code */ | ||
| 1599 | case SP4_MACH_CRED: | 1619 | case SP4_MACH_CRED: |
| 1600 | return nfserr_serverfault; /* no excuse :-/ */ | 1620 | return nfserr_serverfault; /* no excuse :-/ */ |
| 1601 | } | 1621 | } |
| 1602 | 1622 | ||
| 1603 | status = nfs4_make_rec_clidname(dname, &exid->clname); | ||
| 1604 | |||
| 1605 | if (status) | ||
| 1606 | return status; | ||
| 1607 | |||
| 1608 | strhashval = clientstr_hashval(dname); | ||
| 1609 | |||
| 1610 | /* Cases below refer to rfc 5661 section 18.35.4: */ | 1623 | /* Cases below refer to rfc 5661 section 18.35.4: */ |
| 1611 | nfs4_lock_state(); | 1624 | nfs4_lock_state(); |
| 1612 | conf = find_confirmed_client_by_str(dname, strhashval); | 1625 | conf = find_confirmed_client_by_name(&exid->clname, nn); |
| 1613 | if (conf) { | 1626 | if (conf) { |
| 1614 | bool creds_match = same_creds(&conf->cl_cred, &rqstp->rq_cred); | 1627 | bool creds_match = same_creds(&conf->cl_cred, &rqstp->rq_cred); |
| 1615 | bool verfs_match = same_verf(&verf, &conf->cl_verifier); | 1628 | bool verfs_match = same_verf(&verf, &conf->cl_verifier); |
| @@ -1654,21 +1667,21 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, | |||
| 1654 | goto out; | 1667 | goto out; |
| 1655 | } | 1668 | } |
| 1656 | 1669 | ||
| 1657 | unconf = find_unconfirmed_client_by_str(dname, strhashval); | 1670 | unconf = find_unconfirmed_client_by_name(&exid->clname, nn); |
| 1658 | if (unconf) /* case 4, possible retry or client restart */ | 1671 | if (unconf) /* case 4, possible retry or client restart */ |
| 1659 | expire_client(unconf); | 1672 | expire_client(unconf); |
| 1660 | 1673 | ||
| 1661 | /* case 1 (normal case) */ | 1674 | /* case 1 (normal case) */ |
| 1662 | out_new: | 1675 | out_new: |
| 1663 | new = create_client(exid->clname, dname, rqstp, &verf); | 1676 | new = create_client(exid->clname, rqstp, &verf); |
| 1664 | if (new == NULL) { | 1677 | if (new == NULL) { |
| 1665 | status = nfserr_jukebox; | 1678 | status = nfserr_jukebox; |
| 1666 | goto out; | 1679 | goto out; |
| 1667 | } | 1680 | } |
| 1668 | new->cl_minorversion = 1; | 1681 | new->cl_minorversion = 1; |
| 1669 | 1682 | ||
| 1670 | gen_clid(new); | 1683 | gen_clid(new, nn); |
| 1671 | add_to_unconfirmed(new, strhashval); | 1684 | add_to_unconfirmed(new); |
| 1672 | out_copy: | 1685 | out_copy: |
| 1673 | exid->clientid.cl_boot = new->cl_clientid.cl_boot; | 1686 | exid->clientid.cl_boot = new->cl_clientid.cl_boot; |
| 1674 | exid->clientid.cl_id = new->cl_clientid.cl_id; | 1687 | exid->clientid.cl_id = new->cl_clientid.cl_id; |
| @@ -1761,12 +1774,13 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
| 1761 | struct nfsd4_conn *conn; | 1774 | struct nfsd4_conn *conn; |
| 1762 | struct nfsd4_clid_slot *cs_slot = NULL; | 1775 | struct nfsd4_clid_slot *cs_slot = NULL; |
| 1763 | __be32 status = 0; | 1776 | __be32 status = 0; |
| 1777 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | ||
| 1764 | 1778 | ||
| 1765 | if (cr_ses->flags & ~SESSION4_FLAG_MASK_A) | 1779 | if (cr_ses->flags & ~SESSION4_FLAG_MASK_A) |
| 1766 | return nfserr_inval; | 1780 | return nfserr_inval; |
| 1767 | if (check_forechannel_attrs(cr_ses->fore_channel)) | 1781 | if (check_forechannel_attrs(cr_ses->fore_channel)) |
| 1768 | return nfserr_toosmall; | 1782 | return nfserr_toosmall; |
| 1769 | new = alloc_session(&cr_ses->fore_channel); | 1783 | new = alloc_session(&cr_ses->fore_channel, nn); |
| 1770 | if (!new) | 1784 | if (!new) |
| 1771 | return nfserr_jukebox; | 1785 | return nfserr_jukebox; |
| 1772 | status = nfserr_jukebox; | 1786 | status = nfserr_jukebox; |
| @@ -1775,8 +1789,8 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
| 1775 | goto out_free_session; | 1789 | goto out_free_session; |
| 1776 | 1790 | ||
| 1777 | nfs4_lock_state(); | 1791 | nfs4_lock_state(); |
| 1778 | unconf = find_unconfirmed_client(&cr_ses->clientid, true); | 1792 | unconf = find_unconfirmed_client(&cr_ses->clientid, true, nn); |
| 1779 | conf = find_confirmed_client(&cr_ses->clientid, true); | 1793 | conf = find_confirmed_client(&cr_ses->clientid, true, nn); |
| 1780 | 1794 | ||
| 1781 | if (conf) { | 1795 | if (conf) { |
| 1782 | cs_slot = &conf->cl_cs_slot; | 1796 | cs_slot = &conf->cl_cs_slot; |
| @@ -1789,7 +1803,6 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
| 1789 | goto out_free_conn; | 1803 | goto out_free_conn; |
| 1790 | } | 1804 | } |
| 1791 | } else if (unconf) { | 1805 | } else if (unconf) { |
| 1792 | unsigned int hash; | ||
| 1793 | struct nfs4_client *old; | 1806 | struct nfs4_client *old; |
| 1794 | if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) || | 1807 | if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) || |
| 1795 | !rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) { | 1808 | !rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) { |
| @@ -1803,8 +1816,7 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
| 1803 | status = nfserr_seq_misordered; | 1816 | status = nfserr_seq_misordered; |
| 1804 | goto out_free_conn; | 1817 | goto out_free_conn; |
| 1805 | } | 1818 | } |
| 1806 | hash = clientstr_hashval(unconf->cl_recdir); | 1819 | old = find_confirmed_client_by_name(&unconf->cl_name, nn); |
| 1807 | old = find_confirmed_client_by_str(unconf->cl_recdir, hash); | ||
| 1808 | if (old) | 1820 | if (old) |
| 1809 | expire_client(old); | 1821 | expire_client(old); |
| 1810 | move_to_confirmed(unconf); | 1822 | move_to_confirmed(unconf); |
| @@ -1843,14 +1855,6 @@ out_free_session: | |||
| 1843 | goto out; | 1855 | goto out; |
| 1844 | } | 1856 | } |
| 1845 | 1857 | ||
| 1846 | static bool nfsd4_last_compound_op(struct svc_rqst *rqstp) | ||
| 1847 | { | ||
| 1848 | struct nfsd4_compoundres *resp = rqstp->rq_resp; | ||
| 1849 | struct nfsd4_compoundargs *argp = rqstp->rq_argp; | ||
| 1850 | |||
| 1851 | return argp->opcnt == resp->opcnt; | ||
| 1852 | } | ||
| 1853 | |||
| 1854 | static __be32 nfsd4_map_bcts_dir(u32 *dir) | 1858 | static __be32 nfsd4_map_bcts_dir(u32 *dir) |
| 1855 | { | 1859 | { |
| 1856 | switch (*dir) { | 1860 | switch (*dir) { |
| @@ -1865,24 +1869,40 @@ static __be32 nfsd4_map_bcts_dir(u32 *dir) | |||
| 1865 | return nfserr_inval; | 1869 | return nfserr_inval; |
| 1866 | } | 1870 | } |
| 1867 | 1871 | ||
| 1872 | __be32 nfsd4_backchannel_ctl(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_backchannel_ctl *bc) | ||
| 1873 | { | ||
| 1874 | struct nfsd4_session *session = cstate->session; | ||
| 1875 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | ||
| 1876 | |||
| 1877 | spin_lock(&nn->client_lock); | ||
| 1878 | session->se_cb_prog = bc->bc_cb_program; | ||
| 1879 | session->se_cb_sec = bc->bc_cb_sec; | ||
| 1880 | spin_unlock(&nn->client_lock); | ||
| 1881 | |||
| 1882 | nfsd4_probe_callback(session->se_client); | ||
| 1883 | |||
| 1884 | return nfs_ok; | ||
| 1885 | } | ||
| 1886 | |||
| 1868 | __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp, | 1887 | __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp, |
| 1869 | struct nfsd4_compound_state *cstate, | 1888 | struct nfsd4_compound_state *cstate, |
| 1870 | struct nfsd4_bind_conn_to_session *bcts) | 1889 | struct nfsd4_bind_conn_to_session *bcts) |
| 1871 | { | 1890 | { |
| 1872 | __be32 status; | 1891 | __be32 status; |
| 1873 | struct nfsd4_conn *conn; | 1892 | struct nfsd4_conn *conn; |
| 1893 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | ||
| 1874 | 1894 | ||
| 1875 | if (!nfsd4_last_compound_op(rqstp)) | 1895 | if (!nfsd4_last_compound_op(rqstp)) |
| 1876 | return nfserr_not_only_op; | 1896 | return nfserr_not_only_op; |
| 1877 | spin_lock(&client_lock); | 1897 | spin_lock(&nn->client_lock); |
| 1878 | cstate->session = find_in_sessionid_hashtbl(&bcts->sessionid); | 1898 | cstate->session = find_in_sessionid_hashtbl(&bcts->sessionid, SVC_NET(rqstp)); |
| 1879 | /* Sorta weird: we only need the refcnt'ing because new_conn acquires | 1899 | /* Sorta weird: we only need the refcnt'ing because new_conn acquires |
| 1880 | * client_lock iself: */ | 1900 | * client_lock iself: */ |
| 1881 | if (cstate->session) { | 1901 | if (cstate->session) { |
| 1882 | nfsd4_get_session(cstate->session); | 1902 | nfsd4_get_session(cstate->session); |
| 1883 | atomic_inc(&cstate->session->se_client->cl_refcount); | 1903 | atomic_inc(&cstate->session->se_client->cl_refcount); |
| 1884 | } | 1904 | } |
| 1885 | spin_unlock(&client_lock); | 1905 | spin_unlock(&nn->client_lock); |
| 1886 | if (!cstate->session) | 1906 | if (!cstate->session) |
| 1887 | return nfserr_badsession; | 1907 | return nfserr_badsession; |
| 1888 | 1908 | ||
| @@ -1910,6 +1930,7 @@ nfsd4_destroy_session(struct svc_rqst *r, | |||
| 1910 | { | 1930 | { |
| 1911 | struct nfsd4_session *ses; | 1931 | struct nfsd4_session *ses; |
| 1912 | __be32 status = nfserr_badsession; | 1932 | __be32 status = nfserr_badsession; |
| 1933 | struct nfsd_net *nn = net_generic(SVC_NET(r), nfsd_net_id); | ||
| 1913 | 1934 | ||
| 1914 | /* Notes: | 1935 | /* Notes: |
| 1915 | * - The confirmed nfs4_client->cl_sessionid holds destroyed sessinid | 1936 | * - The confirmed nfs4_client->cl_sessionid holds destroyed sessinid |
| @@ -1923,24 +1944,24 @@ nfsd4_destroy_session(struct svc_rqst *r, | |||
| 1923 | return nfserr_not_only_op; | 1944 | return nfserr_not_only_op; |
| 1924 | } | 1945 | } |
| 1925 | dump_sessionid(__func__, &sessionid->sessionid); | 1946 | dump_sessionid(__func__, &sessionid->sessionid); |
| 1926 | spin_lock(&client_lock); | 1947 | spin_lock(&nn->client_lock); |
| 1927 | ses = find_in_sessionid_hashtbl(&sessionid->sessionid); | 1948 | ses = find_in_sessionid_hashtbl(&sessionid->sessionid, SVC_NET(r)); |
| 1928 | if (!ses) { | 1949 | if (!ses) { |
| 1929 | spin_unlock(&client_lock); | 1950 | spin_unlock(&nn->client_lock); |
| 1930 | goto out; | 1951 | goto out; |
| 1931 | } | 1952 | } |
| 1932 | 1953 | ||
| 1933 | unhash_session(ses); | 1954 | unhash_session(ses); |
| 1934 | spin_unlock(&client_lock); | 1955 | spin_unlock(&nn->client_lock); |
| 1935 | 1956 | ||
| 1936 | nfs4_lock_state(); | 1957 | nfs4_lock_state(); |
| 1937 | nfsd4_probe_callback_sync(ses->se_client); | 1958 | nfsd4_probe_callback_sync(ses->se_client); |
| 1938 | nfs4_unlock_state(); | 1959 | nfs4_unlock_state(); |
| 1939 | 1960 | ||
| 1940 | spin_lock(&client_lock); | 1961 | spin_lock(&nn->client_lock); |
| 1941 | nfsd4_del_conns(ses); | 1962 | nfsd4_del_conns(ses); |
| 1942 | nfsd4_put_session_locked(ses); | 1963 | nfsd4_put_session_locked(ses); |
| 1943 | spin_unlock(&client_lock); | 1964 | spin_unlock(&nn->client_lock); |
| 1944 | status = nfs_ok; | 1965 | status = nfs_ok; |
| 1945 | out: | 1966 | out: |
| 1946 | dprintk("%s returns %d\n", __func__, ntohl(status)); | 1967 | dprintk("%s returns %d\n", __func__, ntohl(status)); |
| @@ -2006,6 +2027,7 @@ nfsd4_sequence(struct svc_rqst *rqstp, | |||
| 2006 | struct nfsd4_slot *slot; | 2027 | struct nfsd4_slot *slot; |
| 2007 | struct nfsd4_conn *conn; | 2028 | struct nfsd4_conn *conn; |
| 2008 | __be32 status; | 2029 | __be32 status; |
| 2030 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | ||
| 2009 | 2031 | ||
| 2010 | if (resp->opcnt != 1) | 2032 | if (resp->opcnt != 1) |
| 2011 | return nfserr_sequence_pos; | 2033 | return nfserr_sequence_pos; |
| @@ -2018,9 +2040,9 @@ nfsd4_sequence(struct svc_rqst *rqstp, | |||
| 2018 | if (!conn) | 2040 | if (!conn) |
| 2019 | return nfserr_jukebox; | 2041 | return nfserr_jukebox; |
| 2020 | 2042 | ||
| 2021 | spin_lock(&client_lock); | 2043 | spin_lock(&nn->client_lock); |
| 2022 | status = nfserr_badsession; | 2044 | status = nfserr_badsession; |
| 2023 | session = find_in_sessionid_hashtbl(&seq->sessionid); | 2045 | session = find_in_sessionid_hashtbl(&seq->sessionid, SVC_NET(rqstp)); |
| 2024 | if (!session) | 2046 | if (!session) |
| 2025 | goto out; | 2047 | goto out; |
| 2026 | 2048 | ||
| @@ -2094,7 +2116,7 @@ out: | |||
| 2094 | } | 2116 | } |
| 2095 | } | 2117 | } |
| 2096 | kfree(conn); | 2118 | kfree(conn); |
| 2097 | spin_unlock(&client_lock); | 2119 | spin_unlock(&nn->client_lock); |
| 2098 | dprintk("%s: return %d\n", __func__, ntohl(status)); | 2120 | dprintk("%s: return %d\n", __func__, ntohl(status)); |
| 2099 | return status; | 2121 | return status; |
| 2100 | } | 2122 | } |
| @@ -2104,10 +2126,11 @@ nfsd4_destroy_clientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *csta | |||
| 2104 | { | 2126 | { |
| 2105 | struct nfs4_client *conf, *unconf, *clp; | 2127 | struct nfs4_client *conf, *unconf, *clp; |
| 2106 | __be32 status = 0; | 2128 | __be32 status = 0; |
| 2129 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | ||
| 2107 | 2130 | ||
| 2108 | nfs4_lock_state(); | 2131 | nfs4_lock_state(); |
| 2109 | unconf = find_unconfirmed_client(&dc->clientid, true); | 2132 | unconf = find_unconfirmed_client(&dc->clientid, true, nn); |
| 2110 | conf = find_confirmed_client(&dc->clientid, true); | 2133 | conf = find_confirmed_client(&dc->clientid, true, nn); |
| 2111 | 2134 | ||
| 2112 | if (conf) { | 2135 | if (conf) { |
| 2113 | clp = conf; | 2136 | clp = conf; |
| @@ -2181,20 +2204,13 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
| 2181 | { | 2204 | { |
| 2182 | struct xdr_netobj clname = setclid->se_name; | 2205 | struct xdr_netobj clname = setclid->se_name; |
| 2183 | nfs4_verifier clverifier = setclid->se_verf; | 2206 | nfs4_verifier clverifier = setclid->se_verf; |
| 2184 | unsigned int strhashval; | ||
| 2185 | struct nfs4_client *conf, *unconf, *new; | 2207 | struct nfs4_client *conf, *unconf, *new; |
| 2186 | __be32 status; | 2208 | __be32 status; |
| 2187 | char dname[HEXDIR_LEN]; | 2209 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); |
| 2188 | |||
| 2189 | status = nfs4_make_rec_clidname(dname, &clname); | ||
| 2190 | if (status) | ||
| 2191 | return status; | ||
| 2192 | |||
| 2193 | strhashval = clientstr_hashval(dname); | ||
| 2194 | 2210 | ||
| 2195 | /* Cases below refer to rfc 3530 section 14.2.33: */ | 2211 | /* Cases below refer to rfc 3530 section 14.2.33: */ |
| 2196 | nfs4_lock_state(); | 2212 | nfs4_lock_state(); |
| 2197 | conf = find_confirmed_client_by_str(dname, strhashval); | 2213 | conf = find_confirmed_client_by_name(&clname, nn); |
| 2198 | if (conf) { | 2214 | if (conf) { |
| 2199 | /* case 0: */ | 2215 | /* case 0: */ |
| 2200 | status = nfserr_clid_inuse; | 2216 | status = nfserr_clid_inuse; |
| @@ -2209,21 +2225,21 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
| 2209 | goto out; | 2225 | goto out; |
| 2210 | } | 2226 | } |
| 2211 | } | 2227 | } |
| 2212 | unconf = find_unconfirmed_client_by_str(dname, strhashval); | 2228 | unconf = find_unconfirmed_client_by_name(&clname, nn); |
| 2213 | if (unconf) | 2229 | if (unconf) |
| 2214 | expire_client(unconf); | 2230 | expire_client(unconf); |
| 2215 | status = nfserr_jukebox; | 2231 | status = nfserr_jukebox; |
| 2216 | new = create_client(clname, dname, rqstp, &clverifier); | 2232 | new = create_client(clname, rqstp, &clverifier); |
| 2217 | if (new == NULL) | 2233 | if (new == NULL) |
| 2218 | goto out; | 2234 | goto out; |
| 2219 | if (conf && same_verf(&conf->cl_verifier, &clverifier)) | 2235 | if (conf && same_verf(&conf->cl_verifier, &clverifier)) |
| 2220 | /* case 1: probable callback update */ | 2236 | /* case 1: probable callback update */ |
| 2221 | copy_clid(new, conf); | 2237 | copy_clid(new, conf); |
| 2222 | else /* case 4 (new client) or cases 2, 3 (client reboot): */ | 2238 | else /* case 4 (new client) or cases 2, 3 (client reboot): */ |
| 2223 | gen_clid(new); | 2239 | gen_clid(new, nn); |
| 2224 | new->cl_minorversion = 0; | 2240 | new->cl_minorversion = 0; |
| 2225 | gen_callback(new, setclid, rqstp); | 2241 | gen_callback(new, setclid, rqstp); |
| 2226 | add_to_unconfirmed(new, strhashval); | 2242 | add_to_unconfirmed(new); |
| 2227 | setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot; | 2243 | setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot; |
| 2228 | setclid->se_clientid.cl_id = new->cl_clientid.cl_id; | 2244 | setclid->se_clientid.cl_id = new->cl_clientid.cl_id; |
| 2229 | memcpy(setclid->se_confirm.data, new->cl_confirm.data, sizeof(setclid->se_confirm.data)); | 2245 | memcpy(setclid->se_confirm.data, new->cl_confirm.data, sizeof(setclid->se_confirm.data)); |
| @@ -2243,14 +2259,14 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, | |||
| 2243 | nfs4_verifier confirm = setclientid_confirm->sc_confirm; | 2259 | nfs4_verifier confirm = setclientid_confirm->sc_confirm; |
| 2244 | clientid_t * clid = &setclientid_confirm->sc_clientid; | 2260 | clientid_t * clid = &setclientid_confirm->sc_clientid; |
| 2245 | __be32 status; | 2261 | __be32 status; |
| 2246 | struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); | 2262 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); |
| 2247 | 2263 | ||
| 2248 | if (STALE_CLIENTID(clid, nn)) | 2264 | if (STALE_CLIENTID(clid, nn)) |
| 2249 | return nfserr_stale_clientid; | 2265 | return nfserr_stale_clientid; |
| 2250 | nfs4_lock_state(); | 2266 | nfs4_lock_state(); |
| 2251 | 2267 | ||
| 2252 | conf = find_confirmed_client(clid, false); | 2268 | conf = find_confirmed_client(clid, false, nn); |
| 2253 | unconf = find_unconfirmed_client(clid, false); | 2269 | unconf = find_unconfirmed_client(clid, false, nn); |
| 2254 | /* | 2270 | /* |
| 2255 | * We try hard to give out unique clientid's, so if we get an | 2271 | * We try hard to give out unique clientid's, so if we get an |
| 2256 | * attempt to confirm the same clientid with a different cred, | 2272 | * attempt to confirm the same clientid with a different cred, |
| @@ -2276,9 +2292,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, | |||
| 2276 | nfsd4_probe_callback(conf); | 2292 | nfsd4_probe_callback(conf); |
| 2277 | expire_client(unconf); | 2293 | expire_client(unconf); |
| 2278 | } else { /* case 3: normal case; new or rebooted client */ | 2294 | } else { /* case 3: normal case; new or rebooted client */ |
| 2279 | unsigned int hash = clientstr_hashval(unconf->cl_recdir); | 2295 | conf = find_confirmed_client_by_name(&unconf->cl_name, nn); |
| 2280 | |||
| 2281 | conf = find_confirmed_client_by_str(unconf->cl_recdir, hash); | ||
| 2282 | if (conf) | 2296 | if (conf) |
| 2283 | expire_client(conf); | 2297 | expire_client(conf); |
| 2284 | move_to_confirmed(unconf); | 2298 | move_to_confirmed(unconf); |
| @@ -2340,7 +2354,7 @@ nfsd4_init_slabs(void) | |||
| 2340 | if (openowner_slab == NULL) | 2354 | if (openowner_slab == NULL) |
| 2341 | goto out_nomem; | 2355 | goto out_nomem; |
| 2342 | lockowner_slab = kmem_cache_create("nfsd4_lockowners", | 2356 | lockowner_slab = kmem_cache_create("nfsd4_lockowners", |
| 2343 | sizeof(struct nfs4_openowner), 0, 0, NULL); | 2357 | sizeof(struct nfs4_lockowner), 0, 0, NULL); |
| 2344 | if (lockowner_slab == NULL) | 2358 | if (lockowner_slab == NULL) |
| 2345 | goto out_nomem; | 2359 | goto out_nomem; |
| 2346 | file_slab = kmem_cache_create("nfsd4_files", | 2360 | file_slab = kmem_cache_create("nfsd4_files", |
| @@ -2404,7 +2418,9 @@ static inline void *alloc_stateowner(struct kmem_cache *slab, struct xdr_netobj | |||
| 2404 | 2418 | ||
| 2405 | static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, unsigned int strhashval) | 2419 | static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, unsigned int strhashval) |
| 2406 | { | 2420 | { |
| 2407 | list_add(&oo->oo_owner.so_strhash, &ownerstr_hashtbl[strhashval]); | 2421 | struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); |
| 2422 | |||
| 2423 | list_add(&oo->oo_owner.so_strhash, &nn->ownerstr_hashtbl[strhashval]); | ||
| 2408 | list_add(&oo->oo_perclient, &clp->cl_openowners); | 2424 | list_add(&oo->oo_perclient, &clp->cl_openowners); |
| 2409 | } | 2425 | } |
| 2410 | 2426 | ||
| @@ -2444,11 +2460,13 @@ static void init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp, | |||
| 2444 | } | 2460 | } |
| 2445 | 2461 | ||
| 2446 | static void | 2462 | static void |
| 2447 | move_to_close_lru(struct nfs4_openowner *oo) | 2463 | move_to_close_lru(struct nfs4_openowner *oo, struct net *net) |
| 2448 | { | 2464 | { |
| 2465 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
| 2466 | |||
| 2449 | dprintk("NFSD: move_to_close_lru nfs4_openowner %p\n", oo); | 2467 | dprintk("NFSD: move_to_close_lru nfs4_openowner %p\n", oo); |
| 2450 | 2468 | ||
| 2451 | list_move_tail(&oo->oo_close_lru, &close_lru); | 2469 | list_move_tail(&oo->oo_close_lru, &nn->close_lru); |
| 2452 | oo->oo_time = get_seconds(); | 2470 | oo->oo_time = get_seconds(); |
| 2453 | } | 2471 | } |
| 2454 | 2472 | ||
| @@ -2462,13 +2480,14 @@ same_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner, | |||
| 2462 | } | 2480 | } |
| 2463 | 2481 | ||
| 2464 | static struct nfs4_openowner * | 2482 | static struct nfs4_openowner * |
| 2465 | find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open, bool sessions) | 2483 | find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open, |
| 2484 | bool sessions, struct nfsd_net *nn) | ||
| 2466 | { | 2485 | { |
| 2467 | struct nfs4_stateowner *so; | 2486 | struct nfs4_stateowner *so; |
| 2468 | struct nfs4_openowner *oo; | 2487 | struct nfs4_openowner *oo; |
| 2469 | struct nfs4_client *clp; | 2488 | struct nfs4_client *clp; |
| 2470 | 2489 | ||
| 2471 | list_for_each_entry(so, &ownerstr_hashtbl[hashval], so_strhash) { | 2490 | list_for_each_entry(so, &nn->ownerstr_hashtbl[hashval], so_strhash) { |
| 2472 | if (!so->so_is_open_owner) | 2491 | if (!so->so_is_open_owner) |
| 2473 | continue; | 2492 | continue; |
| 2474 | if (same_owner_str(so, &open->op_owner, &open->op_clientid)) { | 2493 | if (same_owner_str(so, &open->op_owner, &open->op_clientid)) { |
| @@ -2555,9 +2574,14 @@ static void nfsd_break_deleg_cb(struct file_lock *fl) | |||
| 2555 | struct nfs4_file *fp = (struct nfs4_file *)fl->fl_owner; | 2574 | struct nfs4_file *fp = (struct nfs4_file *)fl->fl_owner; |
| 2556 | struct nfs4_delegation *dp; | 2575 | struct nfs4_delegation *dp; |
| 2557 | 2576 | ||
| 2558 | BUG_ON(!fp); | 2577 | if (!fp) { |
| 2559 | /* We assume break_lease is only called once per lease: */ | 2578 | WARN(1, "(%p)->fl_owner NULL\n", fl); |
| 2560 | BUG_ON(fp->fi_had_conflict); | 2579 | return; |
| 2580 | } | ||
| 2581 | if (fp->fi_had_conflict) { | ||
| 2582 | WARN(1, "duplicate break on %p\n", fp); | ||
| 2583 | return; | ||
| 2584 | } | ||
| 2561 | /* | 2585 | /* |
| 2562 | * We don't want the locks code to timeout the lease for us; | 2586 | * We don't want the locks code to timeout the lease for us; |
| 2563 | * we'll remove it ourself if a delegation isn't returned | 2587 | * we'll remove it ourself if a delegation isn't returned |
| @@ -2599,14 +2623,13 @@ static __be32 nfsd4_check_seqid(struct nfsd4_compound_state *cstate, struct nfs4 | |||
| 2599 | 2623 | ||
| 2600 | __be32 | 2624 | __be32 |
| 2601 | nfsd4_process_open1(struct nfsd4_compound_state *cstate, | 2625 | nfsd4_process_open1(struct nfsd4_compound_state *cstate, |
| 2602 | struct nfsd4_open *open) | 2626 | struct nfsd4_open *open, struct nfsd_net *nn) |
| 2603 | { | 2627 | { |
| 2604 | clientid_t *clientid = &open->op_clientid; | 2628 | clientid_t *clientid = &open->op_clientid; |
| 2605 | struct nfs4_client *clp = NULL; | 2629 | struct nfs4_client *clp = NULL; |
| 2606 | unsigned int strhashval; | 2630 | unsigned int strhashval; |
| 2607 | struct nfs4_openowner *oo = NULL; | 2631 | struct nfs4_openowner *oo = NULL; |
| 2608 | __be32 status; | 2632 | __be32 status; |
| 2609 | struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); | ||
| 2610 | 2633 | ||
| 2611 | if (STALE_CLIENTID(&open->op_clientid, nn)) | 2634 | if (STALE_CLIENTID(&open->op_clientid, nn)) |
| 2612 | return nfserr_stale_clientid; | 2635 | return nfserr_stale_clientid; |
| @@ -2619,10 +2642,11 @@ nfsd4_process_open1(struct nfsd4_compound_state *cstate, | |||
| 2619 | return nfserr_jukebox; | 2642 | return nfserr_jukebox; |
| 2620 | 2643 | ||
| 2621 | strhashval = ownerstr_hashval(clientid->cl_id, &open->op_owner); | 2644 | strhashval = ownerstr_hashval(clientid->cl_id, &open->op_owner); |
| 2622 | oo = find_openstateowner_str(strhashval, open, cstate->minorversion); | 2645 | oo = find_openstateowner_str(strhashval, open, cstate->minorversion, nn); |
| 2623 | open->op_openowner = oo; | 2646 | open->op_openowner = oo; |
| 2624 | if (!oo) { | 2647 | if (!oo) { |
| 2625 | clp = find_confirmed_client(clientid, cstate->minorversion); | 2648 | clp = find_confirmed_client(clientid, cstate->minorversion, |
| 2649 | nn); | ||
| 2626 | if (clp == NULL) | 2650 | if (clp == NULL) |
| 2627 | return nfserr_expired; | 2651 | return nfserr_expired; |
| 2628 | goto new_owner; | 2652 | goto new_owner; |
| @@ -2891,7 +2915,7 @@ static void nfsd4_open_deleg_none_ext(struct nfsd4_open *open, int status) | |||
| 2891 | open->op_why_no_deleg = WND4_CANCELLED; | 2915 | open->op_why_no_deleg = WND4_CANCELLED; |
| 2892 | break; | 2916 | break; |
| 2893 | case NFS4_SHARE_WANT_NO_DELEG: | 2917 | case NFS4_SHARE_WANT_NO_DELEG: |
| 2894 | BUG(); /* not supposed to get here */ | 2918 | WARN_ON_ONCE(1); |
| 2895 | } | 2919 | } |
| 2896 | } | 2920 | } |
| 2897 | } | 2921 | } |
| @@ -2959,6 +2983,7 @@ out: | |||
| 2959 | } | 2983 | } |
| 2960 | return; | 2984 | return; |
| 2961 | out_free: | 2985 | out_free: |
| 2986 | unhash_stid(&dp->dl_stid); | ||
| 2962 | nfs4_put_delegation(dp); | 2987 | nfs4_put_delegation(dp); |
| 2963 | out_no_deleg: | 2988 | out_no_deleg: |
| 2964 | flag = NFS4_OPEN_DELEGATE_NONE; | 2989 | flag = NFS4_OPEN_DELEGATE_NONE; |
| @@ -3104,27 +3129,32 @@ void nfsd4_cleanup_open_state(struct nfsd4_open *open, __be32 status) | |||
| 3104 | free_generic_stateid(open->op_stp); | 3129 | free_generic_stateid(open->op_stp); |
| 3105 | } | 3130 | } |
| 3106 | 3131 | ||
| 3132 | static __be32 lookup_clientid(clientid_t *clid, bool session, struct nfsd_net *nn, struct nfs4_client **clp) | ||
| 3133 | { | ||
| 3134 | struct nfs4_client *found; | ||
| 3135 | |||
| 3136 | if (STALE_CLIENTID(clid, nn)) | ||
| 3137 | return nfserr_stale_clientid; | ||
| 3138 | found = find_confirmed_client(clid, session, nn); | ||
| 3139 | if (clp) | ||
| 3140 | *clp = found; | ||
| 3141 | return found ? nfs_ok : nfserr_expired; | ||
| 3142 | } | ||
| 3143 | |||
| 3107 | __be32 | 3144 | __be32 |
| 3108 | nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 3145 | nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
| 3109 | clientid_t *clid) | 3146 | clientid_t *clid) |
| 3110 | { | 3147 | { |
| 3111 | struct nfs4_client *clp; | 3148 | struct nfs4_client *clp; |
| 3112 | __be32 status; | 3149 | __be32 status; |
| 3113 | struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); | 3150 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); |
| 3114 | 3151 | ||
| 3115 | nfs4_lock_state(); | 3152 | nfs4_lock_state(); |
| 3116 | dprintk("process_renew(%08x/%08x): starting\n", | 3153 | dprintk("process_renew(%08x/%08x): starting\n", |
| 3117 | clid->cl_boot, clid->cl_id); | 3154 | clid->cl_boot, clid->cl_id); |
| 3118 | status = nfserr_stale_clientid; | 3155 | status = lookup_clientid(clid, cstate->minorversion, nn, &clp); |
| 3119 | if (STALE_CLIENTID(clid, nn)) | 3156 | if (status) |
| 3120 | goto out; | ||
| 3121 | clp = find_confirmed_client(clid, cstate->minorversion); | ||
| 3122 | status = nfserr_expired; | ||
| 3123 | if (clp == NULL) { | ||
| 3124 | /* We assume the client took too long to RENEW. */ | ||
| 3125 | dprintk("nfsd4_renew: clientid not found!\n"); | ||
| 3126 | goto out; | 3157 | goto out; |
| 3127 | } | ||
| 3128 | status = nfserr_cb_path_down; | 3158 | status = nfserr_cb_path_down; |
| 3129 | if (!list_empty(&clp->cl_delegations) | 3159 | if (!list_empty(&clp->cl_delegations) |
| 3130 | && clp->cl_cb_state != NFSD4_CB_UP) | 3160 | && clp->cl_cb_state != NFSD4_CB_UP) |
| @@ -3136,44 +3166,42 @@ out: | |||
| 3136 | } | 3166 | } |
| 3137 | 3167 | ||
| 3138 | static void | 3168 | static void |
| 3139 | nfsd4_end_grace(struct net *net) | 3169 | nfsd4_end_grace(struct nfsd_net *nn) |
| 3140 | { | 3170 | { |
| 3141 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
| 3142 | |||
| 3143 | /* do nothing if grace period already ended */ | 3171 | /* do nothing if grace period already ended */ |
| 3144 | if (nn->grace_ended) | 3172 | if (nn->grace_ended) |
| 3145 | return; | 3173 | return; |
| 3146 | 3174 | ||
| 3147 | dprintk("NFSD: end of grace period\n"); | 3175 | dprintk("NFSD: end of grace period\n"); |
| 3148 | nn->grace_ended = true; | 3176 | nn->grace_ended = true; |
| 3149 | nfsd4_record_grace_done(net, nn->boot_time); | 3177 | nfsd4_record_grace_done(nn, nn->boot_time); |
| 3150 | locks_end_grace(&nn->nfsd4_manager); | 3178 | locks_end_grace(&nn->nfsd4_manager); |
| 3151 | /* | 3179 | /* |
| 3152 | * Now that every NFSv4 client has had the chance to recover and | 3180 | * Now that every NFSv4 client has had the chance to recover and |
| 3153 | * to see the (possibly new, possibly shorter) lease time, we | 3181 | * to see the (possibly new, possibly shorter) lease time, we |
| 3154 | * can safely set the next grace time to the current lease time: | 3182 | * can safely set the next grace time to the current lease time: |
| 3155 | */ | 3183 | */ |
| 3156 | nfsd4_grace = nfsd4_lease; | 3184 | nn->nfsd4_grace = nn->nfsd4_lease; |
| 3157 | } | 3185 | } |
| 3158 | 3186 | ||
| 3159 | static time_t | 3187 | static time_t |
| 3160 | nfs4_laundromat(void) | 3188 | nfs4_laundromat(struct nfsd_net *nn) |
| 3161 | { | 3189 | { |
| 3162 | struct nfs4_client *clp; | 3190 | struct nfs4_client *clp; |
| 3163 | struct nfs4_openowner *oo; | 3191 | struct nfs4_openowner *oo; |
| 3164 | struct nfs4_delegation *dp; | 3192 | struct nfs4_delegation *dp; |
| 3165 | struct list_head *pos, *next, reaplist; | 3193 | struct list_head *pos, *next, reaplist; |
| 3166 | time_t cutoff = get_seconds() - nfsd4_lease; | 3194 | time_t cutoff = get_seconds() - nn->nfsd4_lease; |
| 3167 | time_t t, clientid_val = nfsd4_lease; | 3195 | time_t t, clientid_val = nn->nfsd4_lease; |
| 3168 | time_t u, test_val = nfsd4_lease; | 3196 | time_t u, test_val = nn->nfsd4_lease; |
| 3169 | 3197 | ||
| 3170 | nfs4_lock_state(); | 3198 | nfs4_lock_state(); |
| 3171 | 3199 | ||
| 3172 | dprintk("NFSD: laundromat service - starting\n"); | 3200 | dprintk("NFSD: laundromat service - starting\n"); |
| 3173 | nfsd4_end_grace(&init_net); | 3201 | nfsd4_end_grace(nn); |
| 3174 | INIT_LIST_HEAD(&reaplist); | 3202 | INIT_LIST_HEAD(&reaplist); |
| 3175 | spin_lock(&client_lock); | 3203 | spin_lock(&nn->client_lock); |
| 3176 | list_for_each_safe(pos, next, &client_lru) { | 3204 | list_for_each_safe(pos, next, &nn->client_lru) { |
| 3177 | clp = list_entry(pos, struct nfs4_client, cl_lru); | 3205 | clp = list_entry(pos, struct nfs4_client, cl_lru); |
| 3178 | if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) { | 3206 | if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) { |
| 3179 | t = clp->cl_time - cutoff; | 3207 | t = clp->cl_time - cutoff; |
| @@ -3189,7 +3217,7 @@ nfs4_laundromat(void) | |||
| 3189 | unhash_client_locked(clp); | 3217 | unhash_client_locked(clp); |
| 3190 | list_add(&clp->cl_lru, &reaplist); | 3218 | list_add(&clp->cl_lru, &reaplist); |
| 3191 | } | 3219 | } |
| 3192 | spin_unlock(&client_lock); | 3220 | spin_unlock(&nn->client_lock); |
| 3193 | list_for_each_safe(pos, next, &reaplist) { | 3221 | list_for_each_safe(pos, next, &reaplist) { |
| 3194 | clp = list_entry(pos, struct nfs4_client, cl_lru); | 3222 | clp = list_entry(pos, struct nfs4_client, cl_lru); |
| 3195 | dprintk("NFSD: purging unused client (clientid %08x)\n", | 3223 | dprintk("NFSD: purging unused client (clientid %08x)\n", |
| @@ -3199,6 +3227,8 @@ nfs4_laundromat(void) | |||
| 3199 | spin_lock(&recall_lock); | 3227 | spin_lock(&recall_lock); |
| 3200 | list_for_each_safe(pos, next, &del_recall_lru) { | 3228 | list_for_each_safe(pos, next, &del_recall_lru) { |
| 3201 | dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); | 3229 | dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); |
| 3230 | if (net_generic(dp->dl_stid.sc_client->net, nfsd_net_id) != nn) | ||
| 3231 | continue; | ||
| 3202 | if (time_after((unsigned long)dp->dl_time, (unsigned long)cutoff)) { | 3232 | if (time_after((unsigned long)dp->dl_time, (unsigned long)cutoff)) { |
| 3203 | u = dp->dl_time - cutoff; | 3233 | u = dp->dl_time - cutoff; |
| 3204 | if (test_val > u) | 3234 | if (test_val > u) |
| @@ -3212,8 +3242,8 @@ nfs4_laundromat(void) | |||
| 3212 | dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); | 3242 | dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); |
| 3213 | unhash_delegation(dp); | 3243 | unhash_delegation(dp); |
| 3214 | } | 3244 | } |
| 3215 | test_val = nfsd4_lease; | 3245 | test_val = nn->nfsd4_lease; |
| 3216 | list_for_each_safe(pos, next, &close_lru) { | 3246 | list_for_each_safe(pos, next, &nn->close_lru) { |
| 3217 | oo = container_of(pos, struct nfs4_openowner, oo_close_lru); | 3247 | oo = container_of(pos, struct nfs4_openowner, oo_close_lru); |
| 3218 | if (time_after((unsigned long)oo->oo_time, (unsigned long)cutoff)) { | 3248 | if (time_after((unsigned long)oo->oo_time, (unsigned long)cutoff)) { |
| 3219 | u = oo->oo_time - cutoff; | 3249 | u = oo->oo_time - cutoff; |
| @@ -3231,16 +3261,19 @@ nfs4_laundromat(void) | |||
| 3231 | 3261 | ||
| 3232 | static struct workqueue_struct *laundry_wq; | 3262 | static struct workqueue_struct *laundry_wq; |
| 3233 | static void laundromat_main(struct work_struct *); | 3263 | static void laundromat_main(struct work_struct *); |
| 3234 | static DECLARE_DELAYED_WORK(laundromat_work, laundromat_main); | ||
| 3235 | 3264 | ||
| 3236 | static void | 3265 | static void |
| 3237 | laundromat_main(struct work_struct *not_used) | 3266 | laundromat_main(struct work_struct *laundry) |
| 3238 | { | 3267 | { |
| 3239 | time_t t; | 3268 | time_t t; |
| 3269 | struct delayed_work *dwork = container_of(laundry, struct delayed_work, | ||
| 3270 | work); | ||
| 3271 | struct nfsd_net *nn = container_of(dwork, struct nfsd_net, | ||
| 3272 | laundromat_work); | ||
| 3240 | 3273 | ||
| 3241 | t = nfs4_laundromat(); | 3274 | t = nfs4_laundromat(nn); |
| 3242 | dprintk("NFSD: laundromat_main - sleeping for %ld seconds\n", t); | 3275 | dprintk("NFSD: laundromat_main - sleeping for %ld seconds\n", t); |
| 3243 | queue_delayed_work(laundry_wq, &laundromat_work, t*HZ); | 3276 | queue_delayed_work(laundry_wq, &nn->laundromat_work, t*HZ); |
| 3244 | } | 3277 | } |
| 3245 | 3278 | ||
| 3246 | static inline __be32 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_ol_stateid *stp) | 3279 | static inline __be32 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_ol_stateid *stp) |
| @@ -3385,16 +3418,17 @@ static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid) | |||
| 3385 | return nfs_ok; | 3418 | return nfs_ok; |
| 3386 | } | 3419 | } |
| 3387 | 3420 | ||
| 3388 | static __be32 nfsd4_lookup_stateid(stateid_t *stateid, unsigned char typemask, struct nfs4_stid **s, bool sessions) | 3421 | static __be32 nfsd4_lookup_stateid(stateid_t *stateid, unsigned char typemask, |
| 3422 | struct nfs4_stid **s, bool sessions, | ||
| 3423 | struct nfsd_net *nn) | ||
| 3389 | { | 3424 | { |
| 3390 | struct nfs4_client *cl; | 3425 | struct nfs4_client *cl; |
| 3391 | struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); | ||
| 3392 | 3426 | ||
| 3393 | if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) | 3427 | if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) |
| 3394 | return nfserr_bad_stateid; | 3428 | return nfserr_bad_stateid; |
| 3395 | if (STALE_STATEID(stateid, nn)) | 3429 | if (STALE_STATEID(stateid, nn)) |
| 3396 | return nfserr_stale_stateid; | 3430 | return nfserr_stale_stateid; |
| 3397 | cl = find_confirmed_client(&stateid->si_opaque.so_clid, sessions); | 3431 | cl = find_confirmed_client(&stateid->si_opaque.so_clid, sessions, nn); |
| 3398 | if (!cl) | 3432 | if (!cl) |
| 3399 | return nfserr_expired; | 3433 | return nfserr_expired; |
| 3400 | *s = find_stateid_by_type(cl, stateid, typemask); | 3434 | *s = find_stateid_by_type(cl, stateid, typemask); |
| @@ -3416,6 +3450,7 @@ nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate, | |||
| 3416 | struct nfs4_delegation *dp = NULL; | 3450 | struct nfs4_delegation *dp = NULL; |
| 3417 | struct svc_fh *current_fh = &cstate->current_fh; | 3451 | struct svc_fh *current_fh = &cstate->current_fh; |
| 3418 | struct inode *ino = current_fh->fh_dentry->d_inode; | 3452 | struct inode *ino = current_fh->fh_dentry->d_inode; |
| 3453 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
| 3419 | __be32 status; | 3454 | __be32 status; |
| 3420 | 3455 | ||
| 3421 | if (filpp) | 3456 | if (filpp) |
| @@ -3427,7 +3462,8 @@ nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate, | |||
| 3427 | if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) | 3462 | if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) |
| 3428 | return check_special_stateids(net, current_fh, stateid, flags); | 3463 | return check_special_stateids(net, current_fh, stateid, flags); |
| 3429 | 3464 | ||
| 3430 | status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID, &s, cstate->minorversion); | 3465 | status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID, |
| 3466 | &s, cstate->minorversion, nn); | ||
| 3431 | if (status) | 3467 | if (status) |
| 3432 | return status; | 3468 | return status; |
| 3433 | status = check_stateid_generation(stateid, &s->sc_stateid, nfsd4_has_session(cstate)); | 3469 | status = check_stateid_generation(stateid, &s->sc_stateid, nfsd4_has_session(cstate)); |
| @@ -3441,7 +3477,11 @@ nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate, | |||
| 3441 | goto out; | 3477 | goto out; |
| 3442 | if (filpp) { | 3478 | if (filpp) { |
| 3443 | *filpp = dp->dl_file->fi_deleg_file; | 3479 | *filpp = dp->dl_file->fi_deleg_file; |
| 3444 | BUG_ON(!*filpp); | 3480 | if (!*filpp) { |
| 3481 | WARN_ON_ONCE(1); | ||
| 3482 | status = nfserr_serverfault; | ||
| 3483 | goto out; | ||
| 3484 | } | ||
| 3445 | } | 3485 | } |
| 3446 | break; | 3486 | break; |
| 3447 | case NFS4_OPEN_STID: | 3487 | case NFS4_OPEN_STID: |
| @@ -3568,7 +3608,8 @@ static __be32 nfs4_seqid_op_checks(struct nfsd4_compound_state *cstate, stateid_ | |||
| 3568 | static __be32 | 3608 | static __be32 |
| 3569 | nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, | 3609 | nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, |
| 3570 | stateid_t *stateid, char typemask, | 3610 | stateid_t *stateid, char typemask, |
| 3571 | struct nfs4_ol_stateid **stpp) | 3611 | struct nfs4_ol_stateid **stpp, |
| 3612 | struct nfsd_net *nn) | ||
| 3572 | { | 3613 | { |
| 3573 | __be32 status; | 3614 | __be32 status; |
| 3574 | struct nfs4_stid *s; | 3615 | struct nfs4_stid *s; |
| @@ -3577,7 +3618,8 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, | |||
| 3577 | seqid, STATEID_VAL(stateid)); | 3618 | seqid, STATEID_VAL(stateid)); |
| 3578 | 3619 | ||
| 3579 | *stpp = NULL; | 3620 | *stpp = NULL; |
| 3580 | status = nfsd4_lookup_stateid(stateid, typemask, &s, cstate->minorversion); | 3621 | status = nfsd4_lookup_stateid(stateid, typemask, &s, |
| 3622 | cstate->minorversion, nn); | ||
| 3581 | if (status) | 3623 | if (status) |
| 3582 | return status; | 3624 | return status; |
| 3583 | *stpp = openlockstateid(s); | 3625 | *stpp = openlockstateid(s); |
| @@ -3586,13 +3628,14 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, | |||
| 3586 | return nfs4_seqid_op_checks(cstate, stateid, seqid, *stpp); | 3628 | return nfs4_seqid_op_checks(cstate, stateid, seqid, *stpp); |
| 3587 | } | 3629 | } |
| 3588 | 3630 | ||
| 3589 | static __be32 nfs4_preprocess_confirmed_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, stateid_t *stateid, struct nfs4_ol_stateid **stpp) | 3631 | static __be32 nfs4_preprocess_confirmed_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, |
| 3632 | stateid_t *stateid, struct nfs4_ol_stateid **stpp, struct nfsd_net *nn) | ||
| 3590 | { | 3633 | { |
| 3591 | __be32 status; | 3634 | __be32 status; |
| 3592 | struct nfs4_openowner *oo; | 3635 | struct nfs4_openowner *oo; |
| 3593 | 3636 | ||
| 3594 | status = nfs4_preprocess_seqid_op(cstate, seqid, stateid, | 3637 | status = nfs4_preprocess_seqid_op(cstate, seqid, stateid, |
| 3595 | NFS4_OPEN_STID, stpp); | 3638 | NFS4_OPEN_STID, stpp, nn); |
| 3596 | if (status) | 3639 | if (status) |
| 3597 | return status; | 3640 | return status; |
| 3598 | oo = openowner((*stpp)->st_stateowner); | 3641 | oo = openowner((*stpp)->st_stateowner); |
| @@ -3608,6 +3651,7 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
| 3608 | __be32 status; | 3651 | __be32 status; |
| 3609 | struct nfs4_openowner *oo; | 3652 | struct nfs4_openowner *oo; |
| 3610 | struct nfs4_ol_stateid *stp; | 3653 | struct nfs4_ol_stateid *stp; |
| 3654 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | ||
| 3611 | 3655 | ||
| 3612 | dprintk("NFSD: nfsd4_open_confirm on file %.*s\n", | 3656 | dprintk("NFSD: nfsd4_open_confirm on file %.*s\n", |
| 3613 | (int)cstate->current_fh.fh_dentry->d_name.len, | 3657 | (int)cstate->current_fh.fh_dentry->d_name.len, |
| @@ -3621,7 +3665,7 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
| 3621 | 3665 | ||
| 3622 | status = nfs4_preprocess_seqid_op(cstate, | 3666 | status = nfs4_preprocess_seqid_op(cstate, |
| 3623 | oc->oc_seqid, &oc->oc_req_stateid, | 3667 | oc->oc_seqid, &oc->oc_req_stateid, |
| 3624 | NFS4_OPEN_STID, &stp); | 3668 | NFS4_OPEN_STID, &stp, nn); |
| 3625 | if (status) | 3669 | if (status) |
| 3626 | goto out; | 3670 | goto out; |
| 3627 | oo = openowner(stp->st_stateowner); | 3671 | oo = openowner(stp->st_stateowner); |
| @@ -3664,7 +3708,7 @@ static inline void nfs4_stateid_downgrade(struct nfs4_ol_stateid *stp, u32 to_ac | |||
| 3664 | case NFS4_SHARE_ACCESS_BOTH: | 3708 | case NFS4_SHARE_ACCESS_BOTH: |
| 3665 | break; | 3709 | break; |
| 3666 | default: | 3710 | default: |
| 3667 | BUG(); | 3711 | WARN_ON_ONCE(1); |
| 3668 | } | 3712 | } |
| 3669 | } | 3713 | } |
| 3670 | 3714 | ||
| @@ -3685,6 +3729,7 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp, | |||
| 3685 | { | 3729 | { |
| 3686 | __be32 status; | 3730 | __be32 status; |
| 3687 | struct nfs4_ol_stateid *stp; | 3731 | struct nfs4_ol_stateid *stp; |
| 3732 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | ||
| 3688 | 3733 | ||
| 3689 | dprintk("NFSD: nfsd4_open_downgrade on file %.*s\n", | 3734 | dprintk("NFSD: nfsd4_open_downgrade on file %.*s\n", |
| 3690 | (int)cstate->current_fh.fh_dentry->d_name.len, | 3735 | (int)cstate->current_fh.fh_dentry->d_name.len, |
| @@ -3697,7 +3742,7 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp, | |||
| 3697 | 3742 | ||
| 3698 | nfs4_lock_state(); | 3743 | nfs4_lock_state(); |
| 3699 | status = nfs4_preprocess_confirmed_seqid_op(cstate, od->od_seqid, | 3744 | status = nfs4_preprocess_confirmed_seqid_op(cstate, od->od_seqid, |
| 3700 | &od->od_stateid, &stp); | 3745 | &od->od_stateid, &stp, nn); |
| 3701 | if (status) | 3746 | if (status) |
| 3702 | goto out; | 3747 | goto out; |
| 3703 | status = nfserr_inval; | 3748 | status = nfserr_inval; |
| @@ -3760,6 +3805,8 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
| 3760 | __be32 status; | 3805 | __be32 status; |
| 3761 | struct nfs4_openowner *oo; | 3806 | struct nfs4_openowner *oo; |
| 3762 | struct nfs4_ol_stateid *stp; | 3807 | struct nfs4_ol_stateid *stp; |
| 3808 | struct net *net = SVC_NET(rqstp); | ||
| 3809 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
| 3763 | 3810 | ||
| 3764 | dprintk("NFSD: nfsd4_close on file %.*s\n", | 3811 | dprintk("NFSD: nfsd4_close on file %.*s\n", |
| 3765 | (int)cstate->current_fh.fh_dentry->d_name.len, | 3812 | (int)cstate->current_fh.fh_dentry->d_name.len, |
| @@ -3769,7 +3816,7 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
| 3769 | status = nfs4_preprocess_seqid_op(cstate, close->cl_seqid, | 3816 | status = nfs4_preprocess_seqid_op(cstate, close->cl_seqid, |
| 3770 | &close->cl_stateid, | 3817 | &close->cl_stateid, |
| 3771 | NFS4_OPEN_STID|NFS4_CLOSED_STID, | 3818 | NFS4_OPEN_STID|NFS4_CLOSED_STID, |
| 3772 | &stp); | 3819 | &stp, nn); |
| 3773 | if (status) | 3820 | if (status) |
| 3774 | goto out; | 3821 | goto out; |
| 3775 | oo = openowner(stp->st_stateowner); | 3822 | oo = openowner(stp->st_stateowner); |
| @@ -3791,7 +3838,7 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
| 3791 | * little while to handle CLOSE replay. | 3838 | * little while to handle CLOSE replay. |
| 3792 | */ | 3839 | */ |
| 3793 | if (list_empty(&oo->oo_owner.so_stateids)) | 3840 | if (list_empty(&oo->oo_owner.so_stateids)) |
| 3794 | move_to_close_lru(oo); | 3841 | move_to_close_lru(oo, SVC_NET(rqstp)); |
| 3795 | } | 3842 | } |
| 3796 | } | 3843 | } |
| 3797 | out: | 3844 | out: |
| @@ -3807,15 +3854,15 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
| 3807 | struct nfs4_delegation *dp; | 3854 | struct nfs4_delegation *dp; |
| 3808 | stateid_t *stateid = &dr->dr_stateid; | 3855 | stateid_t *stateid = &dr->dr_stateid; |
| 3809 | struct nfs4_stid *s; | 3856 | struct nfs4_stid *s; |
| 3810 | struct inode *inode; | ||
| 3811 | __be32 status; | 3857 | __be32 status; |
| 3858 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | ||
| 3812 | 3859 | ||
| 3813 | if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) | 3860 | if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) |
| 3814 | return status; | 3861 | return status; |
| 3815 | inode = cstate->current_fh.fh_dentry->d_inode; | ||
| 3816 | 3862 | ||
| 3817 | nfs4_lock_state(); | 3863 | nfs4_lock_state(); |
| 3818 | status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID, &s, cstate->minorversion); | 3864 | status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID, &s, |
| 3865 | cstate->minorversion, nn); | ||
| 3819 | if (status) | 3866 | if (status) |
| 3820 | goto out; | 3867 | goto out; |
| 3821 | dp = delegstateid(s); | 3868 | dp = delegstateid(s); |
| @@ -3833,8 +3880,6 @@ out: | |||
| 3833 | 3880 | ||
| 3834 | #define LOFF_OVERFLOW(start, len) ((u64)(len) > ~(u64)(start)) | 3881 | #define LOFF_OVERFLOW(start, len) ((u64)(len) > ~(u64)(start)) |
| 3835 | 3882 | ||
| 3836 | #define LOCKOWNER_INO_HASH_BITS 8 | ||
| 3837 | #define LOCKOWNER_INO_HASH_SIZE (1 << LOCKOWNER_INO_HASH_BITS) | ||
| 3838 | #define LOCKOWNER_INO_HASH_MASK (LOCKOWNER_INO_HASH_SIZE - 1) | 3883 | #define LOCKOWNER_INO_HASH_MASK (LOCKOWNER_INO_HASH_SIZE - 1) |
| 3839 | 3884 | ||
| 3840 | static inline u64 | 3885 | static inline u64 |
| @@ -3852,7 +3897,7 @@ last_byte_offset(u64 start, u64 len) | |||
| 3852 | { | 3897 | { |
| 3853 | u64 end; | 3898 | u64 end; |
| 3854 | 3899 | ||
| 3855 | BUG_ON(!len); | 3900 | WARN_ON_ONCE(!len); |
| 3856 | end = start + len; | 3901 | end = start + len; |
| 3857 | return end > start ? end - 1: NFS4_MAX_UINT64; | 3902 | return end > start ? end - 1: NFS4_MAX_UINT64; |
| 3858 | } | 3903 | } |
| @@ -3864,8 +3909,6 @@ static unsigned int lockowner_ino_hashval(struct inode *inode, u32 cl_id, struct | |||
| 3864 | & LOCKOWNER_INO_HASH_MASK; | 3909 | & LOCKOWNER_INO_HASH_MASK; |
| 3865 | } | 3910 | } |
| 3866 | 3911 | ||
| 3867 | static struct list_head lockowner_ino_hashtbl[LOCKOWNER_INO_HASH_SIZE]; | ||
| 3868 | |||
| 3869 | /* | 3912 | /* |
| 3870 | * TODO: Linux file offsets are _signed_ 64-bit quantities, which means that | 3913 | * TODO: Linux file offsets are _signed_ 64-bit quantities, which means that |
| 3871 | * we can't properly handle lock requests that go beyond the (2^63 - 1)-th | 3914 | * we can't properly handle lock requests that go beyond the (2^63 - 1)-th |
| @@ -3931,12 +3974,12 @@ static bool same_lockowner_ino(struct nfs4_lockowner *lo, struct inode *inode, c | |||
| 3931 | 3974 | ||
| 3932 | static struct nfs4_lockowner * | 3975 | static struct nfs4_lockowner * |
| 3933 | find_lockowner_str(struct inode *inode, clientid_t *clid, | 3976 | find_lockowner_str(struct inode *inode, clientid_t *clid, |
| 3934 | struct xdr_netobj *owner) | 3977 | struct xdr_netobj *owner, struct nfsd_net *nn) |
| 3935 | { | 3978 | { |
| 3936 | unsigned int hashval = lockowner_ino_hashval(inode, clid->cl_id, owner); | 3979 | unsigned int hashval = lockowner_ino_hashval(inode, clid->cl_id, owner); |
| 3937 | struct nfs4_lockowner *lo; | 3980 | struct nfs4_lockowner *lo; |
| 3938 | 3981 | ||
| 3939 | list_for_each_entry(lo, &lockowner_ino_hashtbl[hashval], lo_owner_ino_hash) { | 3982 | list_for_each_entry(lo, &nn->lockowner_ino_hashtbl[hashval], lo_owner_ino_hash) { |
| 3940 | if (same_lockowner_ino(lo, inode, clid, owner)) | 3983 | if (same_lockowner_ino(lo, inode, clid, owner)) |
| 3941 | return lo; | 3984 | return lo; |
| 3942 | } | 3985 | } |
| @@ -3948,9 +3991,10 @@ static void hash_lockowner(struct nfs4_lockowner *lo, unsigned int strhashval, s | |||
| 3948 | struct inode *inode = open_stp->st_file->fi_inode; | 3991 | struct inode *inode = open_stp->st_file->fi_inode; |
| 3949 | unsigned int inohash = lockowner_ino_hashval(inode, | 3992 | unsigned int inohash = lockowner_ino_hashval(inode, |
| 3950 | clp->cl_clientid.cl_id, &lo->lo_owner.so_owner); | 3993 | clp->cl_clientid.cl_id, &lo->lo_owner.so_owner); |
| 3994 | struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); | ||
| 3951 | 3995 | ||
| 3952 | list_add(&lo->lo_owner.so_strhash, &ownerstr_hashtbl[strhashval]); | 3996 | list_add(&lo->lo_owner.so_strhash, &nn->ownerstr_hashtbl[strhashval]); |
| 3953 | list_add(&lo->lo_owner_ino_hash, &lockowner_ino_hashtbl[inohash]); | 3997 | list_add(&lo->lo_owner_ino_hash, &nn->lockowner_ino_hashtbl[inohash]); |
| 3954 | list_add(&lo->lo_perstateid, &open_stp->st_lockowners); | 3998 | list_add(&lo->lo_perstateid, &open_stp->st_lockowners); |
| 3955 | } | 3999 | } |
| 3956 | 4000 | ||
| @@ -4024,8 +4068,10 @@ static __be32 lookup_or_create_lock_state(struct nfsd4_compound_state *cstate, s | |||
| 4024 | struct nfs4_client *cl = oo->oo_owner.so_client; | 4068 | struct nfs4_client *cl = oo->oo_owner.so_client; |
| 4025 | struct nfs4_lockowner *lo; | 4069 | struct nfs4_lockowner *lo; |
| 4026 | unsigned int strhashval; | 4070 | unsigned int strhashval; |
| 4071 | struct nfsd_net *nn = net_generic(cl->net, nfsd_net_id); | ||
| 4027 | 4072 | ||
| 4028 | lo = find_lockowner_str(fi->fi_inode, &cl->cl_clientid, &lock->v.new.owner); | 4073 | lo = find_lockowner_str(fi->fi_inode, &cl->cl_clientid, |
| 4074 | &lock->v.new.owner, nn); | ||
| 4029 | if (lo) { | 4075 | if (lo) { |
| 4030 | if (!cstate->minorversion) | 4076 | if (!cstate->minorversion) |
| 4031 | return nfserr_bad_seqid; | 4077 | return nfserr_bad_seqid; |
| @@ -4065,7 +4111,8 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
| 4065 | bool new_state = false; | 4111 | bool new_state = false; |
| 4066 | int lkflg; | 4112 | int lkflg; |
| 4067 | int err; | 4113 | int err; |
| 4068 | struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); | 4114 | struct net *net = SVC_NET(rqstp); |
| 4115 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
| 4069 | 4116 | ||
| 4070 | dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n", | 4117 | dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n", |
| 4071 | (long long) lock->lk_offset, | 4118 | (long long) lock->lk_offset, |
| @@ -4099,7 +4146,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
| 4099 | status = nfs4_preprocess_confirmed_seqid_op(cstate, | 4146 | status = nfs4_preprocess_confirmed_seqid_op(cstate, |
| 4100 | lock->lk_new_open_seqid, | 4147 | lock->lk_new_open_seqid, |
| 4101 | &lock->lk_new_open_stateid, | 4148 | &lock->lk_new_open_stateid, |
| 4102 | &open_stp); | 4149 | &open_stp, nn); |
| 4103 | if (status) | 4150 | if (status) |
| 4104 | goto out; | 4151 | goto out; |
| 4105 | open_sop = openowner(open_stp->st_stateowner); | 4152 | open_sop = openowner(open_stp->st_stateowner); |
| @@ -4113,7 +4160,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
| 4113 | status = nfs4_preprocess_seqid_op(cstate, | 4160 | status = nfs4_preprocess_seqid_op(cstate, |
| 4114 | lock->lk_old_lock_seqid, | 4161 | lock->lk_old_lock_seqid, |
| 4115 | &lock->lk_old_lock_stateid, | 4162 | &lock->lk_old_lock_stateid, |
| 4116 | NFS4_LOCK_STID, &lock_stp); | 4163 | NFS4_LOCK_STID, &lock_stp, nn); |
| 4117 | if (status) | 4164 | if (status) |
| 4118 | goto out; | 4165 | goto out; |
| 4119 | lock_sop = lockowner(lock_stp->st_stateowner); | 4166 | lock_sop = lockowner(lock_stp->st_stateowner); |
| @@ -4124,10 +4171,10 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
| 4124 | goto out; | 4171 | goto out; |
| 4125 | 4172 | ||
| 4126 | status = nfserr_grace; | 4173 | status = nfserr_grace; |
| 4127 | if (locks_in_grace(SVC_NET(rqstp)) && !lock->lk_reclaim) | 4174 | if (locks_in_grace(net) && !lock->lk_reclaim) |
| 4128 | goto out; | 4175 | goto out; |
| 4129 | status = nfserr_no_grace; | 4176 | status = nfserr_no_grace; |
| 4130 | if (!locks_in_grace(SVC_NET(rqstp)) && lock->lk_reclaim) | 4177 | if (!locks_in_grace(net) && lock->lk_reclaim) |
| 4131 | goto out; | 4178 | goto out; |
| 4132 | 4179 | ||
| 4133 | file_lock = locks_alloc_lock(); | 4180 | file_lock = locks_alloc_lock(); |
| @@ -4238,7 +4285,7 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
| 4238 | struct file_lock *file_lock = NULL; | 4285 | struct file_lock *file_lock = NULL; |
| 4239 | struct nfs4_lockowner *lo; | 4286 | struct nfs4_lockowner *lo; |
| 4240 | __be32 status; | 4287 | __be32 status; |
| 4241 | struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); | 4288 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); |
| 4242 | 4289 | ||
| 4243 | if (locks_in_grace(SVC_NET(rqstp))) | 4290 | if (locks_in_grace(SVC_NET(rqstp))) |
| 4244 | return nfserr_grace; | 4291 | return nfserr_grace; |
| @@ -4248,9 +4295,11 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
| 4248 | 4295 | ||
| 4249 | nfs4_lock_state(); | 4296 | nfs4_lock_state(); |
| 4250 | 4297 | ||
| 4251 | status = nfserr_stale_clientid; | 4298 | if (!nfsd4_has_session(cstate)) { |
| 4252 | if (!nfsd4_has_session(cstate) && STALE_CLIENTID(&lockt->lt_clientid, nn)) | 4299 | status = lookup_clientid(&lockt->lt_clientid, false, nn, NULL); |
| 4253 | goto out; | 4300 | if (status) |
| 4301 | goto out; | ||
| 4302 | } | ||
| 4254 | 4303 | ||
| 4255 | if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) | 4304 | if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) |
| 4256 | goto out; | 4305 | goto out; |
| @@ -4278,7 +4327,7 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
| 4278 | goto out; | 4327 | goto out; |
| 4279 | } | 4328 | } |
| 4280 | 4329 | ||
| 4281 | lo = find_lockowner_str(inode, &lockt->lt_clientid, &lockt->lt_owner); | 4330 | lo = find_lockowner_str(inode, &lockt->lt_clientid, &lockt->lt_owner, nn); |
| 4282 | if (lo) | 4331 | if (lo) |
| 4283 | file_lock->fl_owner = (fl_owner_t)lo; | 4332 | file_lock->fl_owner = (fl_owner_t)lo; |
| 4284 | file_lock->fl_pid = current->tgid; | 4333 | file_lock->fl_pid = current->tgid; |
| @@ -4313,7 +4362,8 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
| 4313 | struct file_lock *file_lock = NULL; | 4362 | struct file_lock *file_lock = NULL; |
| 4314 | __be32 status; | 4363 | __be32 status; |
| 4315 | int err; | 4364 | int err; |
| 4316 | 4365 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | |
| 4366 | |||
| 4317 | dprintk("NFSD: nfsd4_locku: start=%Ld length=%Ld\n", | 4367 | dprintk("NFSD: nfsd4_locku: start=%Ld length=%Ld\n", |
| 4318 | (long long) locku->lu_offset, | 4368 | (long long) locku->lu_offset, |
| 4319 | (long long) locku->lu_length); | 4369 | (long long) locku->lu_length); |
| @@ -4324,7 +4374,8 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
| 4324 | nfs4_lock_state(); | 4374 | nfs4_lock_state(); |
| 4325 | 4375 | ||
| 4326 | status = nfs4_preprocess_seqid_op(cstate, locku->lu_seqid, | 4376 | status = nfs4_preprocess_seqid_op(cstate, locku->lu_seqid, |
| 4327 | &locku->lu_stateid, NFS4_LOCK_STID, &stp); | 4377 | &locku->lu_stateid, NFS4_LOCK_STID, |
| 4378 | &stp, nn); | ||
| 4328 | if (status) | 4379 | if (status) |
| 4329 | goto out; | 4380 | goto out; |
| 4330 | filp = find_any_file(stp->st_file); | 4381 | filp = find_any_file(stp->st_file); |
| @@ -4414,23 +4465,21 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, | |||
| 4414 | struct list_head matches; | 4465 | struct list_head matches; |
| 4415 | unsigned int hashval = ownerstr_hashval(clid->cl_id, owner); | 4466 | unsigned int hashval = ownerstr_hashval(clid->cl_id, owner); |
| 4416 | __be32 status; | 4467 | __be32 status; |
| 4417 | struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); | 4468 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); |
| 4418 | 4469 | ||
| 4419 | dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n", | 4470 | dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n", |
| 4420 | clid->cl_boot, clid->cl_id); | 4471 | clid->cl_boot, clid->cl_id); |
| 4421 | 4472 | ||
| 4422 | /* XXX check for lease expiration */ | ||
| 4423 | |||
| 4424 | status = nfserr_stale_clientid; | ||
| 4425 | if (STALE_CLIENTID(clid, nn)) | ||
| 4426 | return status; | ||
| 4427 | |||
| 4428 | nfs4_lock_state(); | 4473 | nfs4_lock_state(); |
| 4429 | 4474 | ||
| 4475 | status = lookup_clientid(clid, cstate->minorversion, nn, NULL); | ||
| 4476 | if (status) | ||
| 4477 | goto out; | ||
| 4478 | |||
| 4430 | status = nfserr_locks_held; | 4479 | status = nfserr_locks_held; |
| 4431 | INIT_LIST_HEAD(&matches); | 4480 | INIT_LIST_HEAD(&matches); |
| 4432 | 4481 | ||
| 4433 | list_for_each_entry(sop, &ownerstr_hashtbl[hashval], so_strhash) { | 4482 | list_for_each_entry(sop, &nn->ownerstr_hashtbl[hashval], so_strhash) { |
| 4434 | if (sop->so_is_open_owner) | 4483 | if (sop->so_is_open_owner) |
| 4435 | continue; | 4484 | continue; |
| 4436 | if (!same_owner_str(sop, owner, clid)) | 4485 | if (!same_owner_str(sop, owner, clid)) |
| @@ -4466,73 +4515,74 @@ alloc_reclaim(void) | |||
| 4466 | return kmalloc(sizeof(struct nfs4_client_reclaim), GFP_KERNEL); | 4515 | return kmalloc(sizeof(struct nfs4_client_reclaim), GFP_KERNEL); |
| 4467 | } | 4516 | } |
| 4468 | 4517 | ||
| 4469 | int | 4518 | bool |
| 4470 | nfs4_has_reclaimed_state(const char *name, bool use_exchange_id) | 4519 | nfs4_has_reclaimed_state(const char *name, struct nfsd_net *nn) |
| 4471 | { | 4520 | { |
| 4472 | unsigned int strhashval = clientstr_hashval(name); | 4521 | struct nfs4_client_reclaim *crp; |
| 4473 | struct nfs4_client *clp; | ||
| 4474 | 4522 | ||
| 4475 | clp = find_confirmed_client_by_str(name, strhashval); | 4523 | crp = nfsd4_find_reclaim_client(name, nn); |
| 4476 | if (!clp) | 4524 | return (crp && crp->cr_clp); |
| 4477 | return 0; | ||
| 4478 | return test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags); | ||
| 4479 | } | 4525 | } |
| 4480 | 4526 | ||
| 4481 | /* | 4527 | /* |
| 4482 | * failure => all reset bets are off, nfserr_no_grace... | 4528 | * failure => all reset bets are off, nfserr_no_grace... |
| 4483 | */ | 4529 | */ |
| 4484 | int | 4530 | struct nfs4_client_reclaim * |
| 4485 | nfs4_client_to_reclaim(const char *name) | 4531 | nfs4_client_to_reclaim(const char *name, struct nfsd_net *nn) |
| 4486 | { | 4532 | { |
| 4487 | unsigned int strhashval; | 4533 | unsigned int strhashval; |
| 4488 | struct nfs4_client_reclaim *crp = NULL; | 4534 | struct nfs4_client_reclaim *crp; |
| 4489 | 4535 | ||
| 4490 | dprintk("NFSD nfs4_client_to_reclaim NAME: %.*s\n", HEXDIR_LEN, name); | 4536 | dprintk("NFSD nfs4_client_to_reclaim NAME: %.*s\n", HEXDIR_LEN, name); |
| 4491 | crp = alloc_reclaim(); | 4537 | crp = alloc_reclaim(); |
| 4492 | if (!crp) | 4538 | if (crp) { |
| 4493 | return 0; | 4539 | strhashval = clientstr_hashval(name); |
| 4494 | strhashval = clientstr_hashval(name); | 4540 | INIT_LIST_HEAD(&crp->cr_strhash); |
| 4495 | INIT_LIST_HEAD(&crp->cr_strhash); | 4541 | list_add(&crp->cr_strhash, &nn->reclaim_str_hashtbl[strhashval]); |
| 4496 | list_add(&crp->cr_strhash, &reclaim_str_hashtbl[strhashval]); | 4542 | memcpy(crp->cr_recdir, name, HEXDIR_LEN); |
| 4497 | memcpy(crp->cr_recdir, name, HEXDIR_LEN); | 4543 | crp->cr_clp = NULL; |
| 4498 | reclaim_str_hashtbl_size++; | 4544 | nn->reclaim_str_hashtbl_size++; |
| 4499 | return 1; | 4545 | } |
| 4546 | return crp; | ||
| 4547 | } | ||
| 4548 | |||
| 4549 | void | ||
| 4550 | nfs4_remove_reclaim_record(struct nfs4_client_reclaim *crp, struct nfsd_net *nn) | ||
| 4551 | { | ||
| 4552 | list_del(&crp->cr_strhash); | ||
| 4553 | kfree(crp); | ||
| 4554 | nn->reclaim_str_hashtbl_size--; | ||
| 4500 | } | 4555 | } |
| 4501 | 4556 | ||
| 4502 | void | 4557 | void |
| 4503 | nfs4_release_reclaim(void) | 4558 | nfs4_release_reclaim(struct nfsd_net *nn) |
| 4504 | { | 4559 | { |
| 4505 | struct nfs4_client_reclaim *crp = NULL; | 4560 | struct nfs4_client_reclaim *crp = NULL; |
| 4506 | int i; | 4561 | int i; |
| 4507 | 4562 | ||
| 4508 | for (i = 0; i < CLIENT_HASH_SIZE; i++) { | 4563 | for (i = 0; i < CLIENT_HASH_SIZE; i++) { |
| 4509 | while (!list_empty(&reclaim_str_hashtbl[i])) { | 4564 | while (!list_empty(&nn->reclaim_str_hashtbl[i])) { |
| 4510 | crp = list_entry(reclaim_str_hashtbl[i].next, | 4565 | crp = list_entry(nn->reclaim_str_hashtbl[i].next, |
| 4511 | struct nfs4_client_reclaim, cr_strhash); | 4566 | struct nfs4_client_reclaim, cr_strhash); |
| 4512 | list_del(&crp->cr_strhash); | 4567 | nfs4_remove_reclaim_record(crp, nn); |
| 4513 | kfree(crp); | ||
| 4514 | reclaim_str_hashtbl_size--; | ||
| 4515 | } | 4568 | } |
| 4516 | } | 4569 | } |
| 4517 | BUG_ON(reclaim_str_hashtbl_size); | 4570 | WARN_ON_ONCE(nn->reclaim_str_hashtbl_size); |
| 4518 | } | 4571 | } |
| 4519 | 4572 | ||
| 4520 | /* | 4573 | /* |
| 4521 | * called from OPEN, CLAIM_PREVIOUS with a new clientid. */ | 4574 | * called from OPEN, CLAIM_PREVIOUS with a new clientid. */ |
| 4522 | struct nfs4_client_reclaim * | 4575 | struct nfs4_client_reclaim * |
| 4523 | nfsd4_find_reclaim_client(struct nfs4_client *clp) | 4576 | nfsd4_find_reclaim_client(const char *recdir, struct nfsd_net *nn) |
| 4524 | { | 4577 | { |
| 4525 | unsigned int strhashval; | 4578 | unsigned int strhashval; |
| 4526 | struct nfs4_client_reclaim *crp = NULL; | 4579 | struct nfs4_client_reclaim *crp = NULL; |
| 4527 | 4580 | ||
| 4528 | dprintk("NFSD: nfs4_find_reclaim_client for %.*s with recdir %s\n", | 4581 | dprintk("NFSD: nfs4_find_reclaim_client for recdir %s\n", recdir); |
| 4529 | clp->cl_name.len, clp->cl_name.data, | ||
| 4530 | clp->cl_recdir); | ||
| 4531 | 4582 | ||
| 4532 | /* find clp->cl_name in reclaim_str_hashtbl */ | 4583 | strhashval = clientstr_hashval(recdir); |
| 4533 | strhashval = clientstr_hashval(clp->cl_recdir); | 4584 | list_for_each_entry(crp, &nn->reclaim_str_hashtbl[strhashval], cr_strhash) { |
| 4534 | list_for_each_entry(crp, &reclaim_str_hashtbl[strhashval], cr_strhash) { | 4585 | if (same_name(crp->cr_recdir, recdir)) { |
| 4535 | if (same_name(crp->cr_recdir, clp->cl_recdir)) { | ||
| 4536 | return crp; | 4586 | return crp; |
| 4537 | } | 4587 | } |
| 4538 | } | 4588 | } |
| @@ -4543,12 +4593,12 @@ nfsd4_find_reclaim_client(struct nfs4_client *clp) | |||
| 4543 | * Called from OPEN. Look for clientid in reclaim list. | 4593 | * Called from OPEN. Look for clientid in reclaim list. |
| 4544 | */ | 4594 | */ |
| 4545 | __be32 | 4595 | __be32 |
| 4546 | nfs4_check_open_reclaim(clientid_t *clid, bool sessions) | 4596 | nfs4_check_open_reclaim(clientid_t *clid, bool sessions, struct nfsd_net *nn) |
| 4547 | { | 4597 | { |
| 4548 | struct nfs4_client *clp; | 4598 | struct nfs4_client *clp; |
| 4549 | 4599 | ||
| 4550 | /* find clientid in conf_id_hashtbl */ | 4600 | /* find clientid in conf_id_hashtbl */ |
| 4551 | clp = find_confirmed_client(clid, sessions); | 4601 | clp = find_confirmed_client(clid, sessions, nn); |
| 4552 | if (clp == NULL) | 4602 | if (clp == NULL) |
| 4553 | return nfserr_reclaim_bad; | 4603 | return nfserr_reclaim_bad; |
| 4554 | 4604 | ||
| @@ -4557,124 +4607,177 @@ nfs4_check_open_reclaim(clientid_t *clid, bool sessions) | |||
| 4557 | 4607 | ||
| 4558 | #ifdef CONFIG_NFSD_FAULT_INJECTION | 4608 | #ifdef CONFIG_NFSD_FAULT_INJECTION |
| 4559 | 4609 | ||
| 4560 | void nfsd_forget_clients(u64 num) | 4610 | u64 nfsd_forget_client(struct nfs4_client *clp, u64 max) |
| 4561 | { | 4611 | { |
| 4562 | struct nfs4_client *clp, *next; | 4612 | expire_client(clp); |
| 4563 | int count = 0; | 4613 | return 1; |
| 4564 | |||
| 4565 | nfs4_lock_state(); | ||
| 4566 | list_for_each_entry_safe(clp, next, &client_lru, cl_lru) { | ||
| 4567 | expire_client(clp); | ||
| 4568 | if (++count == num) | ||
| 4569 | break; | ||
| 4570 | } | ||
| 4571 | nfs4_unlock_state(); | ||
| 4572 | |||
| 4573 | printk(KERN_INFO "NFSD: Forgot %d clients", count); | ||
| 4574 | } | 4614 | } |
| 4575 | 4615 | ||
| 4576 | static void release_lockowner_sop(struct nfs4_stateowner *sop) | 4616 | u64 nfsd_print_client(struct nfs4_client *clp, u64 num) |
| 4577 | { | 4617 | { |
| 4578 | release_lockowner(lockowner(sop)); | 4618 | char buf[INET6_ADDRSTRLEN]; |
| 4619 | rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf)); | ||
| 4620 | printk(KERN_INFO "NFS Client: %s\n", buf); | ||
| 4621 | return 1; | ||
| 4579 | } | 4622 | } |
| 4580 | 4623 | ||
| 4581 | static void release_openowner_sop(struct nfs4_stateowner *sop) | 4624 | static void nfsd_print_count(struct nfs4_client *clp, unsigned int count, |
| 4625 | const char *type) | ||
| 4582 | { | 4626 | { |
| 4583 | release_openowner(openowner(sop)); | 4627 | char buf[INET6_ADDRSTRLEN]; |
| 4628 | rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf)); | ||
| 4629 | printk(KERN_INFO "NFS Client: %s has %u %s\n", buf, count, type); | ||
| 4584 | } | 4630 | } |
| 4585 | 4631 | ||
| 4586 | static int nfsd_release_n_owners(u64 num, bool is_open_owner, | 4632 | static u64 nfsd_foreach_client_lock(struct nfs4_client *clp, u64 max, void (*func)(struct nfs4_lockowner *)) |
| 4587 | void (*release_sop)(struct nfs4_stateowner *)) | ||
| 4588 | { | 4633 | { |
| 4589 | int i, count = 0; | 4634 | struct nfs4_openowner *oop; |
| 4590 | struct nfs4_stateowner *sop, *next; | 4635 | struct nfs4_lockowner *lop, *lo_next; |
| 4636 | struct nfs4_ol_stateid *stp, *st_next; | ||
| 4637 | u64 count = 0; | ||
| 4591 | 4638 | ||
| 4592 | for (i = 0; i < OWNER_HASH_SIZE; i++) { | 4639 | list_for_each_entry(oop, &clp->cl_openowners, oo_perclient) { |
| 4593 | list_for_each_entry_safe(sop, next, &ownerstr_hashtbl[i], so_strhash) { | 4640 | list_for_each_entry_safe(stp, st_next, &oop->oo_owner.so_stateids, st_perstateowner) { |
| 4594 | if (sop->so_is_open_owner != is_open_owner) | 4641 | list_for_each_entry_safe(lop, lo_next, &stp->st_lockowners, lo_perstateid) { |
| 4595 | continue; | 4642 | if (func) |
| 4596 | release_sop(sop); | 4643 | func(lop); |
| 4597 | if (++count == num) | 4644 | if (++count == max) |
| 4598 | return count; | 4645 | return count; |
| 4646 | } | ||
| 4599 | } | 4647 | } |
| 4600 | } | 4648 | } |
| 4649 | |||
| 4601 | return count; | 4650 | return count; |
| 4602 | } | 4651 | } |
| 4603 | 4652 | ||
| 4604 | void nfsd_forget_locks(u64 num) | 4653 | u64 nfsd_forget_client_locks(struct nfs4_client *clp, u64 max) |
| 4605 | { | 4654 | { |
| 4606 | int count; | 4655 | return nfsd_foreach_client_lock(clp, max, release_lockowner); |
| 4607 | 4656 | } | |
| 4608 | nfs4_lock_state(); | ||
| 4609 | count = nfsd_release_n_owners(num, false, release_lockowner_sop); | ||
| 4610 | nfs4_unlock_state(); | ||
| 4611 | 4657 | ||
| 4612 | printk(KERN_INFO "NFSD: Forgot %d locks", count); | 4658 | u64 nfsd_print_client_locks(struct nfs4_client *clp, u64 max) |
| 4659 | { | ||
| 4660 | u64 count = nfsd_foreach_client_lock(clp, max, NULL); | ||
| 4661 | nfsd_print_count(clp, count, "locked files"); | ||
| 4662 | return count; | ||
| 4613 | } | 4663 | } |
| 4614 | 4664 | ||
| 4615 | void nfsd_forget_openowners(u64 num) | 4665 | static u64 nfsd_foreach_client_open(struct nfs4_client *clp, u64 max, void (*func)(struct nfs4_openowner *)) |
| 4616 | { | 4666 | { |
| 4617 | int count; | 4667 | struct nfs4_openowner *oop, *next; |
| 4668 | u64 count = 0; | ||
| 4618 | 4669 | ||
| 4619 | nfs4_lock_state(); | 4670 | list_for_each_entry_safe(oop, next, &clp->cl_openowners, oo_perclient) { |
| 4620 | count = nfsd_release_n_owners(num, true, release_openowner_sop); | 4671 | if (func) |
| 4621 | nfs4_unlock_state(); | 4672 | func(oop); |
| 4673 | if (++count == max) | ||
| 4674 | break; | ||
| 4675 | } | ||
| 4622 | 4676 | ||
| 4623 | printk(KERN_INFO "NFSD: Forgot %d open owners", count); | 4677 | return count; |
| 4624 | } | 4678 | } |
| 4625 | 4679 | ||
| 4626 | static int nfsd_process_n_delegations(u64 num, struct list_head *list) | 4680 | u64 nfsd_forget_client_openowners(struct nfs4_client *clp, u64 max) |
| 4627 | { | 4681 | { |
| 4628 | int i, count = 0; | 4682 | return nfsd_foreach_client_open(clp, max, release_openowner); |
| 4629 | struct nfs4_file *fp, *fnext; | 4683 | } |
| 4630 | struct nfs4_delegation *dp, *dnext; | ||
| 4631 | 4684 | ||
| 4632 | for (i = 0; i < FILE_HASH_SIZE; i++) { | 4685 | u64 nfsd_print_client_openowners(struct nfs4_client *clp, u64 max) |
| 4633 | list_for_each_entry_safe(fp, fnext, &file_hashtbl[i], fi_hash) { | 4686 | { |
| 4634 | list_for_each_entry_safe(dp, dnext, &fp->fi_delegations, dl_perfile) { | 4687 | u64 count = nfsd_foreach_client_open(clp, max, NULL); |
| 4635 | list_move(&dp->dl_recall_lru, list); | 4688 | nfsd_print_count(clp, count, "open files"); |
| 4636 | if (++count == num) | 4689 | return count; |
| 4637 | return count; | 4690 | } |
| 4638 | } | 4691 | |
| 4639 | } | 4692 | static u64 nfsd_find_all_delegations(struct nfs4_client *clp, u64 max, |
| 4640 | } | 4693 | struct list_head *victims) |
| 4694 | { | ||
| 4695 | struct nfs4_delegation *dp, *next; | ||
| 4696 | u64 count = 0; | ||
| 4641 | 4697 | ||
| 4698 | list_for_each_entry_safe(dp, next, &clp->cl_delegations, dl_perclnt) { | ||
| 4699 | if (victims) | ||
| 4700 | list_move(&dp->dl_recall_lru, victims); | ||
| 4701 | if (++count == max) | ||
| 4702 | break; | ||
| 4703 | } | ||
| 4642 | return count; | 4704 | return count; |
| 4643 | } | 4705 | } |
| 4644 | 4706 | ||
| 4645 | void nfsd_forget_delegations(u64 num) | 4707 | u64 nfsd_forget_client_delegations(struct nfs4_client *clp, u64 max) |
| 4646 | { | 4708 | { |
| 4647 | unsigned int count; | 4709 | struct nfs4_delegation *dp, *next; |
| 4648 | LIST_HEAD(victims); | 4710 | LIST_HEAD(victims); |
| 4649 | struct nfs4_delegation *dp, *dnext; | 4711 | u64 count; |
| 4650 | 4712 | ||
| 4651 | spin_lock(&recall_lock); | 4713 | spin_lock(&recall_lock); |
| 4652 | count = nfsd_process_n_delegations(num, &victims); | 4714 | count = nfsd_find_all_delegations(clp, max, &victims); |
| 4653 | spin_unlock(&recall_lock); | 4715 | spin_unlock(&recall_lock); |
| 4654 | 4716 | ||
| 4655 | nfs4_lock_state(); | 4717 | list_for_each_entry_safe(dp, next, &victims, dl_recall_lru) |
| 4656 | list_for_each_entry_safe(dp, dnext, &victims, dl_recall_lru) | ||
| 4657 | unhash_delegation(dp); | 4718 | unhash_delegation(dp); |
| 4658 | nfs4_unlock_state(); | ||
| 4659 | 4719 | ||
| 4660 | printk(KERN_INFO "NFSD: Forgot %d delegations", count); | 4720 | return count; |
| 4661 | } | 4721 | } |
| 4662 | 4722 | ||
| 4663 | void nfsd_recall_delegations(u64 num) | 4723 | u64 nfsd_recall_client_delegations(struct nfs4_client *clp, u64 max) |
| 4664 | { | 4724 | { |
| 4665 | unsigned int count; | 4725 | struct nfs4_delegation *dp, *next; |
| 4666 | LIST_HEAD(victims); | 4726 | LIST_HEAD(victims); |
| 4667 | struct nfs4_delegation *dp, *dnext; | 4727 | u64 count; |
| 4668 | 4728 | ||
| 4669 | spin_lock(&recall_lock); | 4729 | spin_lock(&recall_lock); |
| 4670 | count = nfsd_process_n_delegations(num, &victims); | 4730 | count = nfsd_find_all_delegations(clp, max, &victims); |
| 4671 | list_for_each_entry_safe(dp, dnext, &victims, dl_recall_lru) { | 4731 | list_for_each_entry_safe(dp, next, &victims, dl_recall_lru) |
| 4672 | list_del(&dp->dl_recall_lru); | ||
| 4673 | nfsd_break_one_deleg(dp); | 4732 | nfsd_break_one_deleg(dp); |
| 4674 | } | ||
| 4675 | spin_unlock(&recall_lock); | 4733 | spin_unlock(&recall_lock); |
| 4676 | 4734 | ||
| 4677 | printk(KERN_INFO "NFSD: Recalled %d delegations", count); | 4735 | return count; |
| 4736 | } | ||
| 4737 | |||
| 4738 | u64 nfsd_print_client_delegations(struct nfs4_client *clp, u64 max) | ||
| 4739 | { | ||
| 4740 | u64 count = 0; | ||
| 4741 | |||
| 4742 | spin_lock(&recall_lock); | ||
| 4743 | count = nfsd_find_all_delegations(clp, max, NULL); | ||
| 4744 | spin_unlock(&recall_lock); | ||
| 4745 | |||
| 4746 | nfsd_print_count(clp, count, "delegations"); | ||
| 4747 | return count; | ||
| 4748 | } | ||
| 4749 | |||
| 4750 | u64 nfsd_for_n_state(u64 max, u64 (*func)(struct nfs4_client *, u64)) | ||
| 4751 | { | ||
| 4752 | struct nfs4_client *clp, *next; | ||
| 4753 | u64 count = 0; | ||
| 4754 | struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, nfsd_net_id); | ||
| 4755 | |||
| 4756 | if (!nfsd_netns_ready(nn)) | ||
| 4757 | return 0; | ||
| 4758 | |||
| 4759 | list_for_each_entry_safe(clp, next, &nn->client_lru, cl_lru) { | ||
| 4760 | count += func(clp, max - count); | ||
| 4761 | if ((max != 0) && (count >= max)) | ||
| 4762 | break; | ||
| 4763 | } | ||
| 4764 | |||
| 4765 | return count; | ||
| 4766 | } | ||
| 4767 | |||
| 4768 | struct nfs4_client *nfsd_find_client(struct sockaddr_storage *addr, size_t addr_size) | ||
| 4769 | { | ||
| 4770 | struct nfs4_client *clp; | ||
| 4771 | struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, nfsd_net_id); | ||
| 4772 | |||
| 4773 | if (!nfsd_netns_ready(nn)) | ||
| 4774 | return NULL; | ||
| 4775 | |||
| 4776 | list_for_each_entry(clp, &nn->client_lru, cl_lru) { | ||
| 4777 | if (memcmp(&clp->cl_addr, addr, addr_size) == 0) | ||
| 4778 | return clp; | ||
| 4779 | } | ||
| 4780 | return NULL; | ||
| 4678 | } | 4781 | } |
| 4679 | 4782 | ||
| 4680 | #endif /* CONFIG_NFSD_FAULT_INJECTION */ | 4783 | #endif /* CONFIG_NFSD_FAULT_INJECTION */ |
| @@ -4686,27 +4789,10 @@ nfs4_state_init(void) | |||
| 4686 | { | 4789 | { |
| 4687 | int i; | 4790 | int i; |
| 4688 | 4791 | ||
| 4689 | for (i = 0; i < CLIENT_HASH_SIZE; i++) { | ||
| 4690 | INIT_LIST_HEAD(&conf_id_hashtbl[i]); | ||
| 4691 | INIT_LIST_HEAD(&conf_str_hashtbl[i]); | ||
| 4692 | INIT_LIST_HEAD(&unconf_str_hashtbl[i]); | ||
| 4693 | INIT_LIST_HEAD(&unconf_id_hashtbl[i]); | ||
| 4694 | INIT_LIST_HEAD(&reclaim_str_hashtbl[i]); | ||
| 4695 | } | ||
| 4696 | for (i = 0; i < SESSION_HASH_SIZE; i++) | ||
| 4697 | INIT_LIST_HEAD(&sessionid_hashtbl[i]); | ||
| 4698 | for (i = 0; i < FILE_HASH_SIZE; i++) { | 4792 | for (i = 0; i < FILE_HASH_SIZE; i++) { |
| 4699 | INIT_LIST_HEAD(&file_hashtbl[i]); | 4793 | INIT_LIST_HEAD(&file_hashtbl[i]); |
| 4700 | } | 4794 | } |
| 4701 | for (i = 0; i < OWNER_HASH_SIZE; i++) { | ||
| 4702 | INIT_LIST_HEAD(&ownerstr_hashtbl[i]); | ||
| 4703 | } | ||
| 4704 | for (i = 0; i < LOCKOWNER_INO_HASH_SIZE; i++) | ||
| 4705 | INIT_LIST_HEAD(&lockowner_ino_hashtbl[i]); | ||
| 4706 | INIT_LIST_HEAD(&close_lru); | ||
| 4707 | INIT_LIST_HEAD(&client_lru); | ||
| 4708 | INIT_LIST_HEAD(&del_recall_lru); | 4795 | INIT_LIST_HEAD(&del_recall_lru); |
| 4709 | reclaim_str_hashtbl_size = 0; | ||
| 4710 | } | 4796 | } |
| 4711 | 4797 | ||
| 4712 | /* | 4798 | /* |
| @@ -4730,12 +4816,100 @@ set_max_delegations(void) | |||
| 4730 | max_delegations = nr_free_buffer_pages() >> (20 - 2 - PAGE_SHIFT); | 4816 | max_delegations = nr_free_buffer_pages() >> (20 - 2 - PAGE_SHIFT); |
| 4731 | } | 4817 | } |
| 4732 | 4818 | ||
| 4733 | /* initialization to perform when the nfsd service is started: */ | 4819 | static int nfs4_state_create_net(struct net *net) |
| 4820 | { | ||
| 4821 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
| 4822 | int i; | ||
| 4823 | |||
| 4824 | nn->conf_id_hashtbl = kmalloc(sizeof(struct list_head) * | ||
| 4825 | CLIENT_HASH_SIZE, GFP_KERNEL); | ||
| 4826 | if (!nn->conf_id_hashtbl) | ||
| 4827 | goto err; | ||
| 4828 | nn->unconf_id_hashtbl = kmalloc(sizeof(struct list_head) * | ||
| 4829 | CLIENT_HASH_SIZE, GFP_KERNEL); | ||
| 4830 | if (!nn->unconf_id_hashtbl) | ||
| 4831 | goto err_unconf_id; | ||
| 4832 | nn->ownerstr_hashtbl = kmalloc(sizeof(struct list_head) * | ||
| 4833 | OWNER_HASH_SIZE, GFP_KERNEL); | ||
| 4834 | if (!nn->ownerstr_hashtbl) | ||
| 4835 | goto err_ownerstr; | ||
| 4836 | nn->lockowner_ino_hashtbl = kmalloc(sizeof(struct list_head) * | ||
| 4837 | LOCKOWNER_INO_HASH_SIZE, GFP_KERNEL); | ||
| 4838 | if (!nn->lockowner_ino_hashtbl) | ||
| 4839 | goto err_lockowner_ino; | ||
| 4840 | nn->sessionid_hashtbl = kmalloc(sizeof(struct list_head) * | ||
| 4841 | SESSION_HASH_SIZE, GFP_KERNEL); | ||
| 4842 | if (!nn->sessionid_hashtbl) | ||
| 4843 | goto err_sessionid; | ||
| 4844 | |||
| 4845 | for (i = 0; i < CLIENT_HASH_SIZE; i++) { | ||
| 4846 | INIT_LIST_HEAD(&nn->conf_id_hashtbl[i]); | ||
| 4847 | INIT_LIST_HEAD(&nn->unconf_id_hashtbl[i]); | ||
| 4848 | } | ||
| 4849 | for (i = 0; i < OWNER_HASH_SIZE; i++) | ||
| 4850 | INIT_LIST_HEAD(&nn->ownerstr_hashtbl[i]); | ||
| 4851 | for (i = 0; i < LOCKOWNER_INO_HASH_SIZE; i++) | ||
| 4852 | INIT_LIST_HEAD(&nn->lockowner_ino_hashtbl[i]); | ||
| 4853 | for (i = 0; i < SESSION_HASH_SIZE; i++) | ||
| 4854 | INIT_LIST_HEAD(&nn->sessionid_hashtbl[i]); | ||
| 4855 | nn->conf_name_tree = RB_ROOT; | ||
| 4856 | nn->unconf_name_tree = RB_ROOT; | ||
| 4857 | INIT_LIST_HEAD(&nn->client_lru); | ||
| 4858 | INIT_LIST_HEAD(&nn->close_lru); | ||
| 4859 | spin_lock_init(&nn->client_lock); | ||
| 4860 | |||
| 4861 | INIT_DELAYED_WORK(&nn->laundromat_work, laundromat_main); | ||
| 4862 | get_net(net); | ||
| 4863 | |||
| 4864 | return 0; | ||
| 4865 | |||
| 4866 | err_sessionid: | ||
| 4867 | kfree(nn->lockowner_ino_hashtbl); | ||
| 4868 | err_lockowner_ino: | ||
| 4869 | kfree(nn->ownerstr_hashtbl); | ||
| 4870 | err_ownerstr: | ||
| 4871 | kfree(nn->unconf_id_hashtbl); | ||
| 4872 | err_unconf_id: | ||
| 4873 | kfree(nn->conf_id_hashtbl); | ||
| 4874 | err: | ||
| 4875 | return -ENOMEM; | ||
| 4876 | } | ||
| 4877 | |||
| 4878 | static void | ||
| 4879 | nfs4_state_destroy_net(struct net *net) | ||
| 4880 | { | ||
| 4881 | int i; | ||
| 4882 | struct nfs4_client *clp = NULL; | ||
| 4883 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
| 4884 | struct rb_node *node, *tmp; | ||
| 4885 | |||
| 4886 | for (i = 0; i < CLIENT_HASH_SIZE; i++) { | ||
| 4887 | while (!list_empty(&nn->conf_id_hashtbl[i])) { | ||
| 4888 | clp = list_entry(nn->conf_id_hashtbl[i].next, struct nfs4_client, cl_idhash); | ||
| 4889 | destroy_client(clp); | ||
| 4890 | } | ||
| 4891 | } | ||
| 4892 | |||
| 4893 | node = rb_first(&nn->unconf_name_tree); | ||
| 4894 | while (node != NULL) { | ||
| 4895 | tmp = node; | ||
| 4896 | node = rb_next(tmp); | ||
| 4897 | clp = rb_entry(tmp, struct nfs4_client, cl_namenode); | ||
| 4898 | rb_erase(tmp, &nn->unconf_name_tree); | ||
| 4899 | destroy_client(clp); | ||
| 4900 | } | ||
| 4901 | |||
| 4902 | kfree(nn->sessionid_hashtbl); | ||
| 4903 | kfree(nn->lockowner_ino_hashtbl); | ||
| 4904 | kfree(nn->ownerstr_hashtbl); | ||
| 4905 | kfree(nn->unconf_id_hashtbl); | ||
| 4906 | kfree(nn->conf_id_hashtbl); | ||
| 4907 | put_net(net); | ||
| 4908 | } | ||
| 4734 | 4909 | ||
| 4735 | int | 4910 | int |
| 4736 | nfs4_state_start(void) | 4911 | nfs4_state_start_net(struct net *net) |
| 4737 | { | 4912 | { |
| 4738 | struct net *net = &init_net; | ||
| 4739 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | 4913 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); |
| 4740 | int ret; | 4914 | int ret; |
| 4741 | 4915 | ||
| @@ -4746,18 +4920,32 @@ nfs4_state_start(void) | |||
| 4746 | * to that instead and then do most of the rest of this on a per-net | 4920 | * to that instead and then do most of the rest of this on a per-net |
| 4747 | * basis. | 4921 | * basis. |
| 4748 | */ | 4922 | */ |
| 4749 | get_net(net); | 4923 | if (net != &init_net) |
| 4924 | return -EINVAL; | ||
| 4925 | |||
| 4926 | ret = nfs4_state_create_net(net); | ||
| 4927 | if (ret) | ||
| 4928 | return ret; | ||
| 4750 | nfsd4_client_tracking_init(net); | 4929 | nfsd4_client_tracking_init(net); |
| 4751 | nn->boot_time = get_seconds(); | 4930 | nn->boot_time = get_seconds(); |
| 4752 | locks_start_grace(net, &nn->nfsd4_manager); | 4931 | locks_start_grace(net, &nn->nfsd4_manager); |
| 4753 | nn->grace_ended = false; | 4932 | nn->grace_ended = false; |
| 4754 | printk(KERN_INFO "NFSD: starting %ld-second grace period\n", | 4933 | printk(KERN_INFO "NFSD: starting %ld-second grace period (net %p)\n", |
| 4755 | nfsd4_grace); | 4934 | nn->nfsd4_grace, net); |
| 4935 | queue_delayed_work(laundry_wq, &nn->laundromat_work, nn->nfsd4_grace * HZ); | ||
| 4936 | return 0; | ||
| 4937 | } | ||
| 4938 | |||
| 4939 | /* initialization to perform when the nfsd service is started: */ | ||
| 4940 | |||
| 4941 | int | ||
| 4942 | nfs4_state_start(void) | ||
| 4943 | { | ||
| 4944 | int ret; | ||
| 4945 | |||
| 4756 | ret = set_callback_cred(); | 4946 | ret = set_callback_cred(); |
| 4757 | if (ret) { | 4947 | if (ret) |
| 4758 | ret = -ENOMEM; | 4948 | return -ENOMEM; |
| 4759 | goto out_recovery; | ||
| 4760 | } | ||
| 4761 | laundry_wq = create_singlethread_workqueue("nfsd4"); | 4949 | laundry_wq = create_singlethread_workqueue("nfsd4"); |
| 4762 | if (laundry_wq == NULL) { | 4950 | if (laundry_wq == NULL) { |
| 4763 | ret = -ENOMEM; | 4951 | ret = -ENOMEM; |
| @@ -4766,39 +4954,34 @@ nfs4_state_start(void) | |||
| 4766 | ret = nfsd4_create_callback_queue(); | 4954 | ret = nfsd4_create_callback_queue(); |
| 4767 | if (ret) | 4955 | if (ret) |
| 4768 | goto out_free_laundry; | 4956 | goto out_free_laundry; |
| 4769 | queue_delayed_work(laundry_wq, &laundromat_work, nfsd4_grace * HZ); | 4957 | |
| 4770 | set_max_delegations(); | 4958 | set_max_delegations(); |
| 4959 | |||
| 4771 | return 0; | 4960 | return 0; |
| 4961 | |||
| 4772 | out_free_laundry: | 4962 | out_free_laundry: |
| 4773 | destroy_workqueue(laundry_wq); | 4963 | destroy_workqueue(laundry_wq); |
| 4774 | out_recovery: | 4964 | out_recovery: |
| 4775 | nfsd4_client_tracking_exit(net); | ||
| 4776 | put_net(net); | ||
| 4777 | return ret; | 4965 | return ret; |
| 4778 | } | 4966 | } |
| 4779 | 4967 | ||
| 4780 | static void | 4968 | /* should be called with the state lock held */ |
| 4781 | __nfs4_state_shutdown(void) | 4969 | void |
| 4970 | nfs4_state_shutdown_net(struct net *net) | ||
| 4782 | { | 4971 | { |
| 4783 | int i; | ||
| 4784 | struct nfs4_client *clp = NULL; | ||
| 4785 | struct nfs4_delegation *dp = NULL; | 4972 | struct nfs4_delegation *dp = NULL; |
| 4786 | struct list_head *pos, *next, reaplist; | 4973 | struct list_head *pos, *next, reaplist; |
| 4974 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
| 4975 | |||
| 4976 | cancel_delayed_work_sync(&nn->laundromat_work); | ||
| 4977 | locks_end_grace(&nn->nfsd4_manager); | ||
| 4787 | 4978 | ||
| 4788 | for (i = 0; i < CLIENT_HASH_SIZE; i++) { | ||
| 4789 | while (!list_empty(&conf_id_hashtbl[i])) { | ||
| 4790 | clp = list_entry(conf_id_hashtbl[i].next, struct nfs4_client, cl_idhash); | ||
| 4791 | destroy_client(clp); | ||
| 4792 | } | ||
| 4793 | while (!list_empty(&unconf_str_hashtbl[i])) { | ||
| 4794 | clp = list_entry(unconf_str_hashtbl[i].next, struct nfs4_client, cl_strhash); | ||
| 4795 | destroy_client(clp); | ||
| 4796 | } | ||
| 4797 | } | ||
| 4798 | INIT_LIST_HEAD(&reaplist); | 4979 | INIT_LIST_HEAD(&reaplist); |
| 4799 | spin_lock(&recall_lock); | 4980 | spin_lock(&recall_lock); |
| 4800 | list_for_each_safe(pos, next, &del_recall_lru) { | 4981 | list_for_each_safe(pos, next, &del_recall_lru) { |
| 4801 | dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); | 4982 | dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); |
| 4983 | if (dp->dl_stid.sc_client->net != net) | ||
| 4984 | continue; | ||
| 4802 | list_move(&dp->dl_recall_lru, &reaplist); | 4985 | list_move(&dp->dl_recall_lru, &reaplist); |
| 4803 | } | 4986 | } |
| 4804 | spin_unlock(&recall_lock); | 4987 | spin_unlock(&recall_lock); |
| @@ -4807,22 +4990,14 @@ __nfs4_state_shutdown(void) | |||
| 4807 | unhash_delegation(dp); | 4990 | unhash_delegation(dp); |
| 4808 | } | 4991 | } |
| 4809 | 4992 | ||
| 4810 | nfsd4_client_tracking_exit(&init_net); | 4993 | nfsd4_client_tracking_exit(net); |
| 4811 | put_net(&init_net); | 4994 | nfs4_state_destroy_net(net); |
| 4812 | } | 4995 | } |
| 4813 | 4996 | ||
| 4814 | void | 4997 | void |
| 4815 | nfs4_state_shutdown(void) | 4998 | nfs4_state_shutdown(void) |
| 4816 | { | 4999 | { |
| 4817 | struct net *net = &init_net; | ||
| 4818 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
| 4819 | |||
| 4820 | cancel_delayed_work_sync(&laundromat_work); | ||
| 4821 | destroy_workqueue(laundry_wq); | 5000 | destroy_workqueue(laundry_wq); |
| 4822 | locks_end_grace(&nn->nfsd4_manager); | ||
| 4823 | nfs4_lock_state(); | ||
| 4824 | __nfs4_state_shutdown(); | ||
| 4825 | nfs4_unlock_state(); | ||
| 4826 | nfsd4_destroy_callback_queue(); | 5001 | nfsd4_destroy_callback_queue(); |
| 4827 | } | 5002 | } |
| 4828 | 5003 | ||
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index fd548d155088..0dc11586682f 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c | |||
| @@ -53,6 +53,7 @@ | |||
| 53 | #include "vfs.h" | 53 | #include "vfs.h" |
| 54 | #include "state.h" | 54 | #include "state.h" |
| 55 | #include "cache.h" | 55 | #include "cache.h" |
| 56 | #include "netns.h" | ||
| 56 | 57 | ||
| 57 | #define NFSDDBG_FACILITY NFSDDBG_XDR | 58 | #define NFSDDBG_FACILITY NFSDDBG_XDR |
| 58 | 59 | ||
| @@ -65,17 +66,17 @@ | |||
| 65 | #define NFS4_REFERRAL_FSID_MINOR 0x8000000ULL | 66 | #define NFS4_REFERRAL_FSID_MINOR 0x8000000ULL |
| 66 | 67 | ||
| 67 | static __be32 | 68 | static __be32 |
| 68 | check_filename(char *str, int len, __be32 err) | 69 | check_filename(char *str, int len) |
| 69 | { | 70 | { |
| 70 | int i; | 71 | int i; |
| 71 | 72 | ||
| 72 | if (len == 0) | 73 | if (len == 0) |
| 73 | return nfserr_inval; | 74 | return nfserr_inval; |
| 74 | if (isdotent(str, len)) | 75 | if (isdotent(str, len)) |
| 75 | return err; | 76 | return nfserr_badname; |
| 76 | for (i = 0; i < len; i++) | 77 | for (i = 0; i < len; i++) |
| 77 | if (str[i] == '/') | 78 | if (str[i] == '/') |
| 78 | return err; | 79 | return nfserr_badname; |
| 79 | return 0; | 80 | return 0; |
| 80 | } | 81 | } |
| 81 | 82 | ||
| @@ -422,6 +423,86 @@ nfsd4_decode_access(struct nfsd4_compoundargs *argp, struct nfsd4_access *access | |||
| 422 | DECODE_TAIL; | 423 | DECODE_TAIL; |
| 423 | } | 424 | } |
| 424 | 425 | ||
| 426 | static __be32 nfsd4_decode_cb_sec(struct nfsd4_compoundargs *argp, struct nfsd4_cb_sec *cbs) | ||
| 427 | { | ||
| 428 | DECODE_HEAD; | ||
| 429 | u32 dummy, uid, gid; | ||
| 430 | char *machine_name; | ||
| 431 | int i; | ||
| 432 | int nr_secflavs; | ||
| 433 | |||
| 434 | /* callback_sec_params4 */ | ||
| 435 | READ_BUF(4); | ||
| 436 | READ32(nr_secflavs); | ||
| 437 | cbs->flavor = (u32)(-1); | ||
| 438 | for (i = 0; i < nr_secflavs; ++i) { | ||
| 439 | READ_BUF(4); | ||
| 440 | READ32(dummy); | ||
| 441 | switch (dummy) { | ||
| 442 | case RPC_AUTH_NULL: | ||
| 443 | /* Nothing to read */ | ||
| 444 | if (cbs->flavor == (u32)(-1)) | ||
| 445 | cbs->flavor = RPC_AUTH_NULL; | ||
| 446 | break; | ||
| 447 | case RPC_AUTH_UNIX: | ||
| 448 | READ_BUF(8); | ||
| 449 | /* stamp */ | ||
| 450 | READ32(dummy); | ||
| 451 | |||
| 452 | /* machine name */ | ||
| 453 | READ32(dummy); | ||
| 454 | READ_BUF(dummy); | ||
| 455 | SAVEMEM(machine_name, dummy); | ||
| 456 | |||
| 457 | /* uid, gid */ | ||
| 458 | READ_BUF(8); | ||
| 459 | READ32(uid); | ||
| 460 | READ32(gid); | ||
| 461 | |||
| 462 | /* more gids */ | ||
| 463 | READ_BUF(4); | ||
| 464 | READ32(dummy); | ||
| 465 | READ_BUF(dummy * 4); | ||
| 466 | if (cbs->flavor == (u32)(-1)) { | ||
| 467 | cbs->uid = uid; | ||
| 468 | cbs->gid = gid; | ||
| 469 | cbs->flavor = RPC_AUTH_UNIX; | ||
| 470 | } | ||
| 471 | break; | ||
| 472 | case RPC_AUTH_GSS: | ||
| 473 | dprintk("RPC_AUTH_GSS callback secflavor " | ||
| 474 | "not supported!\n"); | ||
| 475 | READ_BUF(8); | ||
| 476 | /* gcbp_service */ | ||
| 477 | READ32(dummy); | ||
| 478 | /* gcbp_handle_from_server */ | ||
| 479 | READ32(dummy); | ||
| 480 | READ_BUF(dummy); | ||
| 481 | p += XDR_QUADLEN(dummy); | ||
| 482 | /* gcbp_handle_from_client */ | ||
| 483 | READ_BUF(4); | ||
| 484 | READ32(dummy); | ||
| 485 | READ_BUF(dummy); | ||
| 486 | break; | ||
| 487 | default: | ||
| 488 | dprintk("Illegal callback secflavor\n"); | ||
| 489 | return nfserr_inval; | ||
| 490 | } | ||
| 491 | } | ||
| 492 | DECODE_TAIL; | ||
| 493 | } | ||
| 494 | |||
| 495 | static __be32 nfsd4_decode_backchannel_ctl(struct nfsd4_compoundargs *argp, struct nfsd4_backchannel_ctl *bc) | ||
| 496 | { | ||
| 497 | DECODE_HEAD; | ||
| 498 | |||
| 499 | READ_BUF(4); | ||
| 500 | READ32(bc->bc_cb_program); | ||
| 501 | nfsd4_decode_cb_sec(argp, &bc->bc_cb_sec); | ||
| 502 | |||
| 503 | DECODE_TAIL; | ||
| 504 | } | ||
| 505 | |||
| 425 | static __be32 nfsd4_decode_bind_conn_to_session(struct nfsd4_compoundargs *argp, struct nfsd4_bind_conn_to_session *bcts) | 506 | static __be32 nfsd4_decode_bind_conn_to_session(struct nfsd4_compoundargs *argp, struct nfsd4_bind_conn_to_session *bcts) |
| 426 | { | 507 | { |
| 427 | DECODE_HEAD; | 508 | DECODE_HEAD; |
| @@ -490,7 +571,7 @@ nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create | |||
| 490 | READ32(create->cr_namelen); | 571 | READ32(create->cr_namelen); |
| 491 | READ_BUF(create->cr_namelen); | 572 | READ_BUF(create->cr_namelen); |
| 492 | SAVEMEM(create->cr_name, create->cr_namelen); | 573 | SAVEMEM(create->cr_name, create->cr_namelen); |
| 493 | if ((status = check_filename(create->cr_name, create->cr_namelen, nfserr_inval))) | 574 | if ((status = check_filename(create->cr_name, create->cr_namelen))) |
| 494 | return status; | 575 | return status; |
| 495 | 576 | ||
| 496 | status = nfsd4_decode_fattr(argp, create->cr_bmval, &create->cr_iattr, | 577 | status = nfsd4_decode_fattr(argp, create->cr_bmval, &create->cr_iattr, |
| @@ -522,7 +603,7 @@ nfsd4_decode_link(struct nfsd4_compoundargs *argp, struct nfsd4_link *link) | |||
| 522 | READ32(link->li_namelen); | 603 | READ32(link->li_namelen); |
| 523 | READ_BUF(link->li_namelen); | 604 | READ_BUF(link->li_namelen); |
| 524 | SAVEMEM(link->li_name, link->li_namelen); | 605 | SAVEMEM(link->li_name, link->li_namelen); |
| 525 | if ((status = check_filename(link->li_name, link->li_namelen, nfserr_inval))) | 606 | if ((status = check_filename(link->li_name, link->li_namelen))) |
| 526 | return status; | 607 | return status; |
| 527 | 608 | ||
| 528 | DECODE_TAIL; | 609 | DECODE_TAIL; |
| @@ -616,7 +697,7 @@ nfsd4_decode_lookup(struct nfsd4_compoundargs *argp, struct nfsd4_lookup *lookup | |||
| 616 | READ32(lookup->lo_len); | 697 | READ32(lookup->lo_len); |
| 617 | READ_BUF(lookup->lo_len); | 698 | READ_BUF(lookup->lo_len); |
| 618 | SAVEMEM(lookup->lo_name, lookup->lo_len); | 699 | SAVEMEM(lookup->lo_name, lookup->lo_len); |
| 619 | if ((status = check_filename(lookup->lo_name, lookup->lo_len, nfserr_noent))) | 700 | if ((status = check_filename(lookup->lo_name, lookup->lo_len))) |
| 620 | return status; | 701 | return status; |
| 621 | 702 | ||
| 622 | DECODE_TAIL; | 703 | DECODE_TAIL; |
| @@ -780,7 +861,7 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) | |||
| 780 | READ32(open->op_fname.len); | 861 | READ32(open->op_fname.len); |
| 781 | READ_BUF(open->op_fname.len); | 862 | READ_BUF(open->op_fname.len); |
| 782 | SAVEMEM(open->op_fname.data, open->op_fname.len); | 863 | SAVEMEM(open->op_fname.data, open->op_fname.len); |
| 783 | if ((status = check_filename(open->op_fname.data, open->op_fname.len, nfserr_inval))) | 864 | if ((status = check_filename(open->op_fname.data, open->op_fname.len))) |
| 784 | return status; | 865 | return status; |
| 785 | break; | 866 | break; |
| 786 | case NFS4_OPEN_CLAIM_PREVIOUS: | 867 | case NFS4_OPEN_CLAIM_PREVIOUS: |
| @@ -795,7 +876,7 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) | |||
| 795 | READ32(open->op_fname.len); | 876 | READ32(open->op_fname.len); |
| 796 | READ_BUF(open->op_fname.len); | 877 | READ_BUF(open->op_fname.len); |
| 797 | SAVEMEM(open->op_fname.data, open->op_fname.len); | 878 | SAVEMEM(open->op_fname.data, open->op_fname.len); |
| 798 | if ((status = check_filename(open->op_fname.data, open->op_fname.len, nfserr_inval))) | 879 | if ((status = check_filename(open->op_fname.data, open->op_fname.len))) |
| 799 | return status; | 880 | return status; |
| 800 | break; | 881 | break; |
| 801 | case NFS4_OPEN_CLAIM_FH: | 882 | case NFS4_OPEN_CLAIM_FH: |
| @@ -907,7 +988,7 @@ nfsd4_decode_remove(struct nfsd4_compoundargs *argp, struct nfsd4_remove *remove | |||
| 907 | READ32(remove->rm_namelen); | 988 | READ32(remove->rm_namelen); |
| 908 | READ_BUF(remove->rm_namelen); | 989 | READ_BUF(remove->rm_namelen); |
| 909 | SAVEMEM(remove->rm_name, remove->rm_namelen); | 990 | SAVEMEM(remove->rm_name, remove->rm_namelen); |
| 910 | if ((status = check_filename(remove->rm_name, remove->rm_namelen, nfserr_noent))) | 991 | if ((status = check_filename(remove->rm_name, remove->rm_namelen))) |
| 911 | return status; | 992 | return status; |
| 912 | 993 | ||
| 913 | DECODE_TAIL; | 994 | DECODE_TAIL; |
| @@ -925,9 +1006,9 @@ nfsd4_decode_rename(struct nfsd4_compoundargs *argp, struct nfsd4_rename *rename | |||
| 925 | READ32(rename->rn_tnamelen); | 1006 | READ32(rename->rn_tnamelen); |
| 926 | READ_BUF(rename->rn_tnamelen); | 1007 | READ_BUF(rename->rn_tnamelen); |
| 927 | SAVEMEM(rename->rn_tname, rename->rn_tnamelen); | 1008 | SAVEMEM(rename->rn_tname, rename->rn_tnamelen); |
| 928 | if ((status = check_filename(rename->rn_sname, rename->rn_snamelen, nfserr_noent))) | 1009 | if ((status = check_filename(rename->rn_sname, rename->rn_snamelen))) |
| 929 | return status; | 1010 | return status; |
| 930 | if ((status = check_filename(rename->rn_tname, rename->rn_tnamelen, nfserr_inval))) | 1011 | if ((status = check_filename(rename->rn_tname, rename->rn_tnamelen))) |
| 931 | return status; | 1012 | return status; |
| 932 | 1013 | ||
| 933 | DECODE_TAIL; | 1014 | DECODE_TAIL; |
| @@ -954,8 +1035,7 @@ nfsd4_decode_secinfo(struct nfsd4_compoundargs *argp, | |||
| 954 | READ32(secinfo->si_namelen); | 1035 | READ32(secinfo->si_namelen); |
| 955 | READ_BUF(secinfo->si_namelen); | 1036 | READ_BUF(secinfo->si_namelen); |
| 956 | SAVEMEM(secinfo->si_name, secinfo->si_namelen); | 1037 | SAVEMEM(secinfo->si_name, secinfo->si_namelen); |
| 957 | status = check_filename(secinfo->si_name, secinfo->si_namelen, | 1038 | status = check_filename(secinfo->si_name, secinfo->si_namelen); |
| 958 | nfserr_noent); | ||
| 959 | if (status) | 1039 | if (status) |
| 960 | return status; | 1040 | return status; |
| 961 | DECODE_TAIL; | 1041 | DECODE_TAIL; |
| @@ -1026,31 +1106,14 @@ nfsd4_decode_setclientid_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_s | |||
| 1026 | static __be32 | 1106 | static __be32 |
| 1027 | nfsd4_decode_verify(struct nfsd4_compoundargs *argp, struct nfsd4_verify *verify) | 1107 | nfsd4_decode_verify(struct nfsd4_compoundargs *argp, struct nfsd4_verify *verify) |
| 1028 | { | 1108 | { |
| 1029 | #if 0 | ||
| 1030 | struct nfsd4_compoundargs save = { | ||
| 1031 | .p = argp->p, | ||
| 1032 | .end = argp->end, | ||
| 1033 | .rqstp = argp->rqstp, | ||
| 1034 | }; | ||
| 1035 | u32 ve_bmval[2]; | ||
| 1036 | struct iattr ve_iattr; /* request */ | ||
| 1037 | struct nfs4_acl *ve_acl; /* request */ | ||
| 1038 | #endif | ||
| 1039 | DECODE_HEAD; | 1109 | DECODE_HEAD; |
| 1040 | 1110 | ||
| 1041 | if ((status = nfsd4_decode_bitmap(argp, verify->ve_bmval))) | 1111 | if ((status = nfsd4_decode_bitmap(argp, verify->ve_bmval))) |
| 1042 | goto out; | 1112 | goto out; |
| 1043 | 1113 | ||
| 1044 | /* For convenience's sake, we compare raw xdr'd attributes in | 1114 | /* For convenience's sake, we compare raw xdr'd attributes in |
| 1045 | * nfsd4_proc_verify; however we still decode here just to return | 1115 | * nfsd4_proc_verify */ |
| 1046 | * correct error in case of bad xdr. */ | 1116 | |
| 1047 | #if 0 | ||
| 1048 | status = nfsd4_decode_fattr(ve_bmval, &ve_iattr, &ve_acl); | ||
| 1049 | if (status == nfserr_inval) { | ||
| 1050 | status = nfserrno(status); | ||
| 1051 | goto out; | ||
| 1052 | } | ||
| 1053 | #endif | ||
| 1054 | READ_BUF(4); | 1117 | READ_BUF(4); |
| 1055 | READ32(verify->ve_attrlen); | 1118 | READ32(verify->ve_attrlen); |
| 1056 | READ_BUF(verify->ve_attrlen); | 1119 | READ_BUF(verify->ve_attrlen); |
| @@ -1063,7 +1126,6 @@ static __be32 | |||
| 1063 | nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write) | 1126 | nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write) |
| 1064 | { | 1127 | { |
| 1065 | int avail; | 1128 | int avail; |
| 1066 | int v; | ||
| 1067 | int len; | 1129 | int len; |
| 1068 | DECODE_HEAD; | 1130 | DECODE_HEAD; |
| 1069 | 1131 | ||
| @@ -1087,27 +1149,26 @@ nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write) | |||
| 1087 | __FILE__, __LINE__); | 1149 | __FILE__, __LINE__); |
| 1088 | goto xdr_error; | 1150 | goto xdr_error; |
| 1089 | } | 1151 | } |
| 1090 | argp->rqstp->rq_vec[0].iov_base = p; | 1152 | write->wr_head.iov_base = p; |
| 1091 | argp->rqstp->rq_vec[0].iov_len = avail; | 1153 | write->wr_head.iov_len = avail; |
| 1092 | v = 0; | 1154 | WARN_ON(avail != (XDR_QUADLEN(avail) << 2)); |
| 1093 | len = write->wr_buflen; | 1155 | write->wr_pagelist = argp->pagelist; |
| 1094 | while (len > argp->rqstp->rq_vec[v].iov_len) { | 1156 | |
| 1095 | len -= argp->rqstp->rq_vec[v].iov_len; | 1157 | len = XDR_QUADLEN(write->wr_buflen) << 2; |
| 1096 | v++; | 1158 | if (len >= avail) { |
| 1097 | argp->rqstp->rq_vec[v].iov_base = page_address(argp->pagelist[0]); | 1159 | int pages; |
| 1098 | argp->pagelist++; | 1160 | |
| 1099 | if (argp->pagelen >= PAGE_SIZE) { | 1161 | len -= avail; |
| 1100 | argp->rqstp->rq_vec[v].iov_len = PAGE_SIZE; | 1162 | |
| 1101 | argp->pagelen -= PAGE_SIZE; | 1163 | pages = len >> PAGE_SHIFT; |
| 1102 | } else { | 1164 | argp->pagelist += pages; |
| 1103 | argp->rqstp->rq_vec[v].iov_len = argp->pagelen; | 1165 | argp->pagelen -= pages * PAGE_SIZE; |
| 1104 | argp->pagelen -= len; | 1166 | len -= pages * PAGE_SIZE; |
| 1105 | } | 1167 | |
| 1168 | argp->p = (__be32 *)page_address(argp->pagelist[0]); | ||
| 1169 | argp->end = argp->p + XDR_QUADLEN(PAGE_SIZE); | ||
| 1106 | } | 1170 | } |
| 1107 | argp->end = (__be32*) (argp->rqstp->rq_vec[v].iov_base + argp->rqstp->rq_vec[v].iov_len); | 1171 | argp->p += XDR_QUADLEN(len); |
| 1108 | argp->p = (__be32*) (argp->rqstp->rq_vec[v].iov_base + (XDR_QUADLEN(len) << 2)); | ||
| 1109 | argp->rqstp->rq_vec[v].iov_len = len; | ||
| 1110 | write->wr_vlen = v+1; | ||
| 1111 | 1172 | ||
| 1112 | DECODE_TAIL; | 1173 | DECODE_TAIL; |
| 1113 | } | 1174 | } |
| @@ -1237,11 +1298,7 @@ nfsd4_decode_create_session(struct nfsd4_compoundargs *argp, | |||
| 1237 | struct nfsd4_create_session *sess) | 1298 | struct nfsd4_create_session *sess) |
| 1238 | { | 1299 | { |
| 1239 | DECODE_HEAD; | 1300 | DECODE_HEAD; |
| 1240 | |||
| 1241 | u32 dummy; | 1301 | u32 dummy; |
| 1242 | char *machine_name; | ||
| 1243 | int i; | ||
| 1244 | int nr_secflavs; | ||
| 1245 | 1302 | ||
| 1246 | READ_BUF(16); | 1303 | READ_BUF(16); |
| 1247 | COPYMEM(&sess->clientid, 8); | 1304 | COPYMEM(&sess->clientid, 8); |
| @@ -1282,58 +1339,9 @@ nfsd4_decode_create_session(struct nfsd4_compoundargs *argp, | |||
| 1282 | goto xdr_error; | 1339 | goto xdr_error; |
| 1283 | } | 1340 | } |
| 1284 | 1341 | ||
| 1285 | READ_BUF(8); | 1342 | READ_BUF(4); |
| 1286 | READ32(sess->callback_prog); | 1343 | READ32(sess->callback_prog); |
| 1287 | 1344 | nfsd4_decode_cb_sec(argp, &sess->cb_sec); | |
| 1288 | /* callback_sec_params4 */ | ||
| 1289 | READ32(nr_secflavs); | ||
| 1290 | for (i = 0; i < nr_secflavs; ++i) { | ||
| 1291 | READ_BUF(4); | ||
| 1292 | READ32(dummy); | ||
| 1293 | switch (dummy) { | ||
| 1294 | case RPC_AUTH_NULL: | ||
| 1295 | /* Nothing to read */ | ||
| 1296 | break; | ||
| 1297 | case RPC_AUTH_UNIX: | ||
| 1298 | READ_BUF(8); | ||
| 1299 | /* stamp */ | ||
| 1300 | READ32(dummy); | ||
| 1301 | |||
| 1302 | /* machine name */ | ||
| 1303 | READ32(dummy); | ||
| 1304 | READ_BUF(dummy); | ||
| 1305 | SAVEMEM(machine_name, dummy); | ||
| 1306 | |||
| 1307 | /* uid, gid */ | ||
| 1308 | READ_BUF(8); | ||
| 1309 | READ32(sess->uid); | ||
| 1310 | READ32(sess->gid); | ||
| 1311 | |||
| 1312 | /* more gids */ | ||
| 1313 | READ_BUF(4); | ||
| 1314 | READ32(dummy); | ||
| 1315 | READ_BUF(dummy * 4); | ||
| 1316 | break; | ||
| 1317 | case RPC_AUTH_GSS: | ||
| 1318 | dprintk("RPC_AUTH_GSS callback secflavor " | ||
| 1319 | "not supported!\n"); | ||
| 1320 | READ_BUF(8); | ||
| 1321 | /* gcbp_service */ | ||
| 1322 | READ32(dummy); | ||
| 1323 | /* gcbp_handle_from_server */ | ||
| 1324 | READ32(dummy); | ||
| 1325 | READ_BUF(dummy); | ||
| 1326 | p += XDR_QUADLEN(dummy); | ||
| 1327 | /* gcbp_handle_from_client */ | ||
| 1328 | READ_BUF(4); | ||
| 1329 | READ32(dummy); | ||
| 1330 | READ_BUF(dummy); | ||
| 1331 | break; | ||
| 1332 | default: | ||
| 1333 | dprintk("Illegal callback secflavor\n"); | ||
| 1334 | return nfserr_inval; | ||
| 1335 | } | ||
| 1336 | } | ||
| 1337 | DECODE_TAIL; | 1345 | DECODE_TAIL; |
| 1338 | } | 1346 | } |
| 1339 | 1347 | ||
| @@ -1528,7 +1536,7 @@ static nfsd4_dec nfsd41_dec_ops[] = { | |||
| 1528 | [OP_RELEASE_LOCKOWNER] = (nfsd4_dec)nfsd4_decode_notsupp, | 1536 | [OP_RELEASE_LOCKOWNER] = (nfsd4_dec)nfsd4_decode_notsupp, |
| 1529 | 1537 | ||
| 1530 | /* new operations for NFSv4.1 */ | 1538 | /* new operations for NFSv4.1 */ |
| 1531 | [OP_BACKCHANNEL_CTL] = (nfsd4_dec)nfsd4_decode_notsupp, | 1539 | [OP_BACKCHANNEL_CTL] = (nfsd4_dec)nfsd4_decode_backchannel_ctl, |
| 1532 | [OP_BIND_CONN_TO_SESSION]= (nfsd4_dec)nfsd4_decode_bind_conn_to_session, | 1540 | [OP_BIND_CONN_TO_SESSION]= (nfsd4_dec)nfsd4_decode_bind_conn_to_session, |
| 1533 | [OP_EXCHANGE_ID] = (nfsd4_dec)nfsd4_decode_exchange_id, | 1541 | [OP_EXCHANGE_ID] = (nfsd4_dec)nfsd4_decode_exchange_id, |
| 1534 | [OP_CREATE_SESSION] = (nfsd4_dec)nfsd4_decode_create_session, | 1542 | [OP_CREATE_SESSION] = (nfsd4_dec)nfsd4_decode_create_session, |
| @@ -1568,12 +1576,6 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) | |||
| 1568 | bool cachethis = false; | 1576 | bool cachethis = false; |
| 1569 | int i; | 1577 | int i; |
| 1570 | 1578 | ||
| 1571 | /* | ||
| 1572 | * XXX: According to spec, we should check the tag | ||
| 1573 | * for UTF-8 compliance. I'm postponing this for | ||
| 1574 | * now because it seems that some clients do use | ||
| 1575 | * binary tags. | ||
| 1576 | */ | ||
| 1577 | READ_BUF(4); | 1579 | READ_BUF(4); |
| 1578 | READ32(argp->taglen); | 1580 | READ32(argp->taglen); |
| 1579 | READ_BUF(argp->taglen + 8); | 1581 | READ_BUF(argp->taglen + 8); |
| @@ -1603,38 +1605,8 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) | |||
| 1603 | op = &argp->ops[i]; | 1605 | op = &argp->ops[i]; |
| 1604 | op->replay = NULL; | 1606 | op->replay = NULL; |
| 1605 | 1607 | ||
| 1606 | /* | 1608 | READ_BUF(4); |
| 1607 | * We can't use READ_BUF() here because we need to handle | 1609 | READ32(op->opnum); |
| 1608 | * a missing opcode as an OP_WRITE + 1. So we need to check | ||
| 1609 | * to see if we're truly at the end of our buffer or if there | ||
| 1610 | * is another page we need to flip to. | ||
| 1611 | */ | ||
| 1612 | |||
| 1613 | if (argp->p == argp->end) { | ||
| 1614 | if (argp->pagelen < 4) { | ||
| 1615 | /* There isn't an opcode still on the wire */ | ||
| 1616 | op->opnum = OP_WRITE + 1; | ||
| 1617 | op->status = nfserr_bad_xdr; | ||
| 1618 | argp->opcnt = i+1; | ||
| 1619 | break; | ||
| 1620 | } | ||
| 1621 | |||
| 1622 | /* | ||
| 1623 | * False alarm. We just hit a page boundary, but there | ||
| 1624 | * is still data available. Move pointer across page | ||
| 1625 | * boundary. *snip from READ_BUF* | ||
| 1626 | */ | ||
| 1627 | argp->p = page_address(argp->pagelist[0]); | ||
| 1628 | argp->pagelist++; | ||
| 1629 | if (argp->pagelen < PAGE_SIZE) { | ||
| 1630 | argp->end = argp->p + (argp->pagelen>>2); | ||
| 1631 | argp->pagelen = 0; | ||
| 1632 | } else { | ||
| 1633 | argp->end = argp->p + (PAGE_SIZE>>2); | ||
| 1634 | argp->pagelen -= PAGE_SIZE; | ||
| 1635 | } | ||
| 1636 | } | ||
| 1637 | op->opnum = ntohl(*argp->p++); | ||
| 1638 | 1610 | ||
| 1639 | if (op->opnum >= FIRST_NFS4_OP && op->opnum <= LAST_NFS4_OP) | 1611 | if (op->opnum >= FIRST_NFS4_OP && op->opnum <= LAST_NFS4_OP) |
| 1640 | op->status = ops->decoders[op->opnum](argp, &op->u); | 1612 | op->status = ops->decoders[op->opnum](argp, &op->u); |
| @@ -2014,6 +1986,22 @@ static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err) | |||
| 2014 | return 0; | 1986 | return 0; |
| 2015 | } | 1987 | } |
| 2016 | 1988 | ||
| 1989 | |||
| 1990 | static int get_parent_attributes(struct svc_export *exp, struct kstat *stat) | ||
| 1991 | { | ||
| 1992 | struct path path = exp->ex_path; | ||
| 1993 | int err; | ||
| 1994 | |||
| 1995 | path_get(&path); | ||
| 1996 | while (follow_up(&path)) { | ||
| 1997 | if (path.dentry != path.mnt->mnt_root) | ||
| 1998 | break; | ||
| 1999 | } | ||
| 2000 | err = vfs_getattr(path.mnt, path.dentry, stat); | ||
| 2001 | path_put(&path); | ||
| 2002 | return err; | ||
| 2003 | } | ||
| 2004 | |||
| 2017 | /* | 2005 | /* |
| 2018 | * Note: @fhp can be NULL; in this case, we might have to compose the filehandle | 2006 | * Note: @fhp can be NULL; in this case, we might have to compose the filehandle |
| 2019 | * ourselves. | 2007 | * ourselves. |
| @@ -2048,6 +2036,7 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, | |||
| 2048 | .mnt = exp->ex_path.mnt, | 2036 | .mnt = exp->ex_path.mnt, |
| 2049 | .dentry = dentry, | 2037 | .dentry = dentry, |
| 2050 | }; | 2038 | }; |
| 2039 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | ||
| 2051 | 2040 | ||
| 2052 | BUG_ON(bmval1 & NFSD_WRITEONLY_ATTRS_WORD1); | 2041 | BUG_ON(bmval1 & NFSD_WRITEONLY_ATTRS_WORD1); |
| 2053 | BUG_ON(bmval0 & ~nfsd_suppattrs0(minorversion)); | 2042 | BUG_ON(bmval0 & ~nfsd_suppattrs0(minorversion)); |
| @@ -2208,7 +2197,7 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, | |||
| 2208 | if (bmval0 & FATTR4_WORD0_LEASE_TIME) { | 2197 | if (bmval0 & FATTR4_WORD0_LEASE_TIME) { |
| 2209 | if ((buflen -= 4) < 0) | 2198 | if ((buflen -= 4) < 0) |
| 2210 | goto out_resource; | 2199 | goto out_resource; |
| 2211 | WRITE32(nfsd4_lease); | 2200 | WRITE32(nn->nfsd4_lease); |
| 2212 | } | 2201 | } |
| 2213 | if (bmval0 & FATTR4_WORD0_RDATTR_ERROR) { | 2202 | if (bmval0 & FATTR4_WORD0_RDATTR_ERROR) { |
| 2214 | if ((buflen -= 4) < 0) | 2203 | if ((buflen -= 4) < 0) |
| @@ -2430,18 +2419,8 @@ out_acl: | |||
| 2430 | * and this is the root of a cross-mounted filesystem. | 2419 | * and this is the root of a cross-mounted filesystem. |
| 2431 | */ | 2420 | */ |
| 2432 | if (ignore_crossmnt == 0 && | 2421 | if (ignore_crossmnt == 0 && |
| 2433 | dentry == exp->ex_path.mnt->mnt_root) { | 2422 | dentry == exp->ex_path.mnt->mnt_root) |
| 2434 | struct path path = exp->ex_path; | 2423 | get_parent_attributes(exp, &stat); |
| 2435 | path_get(&path); | ||
| 2436 | while (follow_up(&path)) { | ||
| 2437 | if (path.dentry != path.mnt->mnt_root) | ||
| 2438 | break; | ||
| 2439 | } | ||
| 2440 | err = vfs_getattr(path.mnt, path.dentry, &stat); | ||
| 2441 | path_put(&path); | ||
| 2442 | if (err) | ||
| 2443 | goto out_nfserr; | ||
| 2444 | } | ||
| 2445 | WRITE64(stat.ino); | 2424 | WRITE64(stat.ino); |
| 2446 | } | 2425 | } |
| 2447 | if (bmval2 & FATTR4_WORD2_SUPPATTR_EXCLCREAT) { | 2426 | if (bmval2 & FATTR4_WORD2_SUPPATTR_EXCLCREAT) { |
| @@ -2927,7 +2906,8 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr, | |||
| 2927 | struct nfsd4_read *read) | 2906 | struct nfsd4_read *read) |
| 2928 | { | 2907 | { |
| 2929 | u32 eof; | 2908 | u32 eof; |
| 2930 | int v, pn; | 2909 | int v; |
| 2910 | struct page *page; | ||
| 2931 | unsigned long maxcount; | 2911 | unsigned long maxcount; |
| 2932 | long len; | 2912 | long len; |
| 2933 | __be32 *p; | 2913 | __be32 *p; |
| @@ -2946,11 +2926,15 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr, | |||
| 2946 | len = maxcount; | 2926 | len = maxcount; |
| 2947 | v = 0; | 2927 | v = 0; |
| 2948 | while (len > 0) { | 2928 | while (len > 0) { |
| 2949 | pn = resp->rqstp->rq_resused++; | 2929 | page = *(resp->rqstp->rq_next_page); |
| 2950 | resp->rqstp->rq_vec[v].iov_base = | 2930 | if (!page) { /* ran out of pages */ |
| 2951 | page_address(resp->rqstp->rq_respages[pn]); | 2931 | maxcount -= len; |
| 2932 | break; | ||
| 2933 | } | ||
| 2934 | resp->rqstp->rq_vec[v].iov_base = page_address(page); | ||
| 2952 | resp->rqstp->rq_vec[v].iov_len = | 2935 | resp->rqstp->rq_vec[v].iov_len = |
| 2953 | len < PAGE_SIZE ? len : PAGE_SIZE; | 2936 | len < PAGE_SIZE ? len : PAGE_SIZE; |
| 2937 | resp->rqstp->rq_next_page++; | ||
| 2954 | v++; | 2938 | v++; |
| 2955 | len -= PAGE_SIZE; | 2939 | len -= PAGE_SIZE; |
| 2956 | } | 2940 | } |
| @@ -2996,8 +2980,10 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd | |||
| 2996 | return nfserr; | 2980 | return nfserr; |
| 2997 | if (resp->xbuf->page_len) | 2981 | if (resp->xbuf->page_len) |
| 2998 | return nfserr_resource; | 2982 | return nfserr_resource; |
| 2983 | if (!*resp->rqstp->rq_next_page) | ||
| 2984 | return nfserr_resource; | ||
| 2999 | 2985 | ||
| 3000 | page = page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused++]); | 2986 | page = page_address(*(resp->rqstp->rq_next_page++)); |
| 3001 | 2987 | ||
| 3002 | maxcount = PAGE_SIZE; | 2988 | maxcount = PAGE_SIZE; |
| 3003 | RESERVE_SPACE(4); | 2989 | RESERVE_SPACE(4); |
| @@ -3045,6 +3031,8 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4 | |||
| 3045 | return nfserr; | 3031 | return nfserr; |
| 3046 | if (resp->xbuf->page_len) | 3032 | if (resp->xbuf->page_len) |
| 3047 | return nfserr_resource; | 3033 | return nfserr_resource; |
| 3034 | if (!*resp->rqstp->rq_next_page) | ||
| 3035 | return nfserr_resource; | ||
| 3048 | 3036 | ||
| 3049 | RESERVE_SPACE(NFS4_VERIFIER_SIZE); | 3037 | RESERVE_SPACE(NFS4_VERIFIER_SIZE); |
| 3050 | savep = p; | 3038 | savep = p; |
| @@ -3071,7 +3059,7 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4 | |||
| 3071 | goto err_no_verf; | 3059 | goto err_no_verf; |
| 3072 | } | 3060 | } |
| 3073 | 3061 | ||
| 3074 | page = page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused++]); | 3062 | page = page_address(*(resp->rqstp->rq_next_page++)); |
| 3075 | readdir->common.err = 0; | 3063 | readdir->common.err = 0; |
| 3076 | readdir->buflen = maxcount; | 3064 | readdir->buflen = maxcount; |
| 3077 | readdir->buffer = page; | 3065 | readdir->buffer = page; |
| @@ -3094,8 +3082,8 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4 | |||
| 3094 | p = readdir->buffer; | 3082 | p = readdir->buffer; |
| 3095 | *p++ = 0; /* no more entries */ | 3083 | *p++ = 0; /* no more entries */ |
| 3096 | *p++ = htonl(readdir->common.err == nfserr_eof); | 3084 | *p++ = htonl(readdir->common.err == nfserr_eof); |
| 3097 | resp->xbuf->page_len = ((char*)p) - (char*)page_address( | 3085 | resp->xbuf->page_len = ((char*)p) - |
| 3098 | resp->rqstp->rq_respages[resp->rqstp->rq_resused-1]); | 3086 | (char*)page_address(*(resp->rqstp->rq_next_page-1)); |
| 3099 | 3087 | ||
| 3100 | /* Use rest of head for padding and remaining ops: */ | 3088 | /* Use rest of head for padding and remaining ops: */ |
| 3101 | resp->xbuf->tail[0].iov_base = tailbase; | 3089 | resp->xbuf->tail[0].iov_base = tailbase; |
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index dab350dfc376..74934284d9a7 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c | |||
| @@ -19,7 +19,7 @@ | |||
| 19 | #include "idmap.h" | 19 | #include "idmap.h" |
| 20 | #include "nfsd.h" | 20 | #include "nfsd.h" |
| 21 | #include "cache.h" | 21 | #include "cache.h" |
| 22 | #include "fault_inject.h" | 22 | #include "state.h" |
| 23 | #include "netns.h" | 23 | #include "netns.h" |
| 24 | 24 | ||
| 25 | /* | 25 | /* |
| @@ -186,9 +186,6 @@ static struct file_operations supported_enctypes_ops = { | |||
| 186 | }; | 186 | }; |
| 187 | #endif /* CONFIG_SUNRPC_GSS or CONFIG_SUNRPC_GSS_MODULE */ | 187 | #endif /* CONFIG_SUNRPC_GSS or CONFIG_SUNRPC_GSS_MODULE */ |
| 188 | 188 | ||
| 189 | extern int nfsd_pool_stats_open(struct inode *inode, struct file *file); | ||
| 190 | extern int nfsd_pool_stats_release(struct inode *inode, struct file *file); | ||
| 191 | |||
| 192 | static const struct file_operations pool_stats_operations = { | 189 | static const struct file_operations pool_stats_operations = { |
| 193 | .open = nfsd_pool_stats_open, | 190 | .open = nfsd_pool_stats_open, |
| 194 | .read = seq_read, | 191 | .read = seq_read, |
| @@ -399,6 +396,8 @@ static ssize_t write_threads(struct file *file, char *buf, size_t size) | |||
| 399 | { | 396 | { |
| 400 | char *mesg = buf; | 397 | char *mesg = buf; |
| 401 | int rv; | 398 | int rv; |
| 399 | struct net *net = &init_net; | ||
| 400 | |||
| 402 | if (size > 0) { | 401 | if (size > 0) { |
| 403 | int newthreads; | 402 | int newthreads; |
| 404 | rv = get_int(&mesg, &newthreads); | 403 | rv = get_int(&mesg, &newthreads); |
| @@ -406,11 +405,11 @@ static ssize_t write_threads(struct file *file, char *buf, size_t size) | |||
| 406 | return rv; | 405 | return rv; |
| 407 | if (newthreads < 0) | 406 | if (newthreads < 0) |
| 408 | return -EINVAL; | 407 | return -EINVAL; |
| 409 | rv = nfsd_svc(newthreads); | 408 | rv = nfsd_svc(newthreads, net); |
| 410 | if (rv < 0) | 409 | if (rv < 0) |
| 411 | return rv; | 410 | return rv; |
| 412 | } else | 411 | } else |
| 413 | rv = nfsd_nrthreads(); | 412 | rv = nfsd_nrthreads(net); |
| 414 | 413 | ||
| 415 | return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%d\n", rv); | 414 | return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%d\n", rv); |
| 416 | } | 415 | } |
| @@ -448,9 +447,10 @@ static ssize_t write_pool_threads(struct file *file, char *buf, size_t size) | |||
| 448 | int len; | 447 | int len; |
| 449 | int npools; | 448 | int npools; |
| 450 | int *nthreads; | 449 | int *nthreads; |
| 450 | struct net *net = &init_net; | ||
| 451 | 451 | ||
| 452 | mutex_lock(&nfsd_mutex); | 452 | mutex_lock(&nfsd_mutex); |
| 453 | npools = nfsd_nrpools(); | 453 | npools = nfsd_nrpools(net); |
| 454 | if (npools == 0) { | 454 | if (npools == 0) { |
| 455 | /* | 455 | /* |
| 456 | * NFS is shut down. The admin can start it by | 456 | * 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) | |||
| 478 | if (nthreads[i] < 0) | 478 | if (nthreads[i] < 0) |
| 479 | goto out_free; | 479 | goto out_free; |
| 480 | } | 480 | } |
| 481 | rv = nfsd_set_nrthreads(i, nthreads); | 481 | rv = nfsd_set_nrthreads(i, nthreads, net); |
| 482 | if (rv) | 482 | if (rv) |
| 483 | goto out_free; | 483 | goto out_free; |
| 484 | } | 484 | } |
| 485 | 485 | ||
| 486 | rv = nfsd_get_nrthreads(npools, nthreads); | 486 | rv = nfsd_get_nrthreads(npools, nthreads, net); |
| 487 | if (rv) | 487 | if (rv) |
| 488 | goto out_free; | 488 | goto out_free; |
| 489 | 489 | ||
| @@ -510,11 +510,13 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size) | |||
| 510 | unsigned minor; | 510 | unsigned minor; |
| 511 | ssize_t tlen = 0; | 511 | ssize_t tlen = 0; |
| 512 | char *sep; | 512 | char *sep; |
| 513 | struct net *net = &init_net; | ||
| 514 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
| 513 | 515 | ||
| 514 | if (size>0) { | 516 | if (size>0) { |
| 515 | if (nfsd_serv) | 517 | if (nn->nfsd_serv) |
| 516 | /* Cannot change versions without updating | 518 | /* Cannot change versions without updating |
| 517 | * nfsd_serv->sv_xdrsize, and reallocing | 519 | * nn->nfsd_serv->sv_xdrsize, and reallocing |
| 518 | * rq_argp and rq_resp | 520 | * rq_argp and rq_resp |
| 519 | */ | 521 | */ |
| 520 | return -EBUSY; | 522 | return -EBUSY; |
| @@ -645,11 +647,13 @@ static ssize_t write_versions(struct file *file, char *buf, size_t size) | |||
| 645 | * Zero-length write. Return a list of NFSD's current listener | 647 | * Zero-length write. Return a list of NFSD's current listener |
| 646 | * transports. | 648 | * transports. |
| 647 | */ | 649 | */ |
| 648 | static ssize_t __write_ports_names(char *buf) | 650 | static ssize_t __write_ports_names(char *buf, struct net *net) |
| 649 | { | 651 | { |
| 650 | if (nfsd_serv == NULL) | 652 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); |
| 653 | |||
| 654 | if (nn->nfsd_serv == NULL) | ||
| 651 | return 0; | 655 | return 0; |
| 652 | return svc_xprt_names(nfsd_serv, buf, SIMPLE_TRANSACTION_LIMIT); | 656 | return svc_xprt_names(nn->nfsd_serv, buf, SIMPLE_TRANSACTION_LIMIT); |
| 653 | } | 657 | } |
| 654 | 658 | ||
| 655 | /* | 659 | /* |
| @@ -657,28 +661,28 @@ static ssize_t __write_ports_names(char *buf) | |||
| 657 | * a socket of a supported family/protocol, and we use it as an | 661 | * a socket of a supported family/protocol, and we use it as an |
| 658 | * nfsd listener. | 662 | * nfsd listener. |
| 659 | */ | 663 | */ |
| 660 | static ssize_t __write_ports_addfd(char *buf) | 664 | static ssize_t __write_ports_addfd(char *buf, struct net *net) |
| 661 | { | 665 | { |
| 662 | char *mesg = buf; | 666 | char *mesg = buf; |
| 663 | int fd, err; | 667 | int fd, err; |
| 664 | struct net *net = &init_net; | 668 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); |
| 665 | 669 | ||
| 666 | err = get_int(&mesg, &fd); | 670 | err = get_int(&mesg, &fd); |
| 667 | if (err != 0 || fd < 0) | 671 | if (err != 0 || fd < 0) |
| 668 | return -EINVAL; | 672 | return -EINVAL; |
| 669 | 673 | ||
| 670 | err = nfsd_create_serv(); | 674 | err = nfsd_create_serv(net); |
| 671 | if (err != 0) | 675 | if (err != 0) |
| 672 | return err; | 676 | return err; |
| 673 | 677 | ||
| 674 | err = svc_addsock(nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT); | 678 | err = svc_addsock(nn->nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT); |
| 675 | if (err < 0) { | 679 | if (err < 0) { |
| 676 | nfsd_destroy(net); | 680 | nfsd_destroy(net); |
| 677 | return err; | 681 | return err; |
| 678 | } | 682 | } |
| 679 | 683 | ||
| 680 | /* Decrease the count, but don't shut down the service */ | 684 | /* Decrease the count, but don't shut down the service */ |
| 681 | nfsd_serv->sv_nrthreads--; | 685 | nn->nfsd_serv->sv_nrthreads--; |
| 682 | return err; | 686 | return err; |
| 683 | } | 687 | } |
| 684 | 688 | ||
| @@ -686,12 +690,12 @@ static ssize_t __write_ports_addfd(char *buf) | |||
| 686 | * A transport listener is added by writing it's transport name and | 690 | * A transport listener is added by writing it's transport name and |
| 687 | * a port number. | 691 | * a port number. |
| 688 | */ | 692 | */ |
| 689 | static ssize_t __write_ports_addxprt(char *buf) | 693 | static ssize_t __write_ports_addxprt(char *buf, struct net *net) |
| 690 | { | 694 | { |
| 691 | char transport[16]; | 695 | char transport[16]; |
| 692 | struct svc_xprt *xprt; | 696 | struct svc_xprt *xprt; |
| 693 | int port, err; | 697 | int port, err; |
| 694 | struct net *net = &init_net; | 698 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); |
| 695 | 699 | ||
| 696 | if (sscanf(buf, "%15s %5u", transport, &port) != 2) | 700 | if (sscanf(buf, "%15s %5u", transport, &port) != 2) |
| 697 | return -EINVAL; | 701 | return -EINVAL; |
| @@ -699,25 +703,25 @@ static ssize_t __write_ports_addxprt(char *buf) | |||
| 699 | if (port < 1 || port > USHRT_MAX) | 703 | if (port < 1 || port > USHRT_MAX) |
| 700 | return -EINVAL; | 704 | return -EINVAL; |
| 701 | 705 | ||
| 702 | err = nfsd_create_serv(); | 706 | err = nfsd_create_serv(net); |
| 703 | if (err != 0) | 707 | if (err != 0) |
| 704 | return err; | 708 | return err; |
| 705 | 709 | ||
| 706 | err = svc_create_xprt(nfsd_serv, transport, net, | 710 | err = svc_create_xprt(nn->nfsd_serv, transport, net, |
| 707 | PF_INET, port, SVC_SOCK_ANONYMOUS); | 711 | PF_INET, port, SVC_SOCK_ANONYMOUS); |
| 708 | if (err < 0) | 712 | if (err < 0) |
| 709 | goto out_err; | 713 | goto out_err; |
| 710 | 714 | ||
| 711 | err = svc_create_xprt(nfsd_serv, transport, net, | 715 | err = svc_create_xprt(nn->nfsd_serv, transport, net, |
| 712 | PF_INET6, port, SVC_SOCK_ANONYMOUS); | 716 | PF_INET6, port, SVC_SOCK_ANONYMOUS); |
| 713 | if (err < 0 && err != -EAFNOSUPPORT) | 717 | if (err < 0 && err != -EAFNOSUPPORT) |
| 714 | goto out_close; | 718 | goto out_close; |
| 715 | 719 | ||
| 716 | /* Decrease the count, but don't shut down the service */ | 720 | /* Decrease the count, but don't shut down the service */ |
| 717 | nfsd_serv->sv_nrthreads--; | 721 | nn->nfsd_serv->sv_nrthreads--; |
| 718 | return 0; | 722 | return 0; |
| 719 | out_close: | 723 | out_close: |
| 720 | xprt = svc_find_xprt(nfsd_serv, transport, net, PF_INET, port); | 724 | xprt = svc_find_xprt(nn->nfsd_serv, transport, net, PF_INET, port); |
| 721 | if (xprt != NULL) { | 725 | if (xprt != NULL) { |
| 722 | svc_close_xprt(xprt); | 726 | svc_close_xprt(xprt); |
| 723 | svc_xprt_put(xprt); | 727 | svc_xprt_put(xprt); |
| @@ -727,16 +731,17 @@ out_err: | |||
| 727 | return err; | 731 | return err; |
| 728 | } | 732 | } |
| 729 | 733 | ||
| 730 | static ssize_t __write_ports(struct file *file, char *buf, size_t size) | 734 | static ssize_t __write_ports(struct file *file, char *buf, size_t size, |
| 735 | struct net *net) | ||
| 731 | { | 736 | { |
| 732 | if (size == 0) | 737 | if (size == 0) |
| 733 | return __write_ports_names(buf); | 738 | return __write_ports_names(buf, net); |
| 734 | 739 | ||
| 735 | if (isdigit(buf[0])) | 740 | if (isdigit(buf[0])) |
| 736 | return __write_ports_addfd(buf); | 741 | return __write_ports_addfd(buf, net); |
| 737 | 742 | ||
| 738 | if (isalpha(buf[0])) | 743 | if (isalpha(buf[0])) |
| 739 | return __write_ports_addxprt(buf); | 744 | return __write_ports_addxprt(buf, net); |
| 740 | 745 | ||
| 741 | return -EINVAL; | 746 | return -EINVAL; |
| 742 | } | 747 | } |
| @@ -787,9 +792,10 @@ static ssize_t __write_ports(struct file *file, char *buf, size_t size) | |||
| 787 | static ssize_t write_ports(struct file *file, char *buf, size_t size) | 792 | static ssize_t write_ports(struct file *file, char *buf, size_t size) |
| 788 | { | 793 | { |
| 789 | ssize_t rv; | 794 | ssize_t rv; |
| 795 | struct net *net = &init_net; | ||
| 790 | 796 | ||
| 791 | mutex_lock(&nfsd_mutex); | 797 | mutex_lock(&nfsd_mutex); |
| 792 | rv = __write_ports(file, buf, size); | 798 | rv = __write_ports(file, buf, size, net); |
| 793 | mutex_unlock(&nfsd_mutex); | 799 | mutex_unlock(&nfsd_mutex); |
| 794 | return rv; | 800 | return rv; |
| 795 | } | 801 | } |
| @@ -821,6 +827,9 @@ int nfsd_max_blksize; | |||
| 821 | static ssize_t write_maxblksize(struct file *file, char *buf, size_t size) | 827 | static ssize_t write_maxblksize(struct file *file, char *buf, size_t size) |
| 822 | { | 828 | { |
| 823 | char *mesg = buf; | 829 | char *mesg = buf; |
| 830 | struct net *net = &init_net; | ||
| 831 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
| 832 | |||
| 824 | if (size > 0) { | 833 | if (size > 0) { |
| 825 | int bsize; | 834 | int bsize; |
| 826 | int rv = get_int(&mesg, &bsize); | 835 | int rv = get_int(&mesg, &bsize); |
| @@ -835,7 +844,7 @@ static ssize_t write_maxblksize(struct file *file, char *buf, size_t size) | |||
| 835 | bsize = NFSSVC_MAXBLKSIZE; | 844 | bsize = NFSSVC_MAXBLKSIZE; |
| 836 | bsize &= ~(1024-1); | 845 | bsize &= ~(1024-1); |
| 837 | mutex_lock(&nfsd_mutex); | 846 | mutex_lock(&nfsd_mutex); |
| 838 | if (nfsd_serv) { | 847 | if (nn->nfsd_serv) { |
| 839 | mutex_unlock(&nfsd_mutex); | 848 | mutex_unlock(&nfsd_mutex); |
| 840 | return -EBUSY; | 849 | return -EBUSY; |
| 841 | } | 850 | } |
| @@ -848,13 +857,14 @@ static ssize_t write_maxblksize(struct file *file, char *buf, size_t size) | |||
| 848 | } | 857 | } |
| 849 | 858 | ||
| 850 | #ifdef CONFIG_NFSD_V4 | 859 | #ifdef CONFIG_NFSD_V4 |
| 851 | static ssize_t __nfsd4_write_time(struct file *file, char *buf, size_t size, time_t *time) | 860 | static ssize_t __nfsd4_write_time(struct file *file, char *buf, size_t size, |
| 861 | time_t *time, struct nfsd_net *nn) | ||
| 852 | { | 862 | { |
| 853 | char *mesg = buf; | 863 | char *mesg = buf; |
| 854 | int rv, i; | 864 | int rv, i; |
| 855 | 865 | ||
| 856 | if (size > 0) { | 866 | if (size > 0) { |
| 857 | if (nfsd_serv) | 867 | if (nn->nfsd_serv) |
| 858 | return -EBUSY; | 868 | return -EBUSY; |
| 859 | rv = get_int(&mesg, &i); | 869 | rv = get_int(&mesg, &i); |
| 860 | if (rv) | 870 | if (rv) |
| @@ -879,12 +889,13 @@ static ssize_t __nfsd4_write_time(struct file *file, char *buf, size_t size, tim | |||
| 879 | return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%ld\n", *time); | 889 | return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%ld\n", *time); |
| 880 | } | 890 | } |
| 881 | 891 | ||
| 882 | static ssize_t nfsd4_write_time(struct file *file, char *buf, size_t size, time_t *time) | 892 | static ssize_t nfsd4_write_time(struct file *file, char *buf, size_t size, |
| 893 | time_t *time, struct nfsd_net *nn) | ||
| 883 | { | 894 | { |
| 884 | ssize_t rv; | 895 | ssize_t rv; |
| 885 | 896 | ||
| 886 | mutex_lock(&nfsd_mutex); | 897 | mutex_lock(&nfsd_mutex); |
| 887 | rv = __nfsd4_write_time(file, buf, size, time); | 898 | rv = __nfsd4_write_time(file, buf, size, time, nn); |
| 888 | mutex_unlock(&nfsd_mutex); | 899 | mutex_unlock(&nfsd_mutex); |
| 889 | return rv; | 900 | return rv; |
| 890 | } | 901 | } |
| @@ -912,7 +923,8 @@ static ssize_t nfsd4_write_time(struct file *file, char *buf, size_t size, time_ | |||
| 912 | */ | 923 | */ |
| 913 | static ssize_t write_leasetime(struct file *file, char *buf, size_t size) | 924 | static ssize_t write_leasetime(struct file *file, char *buf, size_t size) |
| 914 | { | 925 | { |
| 915 | return nfsd4_write_time(file, buf, size, &nfsd4_lease); | 926 | struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); |
| 927 | return nfsd4_write_time(file, buf, size, &nn->nfsd4_lease, nn); | ||
| 916 | } | 928 | } |
| 917 | 929 | ||
| 918 | /** | 930 | /** |
| @@ -927,17 +939,19 @@ static ssize_t write_leasetime(struct file *file, char *buf, size_t size) | |||
| 927 | */ | 939 | */ |
| 928 | static ssize_t write_gracetime(struct file *file, char *buf, size_t size) | 940 | static ssize_t write_gracetime(struct file *file, char *buf, size_t size) |
| 929 | { | 941 | { |
| 930 | return nfsd4_write_time(file, buf, size, &nfsd4_grace); | 942 | struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); |
| 943 | return nfsd4_write_time(file, buf, size, &nn->nfsd4_grace, nn); | ||
| 931 | } | 944 | } |
| 932 | 945 | ||
| 933 | static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size) | 946 | static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size, |
| 947 | struct nfsd_net *nn) | ||
| 934 | { | 948 | { |
| 935 | char *mesg = buf; | 949 | char *mesg = buf; |
| 936 | char *recdir; | 950 | char *recdir; |
| 937 | int len, status; | 951 | int len, status; |
| 938 | 952 | ||
| 939 | if (size > 0) { | 953 | if (size > 0) { |
| 940 | if (nfsd_serv) | 954 | if (nn->nfsd_serv) |
| 941 | return -EBUSY; | 955 | return -EBUSY; |
| 942 | if (size > PATH_MAX || buf[size-1] != '\n') | 956 | if (size > PATH_MAX || buf[size-1] != '\n') |
| 943 | return -EINVAL; | 957 | return -EINVAL; |
| @@ -981,9 +995,10 @@ static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size) | |||
| 981 | static ssize_t write_recoverydir(struct file *file, char *buf, size_t size) | 995 | static ssize_t write_recoverydir(struct file *file, char *buf, size_t size) |
| 982 | { | 996 | { |
| 983 | ssize_t rv; | 997 | ssize_t rv; |
| 998 | struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); | ||
| 984 | 999 | ||
| 985 | mutex_lock(&nfsd_mutex); | 1000 | mutex_lock(&nfsd_mutex); |
| 986 | rv = __write_recoverydir(file, buf, size); | 1001 | rv = __write_recoverydir(file, buf, size, nn); |
| 987 | mutex_unlock(&nfsd_mutex); | 1002 | mutex_unlock(&nfsd_mutex); |
| 988 | return rv; | 1003 | return rv; |
| 989 | } | 1004 | } |
| @@ -1063,6 +1078,7 @@ int nfsd_net_id; | |||
| 1063 | static __net_init int nfsd_init_net(struct net *net) | 1078 | static __net_init int nfsd_init_net(struct net *net) |
| 1064 | { | 1079 | { |
| 1065 | int retval; | 1080 | int retval; |
| 1081 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
| 1066 | 1082 | ||
| 1067 | retval = nfsd_export_init(net); | 1083 | retval = nfsd_export_init(net); |
| 1068 | if (retval) | 1084 | if (retval) |
| @@ -1070,6 +1086,8 @@ static __net_init int nfsd_init_net(struct net *net) | |||
| 1070 | retval = nfsd_idmap_init(net); | 1086 | retval = nfsd_idmap_init(net); |
| 1071 | if (retval) | 1087 | if (retval) |
| 1072 | goto out_idmap_error; | 1088 | goto out_idmap_error; |
| 1089 | nn->nfsd4_lease = 90; /* default lease time */ | ||
| 1090 | nn->nfsd4_grace = 90; | ||
| 1073 | return 0; | 1091 | return 0; |
| 1074 | 1092 | ||
| 1075 | out_idmap_error: | 1093 | out_idmap_error: |
diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h index 80d5ce40aadb..de23db255c69 100644 --- a/fs/nfsd/nfsd.h +++ b/fs/nfsd/nfsd.h | |||
| @@ -55,7 +55,6 @@ extern struct svc_version nfsd_version2, nfsd_version3, | |||
| 55 | nfsd_version4; | 55 | nfsd_version4; |
| 56 | extern u32 nfsd_supported_minorversion; | 56 | extern u32 nfsd_supported_minorversion; |
| 57 | extern struct mutex nfsd_mutex; | 57 | extern struct mutex nfsd_mutex; |
| 58 | extern struct svc_serv *nfsd_serv; | ||
| 59 | extern spinlock_t nfsd_drc_lock; | 58 | extern spinlock_t nfsd_drc_lock; |
| 60 | extern unsigned int nfsd_drc_max_mem; | 59 | extern unsigned int nfsd_drc_max_mem; |
| 61 | extern unsigned int nfsd_drc_mem_used; | 60 | extern unsigned int nfsd_drc_mem_used; |
| @@ -65,26 +64,17 @@ extern const struct seq_operations nfs_exports_op; | |||
| 65 | /* | 64 | /* |
| 66 | * Function prototypes. | 65 | * Function prototypes. |
| 67 | */ | 66 | */ |
| 68 | int nfsd_svc(int nrservs); | 67 | int nfsd_svc(int nrservs, struct net *net); |
| 69 | int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp); | 68 | int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp); |
| 70 | 69 | ||
| 71 | int nfsd_nrthreads(void); | 70 | int nfsd_nrthreads(struct net *); |
| 72 | int nfsd_nrpools(void); | 71 | int nfsd_nrpools(struct net *); |
| 73 | int nfsd_get_nrthreads(int n, int *); | 72 | int nfsd_get_nrthreads(int n, int *, struct net *); |
| 74 | int nfsd_set_nrthreads(int n, int *); | 73 | int nfsd_set_nrthreads(int n, int *, struct net *); |
| 75 | int nfsd_pool_stats_open(struct inode *, struct file *); | 74 | int nfsd_pool_stats_open(struct inode *, struct file *); |
| 76 | int nfsd_pool_stats_release(struct inode *, struct file *); | 75 | int nfsd_pool_stats_release(struct inode *, struct file *); |
| 77 | 76 | ||
| 78 | static inline void nfsd_destroy(struct net *net) | 77 | void nfsd_destroy(struct net *net); |
| 79 | { | ||
| 80 | int destroy = (nfsd_serv->sv_nrthreads == 1); | ||
| 81 | |||
| 82 | if (destroy) | ||
| 83 | svc_shutdown_net(nfsd_serv, net); | ||
| 84 | svc_destroy(nfsd_serv); | ||
| 85 | if (destroy) | ||
| 86 | nfsd_serv = NULL; | ||
| 87 | } | ||
| 88 | 78 | ||
| 89 | #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) | 79 | #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) |
| 90 | #ifdef CONFIG_NFSD_V2_ACL | 80 | #ifdef CONFIG_NFSD_V2_ACL |
| @@ -103,7 +93,7 @@ enum vers_op {NFSD_SET, NFSD_CLEAR, NFSD_TEST, NFSD_AVAIL }; | |||
| 103 | int nfsd_vers(int vers, enum vers_op change); | 93 | int nfsd_vers(int vers, enum vers_op change); |
| 104 | int nfsd_minorversion(u32 minorversion, enum vers_op change); | 94 | int nfsd_minorversion(u32 minorversion, enum vers_op change); |
| 105 | void nfsd_reset_versions(void); | 95 | void nfsd_reset_versions(void); |
| 106 | int nfsd_create_serv(void); | 96 | int nfsd_create_serv(struct net *net); |
| 107 | 97 | ||
| 108 | extern int nfsd_max_blksize; | 98 | extern int nfsd_max_blksize; |
| 109 | 99 | ||
| @@ -121,7 +111,9 @@ void nfs4_state_init(void); | |||
| 121 | int nfsd4_init_slabs(void); | 111 | int nfsd4_init_slabs(void); |
| 122 | void nfsd4_free_slabs(void); | 112 | void nfsd4_free_slabs(void); |
| 123 | int nfs4_state_start(void); | 113 | int nfs4_state_start(void); |
| 114 | int nfs4_state_start_net(struct net *net); | ||
| 124 | void nfs4_state_shutdown(void); | 115 | void nfs4_state_shutdown(void); |
| 116 | void nfs4_state_shutdown_net(struct net *net); | ||
| 125 | void nfs4_reset_lease(time_t leasetime); | 117 | void nfs4_reset_lease(time_t leasetime); |
| 126 | int nfs4_reset_recoverydir(char *recdir); | 118 | int nfs4_reset_recoverydir(char *recdir); |
| 127 | char * nfs4_recoverydir(void); | 119 | char * nfs4_recoverydir(void); |
| @@ -130,7 +122,9 @@ static inline void nfs4_state_init(void) { } | |||
| 130 | static inline int nfsd4_init_slabs(void) { return 0; } | 122 | static inline int nfsd4_init_slabs(void) { return 0; } |
| 131 | static inline void nfsd4_free_slabs(void) { } | 123 | static inline void nfsd4_free_slabs(void) { } |
| 132 | static inline int nfs4_state_start(void) { return 0; } | 124 | static inline int nfs4_state_start(void) { return 0; } |
| 125 | static inline int nfs4_state_start_net(struct net *net) { return 0; } | ||
| 133 | static inline void nfs4_state_shutdown(void) { } | 126 | static inline void nfs4_state_shutdown(void) { } |
| 127 | static inline void nfs4_state_shutdown_net(struct net *net) { } | ||
| 134 | static inline void nfs4_reset_lease(time_t leasetime) { } | 128 | static inline void nfs4_reset_lease(time_t leasetime) { } |
| 135 | static inline int nfs4_reset_recoverydir(char *recdir) { return 0; } | 129 | static inline int nfs4_reset_recoverydir(char *recdir) { return 0; } |
| 136 | static inline char * nfs4_recoverydir(void) {return NULL; } | 130 | static inline char * nfs4_recoverydir(void) {return NULL; } |
| @@ -265,16 +259,8 @@ void nfsd_lockd_shutdown(void); | |||
| 265 | /* Check for dir entries '.' and '..' */ | 259 | /* Check for dir entries '.' and '..' */ |
| 266 | #define isdotent(n, l) (l < 3 && n[0] == '.' && (l == 1 || n[1] == '.')) | 260 | #define isdotent(n, l) (l < 3 && n[0] == '.' && (l == 1 || n[1] == '.')) |
| 267 | 261 | ||
| 268 | /* | ||
| 269 | * Time of server startup | ||
| 270 | */ | ||
| 271 | extern struct timeval nfssvc_boot; | ||
| 272 | |||
| 273 | #ifdef CONFIG_NFSD_V4 | 262 | #ifdef CONFIG_NFSD_V4 |
| 274 | 263 | ||
| 275 | extern time_t nfsd4_lease; | ||
| 276 | extern time_t nfsd4_grace; | ||
| 277 | |||
| 278 | /* before processing a COMPOUND operation, we have to check that there | 264 | /* before processing a COMPOUND operation, we have to check that there |
| 279 | * is enough space in the buffer for XDR encode to succeed. otherwise, | 265 | * is enough space in the buffer for XDR encode to succeed. otherwise, |
| 280 | * we might process an operation with side effects, and be unable to | 266 | * we might process an operation with side effects, and be unable to |
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index 032af381b3aa..814afaa4458a 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c | |||
| @@ -572,7 +572,7 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, | |||
| 572 | 572 | ||
| 573 | if (inode) | 573 | if (inode) |
| 574 | _fh_update(fhp, exp, dentry); | 574 | _fh_update(fhp, exp, dentry); |
| 575 | if (fhp->fh_handle.fh_fileid_type == 255) { | 575 | if (fhp->fh_handle.fh_fileid_type == FILEID_INVALID) { |
| 576 | fh_put(fhp); | 576 | fh_put(fhp); |
| 577 | return nfserr_opnotsupp; | 577 | return nfserr_opnotsupp; |
| 578 | } | 578 | } |
| @@ -603,7 +603,7 @@ fh_update(struct svc_fh *fhp) | |||
| 603 | goto out; | 603 | goto out; |
| 604 | 604 | ||
| 605 | _fh_update(fhp, fhp->fh_export, dentry); | 605 | _fh_update(fhp, fhp->fh_export, dentry); |
| 606 | if (fhp->fh_handle.fh_fileid_type == 255) | 606 | if (fhp->fh_handle.fh_fileid_type == FILEID_INVALID) |
| 607 | return nfserr_opnotsupp; | 607 | return nfserr_opnotsupp; |
| 608 | } | 608 | } |
| 609 | out: | 609 | out: |
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 2013aa001dab..cee62ab9d4a3 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c | |||
| @@ -11,7 +11,6 @@ | |||
| 11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
| 12 | #include <linux/fs_struct.h> | 12 | #include <linux/fs_struct.h> |
| 13 | #include <linux/swap.h> | 13 | #include <linux/swap.h> |
| 14 | #include <linux/nsproxy.h> | ||
| 15 | 14 | ||
| 16 | #include <linux/sunrpc/stats.h> | 15 | #include <linux/sunrpc/stats.h> |
| 17 | #include <linux/sunrpc/svcsock.h> | 16 | #include <linux/sunrpc/svcsock.h> |
| @@ -22,19 +21,19 @@ | |||
| 22 | #include "nfsd.h" | 21 | #include "nfsd.h" |
| 23 | #include "cache.h" | 22 | #include "cache.h" |
| 24 | #include "vfs.h" | 23 | #include "vfs.h" |
| 24 | #include "netns.h" | ||
| 25 | 25 | ||
| 26 | #define NFSDDBG_FACILITY NFSDDBG_SVC | 26 | #define NFSDDBG_FACILITY NFSDDBG_SVC |
| 27 | 27 | ||
| 28 | extern struct svc_program nfsd_program; | 28 | extern struct svc_program nfsd_program; |
| 29 | static int nfsd(void *vrqstp); | 29 | static int nfsd(void *vrqstp); |
| 30 | struct timeval nfssvc_boot; | ||
| 31 | 30 | ||
| 32 | /* | 31 | /* |
| 33 | * nfsd_mutex protects nfsd_serv -- both the pointer itself and the members | 32 | * nfsd_mutex protects nn->nfsd_serv -- both the pointer itself and the members |
| 34 | * of the svc_serv struct. In particular, ->sv_nrthreads but also to some | 33 | * of the svc_serv struct. In particular, ->sv_nrthreads but also to some |
| 35 | * extent ->sv_temp_socks and ->sv_permsocks. It also protects nfsdstats.th_cnt | 34 | * extent ->sv_temp_socks and ->sv_permsocks. It also protects nfsdstats.th_cnt |
| 36 | * | 35 | * |
| 37 | * If (out side the lock) nfsd_serv is non-NULL, then it must point to a | 36 | * If (out side the lock) nn->nfsd_serv is non-NULL, then it must point to a |
| 38 | * properly initialised 'struct svc_serv' with ->sv_nrthreads > 0. That number | 37 | * properly initialised 'struct svc_serv' with ->sv_nrthreads > 0. That number |
| 39 | * of nfsd threads must exist and each must listed in ->sp_all_threads in each | 38 | * of nfsd threads must exist and each must listed in ->sp_all_threads in each |
| 40 | * entry of ->sv_pools[]. | 39 | * entry of ->sv_pools[]. |
| @@ -52,7 +51,6 @@ struct timeval nfssvc_boot; | |||
| 52 | * nfsd_versions | 51 | * nfsd_versions |
| 53 | */ | 52 | */ |
| 54 | DEFINE_MUTEX(nfsd_mutex); | 53 | DEFINE_MUTEX(nfsd_mutex); |
| 55 | struct svc_serv *nfsd_serv; | ||
| 56 | 54 | ||
| 57 | /* | 55 | /* |
| 58 | * nfsd_drc_lock protects nfsd_drc_max_pages and nfsd_drc_pages_used. | 56 | * 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) | |||
| 173 | */ | 171 | */ |
| 174 | #define NFSD_MAXSERVS 8192 | 172 | #define NFSD_MAXSERVS 8192 |
| 175 | 173 | ||
| 176 | int nfsd_nrthreads(void) | 174 | int nfsd_nrthreads(struct net *net) |
| 177 | { | 175 | { |
| 178 | int rv = 0; | 176 | int rv = 0; |
| 177 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
| 178 | |||
| 179 | mutex_lock(&nfsd_mutex); | 179 | mutex_lock(&nfsd_mutex); |
| 180 | if (nfsd_serv) | 180 | if (nn->nfsd_serv) |
| 181 | rv = nfsd_serv->sv_nrthreads; | 181 | rv = nn->nfsd_serv->sv_nrthreads; |
| 182 | mutex_unlock(&nfsd_mutex); | 182 | mutex_unlock(&nfsd_mutex); |
| 183 | return rv; | 183 | return rv; |
| 184 | } | 184 | } |
| 185 | 185 | ||
| 186 | static int nfsd_init_socks(void) | 186 | static int nfsd_init_socks(struct net *net) |
| 187 | { | 187 | { |
| 188 | int error; | 188 | int error; |
| 189 | if (!list_empty(&nfsd_serv->sv_permsocks)) | 189 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); |
| 190 | |||
| 191 | if (!list_empty(&nn->nfsd_serv->sv_permsocks)) | ||
| 190 | return 0; | 192 | return 0; |
| 191 | 193 | ||
| 192 | error = svc_create_xprt(nfsd_serv, "udp", &init_net, PF_INET, NFS_PORT, | 194 | error = svc_create_xprt(nn->nfsd_serv, "udp", net, PF_INET, NFS_PORT, |
| 193 | SVC_SOCK_DEFAULTS); | 195 | SVC_SOCK_DEFAULTS); |
| 194 | if (error < 0) | 196 | if (error < 0) |
| 195 | return error; | 197 | return error; |
| 196 | 198 | ||
| 197 | error = svc_create_xprt(nfsd_serv, "tcp", &init_net, PF_INET, NFS_PORT, | 199 | error = svc_create_xprt(nn->nfsd_serv, "tcp", net, PF_INET, NFS_PORT, |
| 198 | SVC_SOCK_DEFAULTS); | 200 | SVC_SOCK_DEFAULTS); |
| 199 | if (error < 0) | 201 | if (error < 0) |
| 200 | return error; | 202 | return error; |
| @@ -202,14 +204,15 @@ static int nfsd_init_socks(void) | |||
| 202 | return 0; | 204 | return 0; |
| 203 | } | 205 | } |
| 204 | 206 | ||
| 205 | static bool nfsd_up = false; | 207 | static int nfsd_users = 0; |
| 206 | 208 | ||
| 207 | static int nfsd_startup(int nrservs) | 209 | static int nfsd_startup_generic(int nrservs) |
| 208 | { | 210 | { |
| 209 | int ret; | 211 | int ret; |
| 210 | 212 | ||
| 211 | if (nfsd_up) | 213 | if (nfsd_users++) |
| 212 | return 0; | 214 | return 0; |
| 215 | |||
| 213 | /* | 216 | /* |
| 214 | * Readahead param cache - will no-op if it already exists. | 217 | * Readahead param cache - will no-op if it already exists. |
| 215 | * (Note therefore results will be suboptimal if number of | 218 | * (Note therefore results will be suboptimal if number of |
| @@ -218,43 +221,79 @@ static int nfsd_startup(int nrservs) | |||
| 218 | ret = nfsd_racache_init(2*nrservs); | 221 | ret = nfsd_racache_init(2*nrservs); |
| 219 | if (ret) | 222 | if (ret) |
| 220 | return ret; | 223 | return ret; |
| 221 | ret = nfsd_init_socks(); | 224 | ret = nfs4_state_start(); |
| 222 | if (ret) | 225 | if (ret) |
| 223 | goto out_racache; | 226 | goto out_racache; |
| 224 | ret = lockd_up(&init_net); | 227 | return 0; |
| 228 | |||
| 229 | out_racache: | ||
| 230 | nfsd_racache_shutdown(); | ||
| 231 | return ret; | ||
| 232 | } | ||
| 233 | |||
| 234 | static void nfsd_shutdown_generic(void) | ||
| 235 | { | ||
| 236 | if (--nfsd_users) | ||
| 237 | return; | ||
| 238 | |||
| 239 | nfs4_state_shutdown(); | ||
| 240 | nfsd_racache_shutdown(); | ||
| 241 | } | ||
| 242 | |||
| 243 | static int nfsd_startup_net(int nrservs, struct net *net) | ||
| 244 | { | ||
| 245 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
| 246 | int ret; | ||
| 247 | |||
| 248 | if (nn->nfsd_net_up) | ||
| 249 | return 0; | ||
| 250 | |||
| 251 | ret = nfsd_startup_generic(nrservs); | ||
| 225 | if (ret) | 252 | if (ret) |
| 226 | goto out_racache; | 253 | return ret; |
| 227 | ret = nfs4_state_start(); | 254 | ret = nfsd_init_socks(net); |
| 255 | if (ret) | ||
| 256 | goto out_socks; | ||
| 257 | ret = lockd_up(net); | ||
| 258 | if (ret) | ||
| 259 | goto out_socks; | ||
| 260 | ret = nfs4_state_start_net(net); | ||
| 228 | if (ret) | 261 | if (ret) |
| 229 | goto out_lockd; | 262 | goto out_lockd; |
| 230 | nfsd_up = true; | 263 | |
| 264 | nn->nfsd_net_up = true; | ||
| 231 | return 0; | 265 | return 0; |
| 266 | |||
| 232 | out_lockd: | 267 | out_lockd: |
| 233 | lockd_down(&init_net); | 268 | lockd_down(net); |
| 234 | out_racache: | 269 | out_socks: |
| 235 | nfsd_racache_shutdown(); | 270 | nfsd_shutdown_generic(); |
| 236 | return ret; | 271 | return ret; |
| 237 | } | 272 | } |
| 238 | 273 | ||
| 239 | static void nfsd_shutdown(void) | 274 | static void nfsd_shutdown_net(struct net *net) |
| 240 | { | 275 | { |
| 276 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
| 277 | |||
| 278 | nfs4_state_shutdown_net(net); | ||
| 279 | lockd_down(net); | ||
| 280 | nn->nfsd_net_up = false; | ||
| 281 | nfsd_shutdown_generic(); | ||
| 282 | } | ||
| 283 | |||
| 284 | static void nfsd_last_thread(struct svc_serv *serv, struct net *net) | ||
| 285 | { | ||
| 286 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
| 287 | |||
| 241 | /* | 288 | /* |
| 242 | * write_ports can create the server without actually starting | 289 | * write_ports can create the server without actually starting |
| 243 | * any threads--if we get shut down before any threads are | 290 | * any threads--if we get shut down before any threads are |
| 244 | * started, then nfsd_last_thread will be run before any of this | 291 | * started, then nfsd_last_thread will be run before any of this |
| 245 | * other initialization has been done. | 292 | * other initialization has been done. |
| 246 | */ | 293 | */ |
| 247 | if (!nfsd_up) | 294 | if (!nn->nfsd_net_up) |
| 248 | return; | 295 | return; |
| 249 | nfs4_state_shutdown(); | 296 | nfsd_shutdown_net(net); |
| 250 | lockd_down(&init_net); | ||
| 251 | nfsd_racache_shutdown(); | ||
| 252 | nfsd_up = false; | ||
| 253 | } | ||
| 254 | |||
| 255 | static void nfsd_last_thread(struct svc_serv *serv, struct net *net) | ||
| 256 | { | ||
| 257 | nfsd_shutdown(); | ||
| 258 | 297 | ||
| 259 | svc_rpcb_cleanup(serv, net); | 298 | svc_rpcb_cleanup(serv, net); |
| 260 | 299 | ||
| @@ -327,69 +366,84 @@ static int nfsd_get_default_max_blksize(void) | |||
| 327 | return ret; | 366 | return ret; |
| 328 | } | 367 | } |
| 329 | 368 | ||
| 330 | int nfsd_create_serv(void) | 369 | int nfsd_create_serv(struct net *net) |
| 331 | { | 370 | { |
| 332 | int error; | 371 | int error; |
| 333 | struct net *net = current->nsproxy->net_ns; | 372 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); |
| 334 | 373 | ||
| 335 | WARN_ON(!mutex_is_locked(&nfsd_mutex)); | 374 | WARN_ON(!mutex_is_locked(&nfsd_mutex)); |
| 336 | if (nfsd_serv) { | 375 | if (nn->nfsd_serv) { |
| 337 | svc_get(nfsd_serv); | 376 | svc_get(nn->nfsd_serv); |
| 338 | return 0; | 377 | return 0; |
| 339 | } | 378 | } |
| 340 | if (nfsd_max_blksize == 0) | 379 | if (nfsd_max_blksize == 0) |
| 341 | nfsd_max_blksize = nfsd_get_default_max_blksize(); | 380 | nfsd_max_blksize = nfsd_get_default_max_blksize(); |
| 342 | nfsd_reset_versions(); | 381 | nfsd_reset_versions(); |
| 343 | nfsd_serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize, | 382 | nn->nfsd_serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize, |
| 344 | nfsd_last_thread, nfsd, THIS_MODULE); | 383 | nfsd_last_thread, nfsd, THIS_MODULE); |
| 345 | if (nfsd_serv == NULL) | 384 | if (nn->nfsd_serv == NULL) |
| 346 | return -ENOMEM; | 385 | return -ENOMEM; |
| 347 | 386 | ||
| 348 | error = svc_bind(nfsd_serv, net); | 387 | error = svc_bind(nn->nfsd_serv, net); |
| 349 | if (error < 0) { | 388 | if (error < 0) { |
| 350 | svc_destroy(nfsd_serv); | 389 | svc_destroy(nn->nfsd_serv); |
| 351 | return error; | 390 | return error; |
| 352 | } | 391 | } |
| 353 | 392 | ||
| 354 | set_max_drc(); | 393 | set_max_drc(); |
| 355 | do_gettimeofday(&nfssvc_boot); /* record boot time */ | 394 | do_gettimeofday(&nn->nfssvc_boot); /* record boot time */ |
| 356 | return 0; | 395 | return 0; |
| 357 | } | 396 | } |
| 358 | 397 | ||
| 359 | int nfsd_nrpools(void) | 398 | int nfsd_nrpools(struct net *net) |
| 360 | { | 399 | { |
| 361 | if (nfsd_serv == NULL) | 400 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); |
| 401 | |||
| 402 | if (nn->nfsd_serv == NULL) | ||
| 362 | return 0; | 403 | return 0; |
| 363 | else | 404 | else |
| 364 | return nfsd_serv->sv_nrpools; | 405 | return nn->nfsd_serv->sv_nrpools; |
| 365 | } | 406 | } |
| 366 | 407 | ||
| 367 | int nfsd_get_nrthreads(int n, int *nthreads) | 408 | int nfsd_get_nrthreads(int n, int *nthreads, struct net *net) |
| 368 | { | 409 | { |
| 369 | int i = 0; | 410 | int i = 0; |
| 411 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
| 370 | 412 | ||
| 371 | if (nfsd_serv != NULL) { | 413 | if (nn->nfsd_serv != NULL) { |
| 372 | for (i = 0; i < nfsd_serv->sv_nrpools && i < n; i++) | 414 | for (i = 0; i < nn->nfsd_serv->sv_nrpools && i < n; i++) |
| 373 | nthreads[i] = nfsd_serv->sv_pools[i].sp_nrthreads; | 415 | nthreads[i] = nn->nfsd_serv->sv_pools[i].sp_nrthreads; |
| 374 | } | 416 | } |
| 375 | 417 | ||
| 376 | return 0; | 418 | return 0; |
| 377 | } | 419 | } |
| 378 | 420 | ||
| 379 | int nfsd_set_nrthreads(int n, int *nthreads) | 421 | void nfsd_destroy(struct net *net) |
| 422 | { | ||
| 423 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
| 424 | int destroy = (nn->nfsd_serv->sv_nrthreads == 1); | ||
| 425 | |||
| 426 | if (destroy) | ||
| 427 | svc_shutdown_net(nn->nfsd_serv, net); | ||
| 428 | svc_destroy(nn->nfsd_serv); | ||
| 429 | if (destroy) | ||
| 430 | nn->nfsd_serv = NULL; | ||
| 431 | } | ||
| 432 | |||
| 433 | int nfsd_set_nrthreads(int n, int *nthreads, struct net *net) | ||
| 380 | { | 434 | { |
| 381 | int i = 0; | 435 | int i = 0; |
| 382 | int tot = 0; | 436 | int tot = 0; |
| 383 | int err = 0; | 437 | int err = 0; |
| 384 | struct net *net = &init_net; | 438 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); |
| 385 | 439 | ||
| 386 | WARN_ON(!mutex_is_locked(&nfsd_mutex)); | 440 | WARN_ON(!mutex_is_locked(&nfsd_mutex)); |
| 387 | 441 | ||
| 388 | if (nfsd_serv == NULL || n <= 0) | 442 | if (nn->nfsd_serv == NULL || n <= 0) |
| 389 | return 0; | 443 | return 0; |
| 390 | 444 | ||
| 391 | if (n > nfsd_serv->sv_nrpools) | 445 | if (n > nn->nfsd_serv->sv_nrpools) |
| 392 | n = nfsd_serv->sv_nrpools; | 446 | n = nn->nfsd_serv->sv_nrpools; |
| 393 | 447 | ||
| 394 | /* enforce a global maximum number of threads */ | 448 | /* enforce a global maximum number of threads */ |
| 395 | tot = 0; | 449 | tot = 0; |
| @@ -419,9 +473,9 @@ int nfsd_set_nrthreads(int n, int *nthreads) | |||
| 419 | nthreads[0] = 1; | 473 | nthreads[0] = 1; |
| 420 | 474 | ||
| 421 | /* apply the new numbers */ | 475 | /* apply the new numbers */ |
| 422 | svc_get(nfsd_serv); | 476 | svc_get(nn->nfsd_serv); |
| 423 | for (i = 0; i < n; i++) { | 477 | for (i = 0; i < n; i++) { |
| 424 | err = svc_set_num_threads(nfsd_serv, &nfsd_serv->sv_pools[i], | 478 | err = svc_set_num_threads(nn->nfsd_serv, &nn->nfsd_serv->sv_pools[i], |
| 425 | nthreads[i]); | 479 | nthreads[i]); |
| 426 | if (err) | 480 | if (err) |
| 427 | break; | 481 | break; |
| @@ -436,11 +490,11 @@ int nfsd_set_nrthreads(int n, int *nthreads) | |||
| 436 | * this is the first time nrservs is nonzero. | 490 | * this is the first time nrservs is nonzero. |
| 437 | */ | 491 | */ |
| 438 | int | 492 | int |
| 439 | nfsd_svc(int nrservs) | 493 | nfsd_svc(int nrservs, struct net *net) |
| 440 | { | 494 | { |
| 441 | int error; | 495 | int error; |
| 442 | bool nfsd_up_before; | 496 | bool nfsd_up_before; |
| 443 | struct net *net = &init_net; | 497 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); |
| 444 | 498 | ||
| 445 | mutex_lock(&nfsd_mutex); | 499 | mutex_lock(&nfsd_mutex); |
| 446 | dprintk("nfsd: creating service\n"); | 500 | dprintk("nfsd: creating service\n"); |
| @@ -449,29 +503,29 @@ nfsd_svc(int nrservs) | |||
| 449 | if (nrservs > NFSD_MAXSERVS) | 503 | if (nrservs > NFSD_MAXSERVS) |
| 450 | nrservs = NFSD_MAXSERVS; | 504 | nrservs = NFSD_MAXSERVS; |
| 451 | error = 0; | 505 | error = 0; |
| 452 | if (nrservs == 0 && nfsd_serv == NULL) | 506 | if (nrservs == 0 && nn->nfsd_serv == NULL) |
| 453 | goto out; | 507 | goto out; |
| 454 | 508 | ||
| 455 | error = nfsd_create_serv(); | 509 | error = nfsd_create_serv(net); |
| 456 | if (error) | 510 | if (error) |
| 457 | goto out; | 511 | goto out; |
| 458 | 512 | ||
| 459 | nfsd_up_before = nfsd_up; | 513 | nfsd_up_before = nn->nfsd_net_up; |
| 460 | 514 | ||
| 461 | error = nfsd_startup(nrservs); | 515 | error = nfsd_startup_net(nrservs, net); |
| 462 | if (error) | 516 | if (error) |
| 463 | goto out_destroy; | 517 | goto out_destroy; |
| 464 | error = svc_set_num_threads(nfsd_serv, NULL, nrservs); | 518 | error = svc_set_num_threads(nn->nfsd_serv, NULL, nrservs); |
| 465 | if (error) | 519 | if (error) |
| 466 | goto out_shutdown; | 520 | goto out_shutdown; |
| 467 | /* We are holding a reference to nfsd_serv which | 521 | /* We are holding a reference to nn->nfsd_serv which |
| 468 | * we don't want to count in the return value, | 522 | * we don't want to count in the return value, |
| 469 | * so subtract 1 | 523 | * so subtract 1 |
| 470 | */ | 524 | */ |
| 471 | error = nfsd_serv->sv_nrthreads - 1; | 525 | error = nn->nfsd_serv->sv_nrthreads - 1; |
| 472 | out_shutdown: | 526 | out_shutdown: |
| 473 | if (error < 0 && !nfsd_up_before) | 527 | if (error < 0 && !nfsd_up_before) |
| 474 | nfsd_shutdown(); | 528 | nfsd_shutdown_net(net); |
| 475 | out_destroy: | 529 | out_destroy: |
| 476 | nfsd_destroy(net); /* Release server */ | 530 | nfsd_destroy(net); /* Release server */ |
| 477 | out: | 531 | out: |
| @@ -487,6 +541,8 @@ static int | |||
| 487 | nfsd(void *vrqstp) | 541 | nfsd(void *vrqstp) |
| 488 | { | 542 | { |
| 489 | struct svc_rqst *rqstp = (struct svc_rqst *) vrqstp; | 543 | struct svc_rqst *rqstp = (struct svc_rqst *) vrqstp; |
| 544 | struct svc_xprt *perm_sock = list_entry(rqstp->rq_server->sv_permsocks.next, typeof(struct svc_xprt), xpt_list); | ||
| 545 | struct net *net = perm_sock->xpt_net; | ||
| 490 | int err; | 546 | int err; |
| 491 | 547 | ||
| 492 | /* Lock module and set up kernel thread */ | 548 | /* Lock module and set up kernel thread */ |
| @@ -551,7 +607,7 @@ out: | |||
| 551 | /* Release the thread */ | 607 | /* Release the thread */ |
| 552 | svc_exit_thread(rqstp); | 608 | svc_exit_thread(rqstp); |
| 553 | 609 | ||
| 554 | nfsd_destroy(&init_net); | 610 | nfsd_destroy(net); |
| 555 | 611 | ||
| 556 | /* Release module */ | 612 | /* Release module */ |
| 557 | mutex_unlock(&nfsd_mutex); | 613 | mutex_unlock(&nfsd_mutex); |
| @@ -640,21 +696,24 @@ nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) | |||
| 640 | } | 696 | } |
| 641 | 697 | ||
| 642 | /* Store reply in cache. */ | 698 | /* Store reply in cache. */ |
| 643 | nfsd_cache_update(rqstp, proc->pc_cachetype, statp + 1); | 699 | nfsd_cache_update(rqstp, rqstp->rq_cachetype, statp + 1); |
| 644 | return 1; | 700 | return 1; |
| 645 | } | 701 | } |
| 646 | 702 | ||
| 647 | int nfsd_pool_stats_open(struct inode *inode, struct file *file) | 703 | int nfsd_pool_stats_open(struct inode *inode, struct file *file) |
| 648 | { | 704 | { |
| 649 | int ret; | 705 | int ret; |
| 706 | struct net *net = &init_net; | ||
| 707 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
| 708 | |||
| 650 | mutex_lock(&nfsd_mutex); | 709 | mutex_lock(&nfsd_mutex); |
| 651 | if (nfsd_serv == NULL) { | 710 | if (nn->nfsd_serv == NULL) { |
| 652 | mutex_unlock(&nfsd_mutex); | 711 | mutex_unlock(&nfsd_mutex); |
| 653 | return -ENODEV; | 712 | return -ENODEV; |
| 654 | } | 713 | } |
| 655 | /* bump up the psudo refcount while traversing */ | 714 | /* bump up the psudo refcount while traversing */ |
| 656 | svc_get(nfsd_serv); | 715 | svc_get(nn->nfsd_serv); |
| 657 | ret = svc_pool_stats_open(nfsd_serv, file); | 716 | ret = svc_pool_stats_open(nn->nfsd_serv, file); |
| 658 | mutex_unlock(&nfsd_mutex); | 717 | mutex_unlock(&nfsd_mutex); |
| 659 | return ret; | 718 | return ret; |
| 660 | } | 719 | } |
diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c index 65ec595e2226..979b42106979 100644 --- a/fs/nfsd/nfsxdr.c +++ b/fs/nfsd/nfsxdr.c | |||
| @@ -246,7 +246,7 @@ nfssvc_decode_readargs(struct svc_rqst *rqstp, __be32 *p, | |||
| 246 | struct nfsd_readargs *args) | 246 | struct nfsd_readargs *args) |
| 247 | { | 247 | { |
| 248 | unsigned int len; | 248 | unsigned int len; |
| 249 | int v,pn; | 249 | int v; |
| 250 | if (!(p = decode_fh(p, &args->fh))) | 250 | if (!(p = decode_fh(p, &args->fh))) |
| 251 | return 0; | 251 | return 0; |
| 252 | 252 | ||
| @@ -262,8 +262,9 @@ nfssvc_decode_readargs(struct svc_rqst *rqstp, __be32 *p, | |||
| 262 | */ | 262 | */ |
| 263 | v=0; | 263 | v=0; |
| 264 | while (len > 0) { | 264 | while (len > 0) { |
| 265 | pn = rqstp->rq_resused++; | 265 | struct page *p = *(rqstp->rq_next_page++); |
| 266 | rqstp->rq_vec[v].iov_base = page_address(rqstp->rq_respages[pn]); | 266 | |
| 267 | rqstp->rq_vec[v].iov_base = page_address(p); | ||
| 267 | rqstp->rq_vec[v].iov_len = len < PAGE_SIZE?len:PAGE_SIZE; | 268 | rqstp->rq_vec[v].iov_len = len < PAGE_SIZE?len:PAGE_SIZE; |
| 268 | len -= rqstp->rq_vec[v].iov_len; | 269 | len -= rqstp->rq_vec[v].iov_len; |
| 269 | v++; | 270 | v++; |
| @@ -355,7 +356,7 @@ nfssvc_decode_readlinkargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd_readli | |||
| 355 | { | 356 | { |
| 356 | if (!(p = decode_fh(p, &args->fh))) | 357 | if (!(p = decode_fh(p, &args->fh))) |
| 357 | return 0; | 358 | return 0; |
| 358 | args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused++]); | 359 | args->buffer = page_address(*(rqstp->rq_next_page++)); |
| 359 | 360 | ||
| 360 | return xdr_argsize_check(rqstp, p); | 361 | return xdr_argsize_check(rqstp, p); |
| 361 | } | 362 | } |
| @@ -396,7 +397,7 @@ nfssvc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p, | |||
| 396 | if (args->count > PAGE_SIZE) | 397 | if (args->count > PAGE_SIZE) |
| 397 | args->count = PAGE_SIZE; | 398 | args->count = PAGE_SIZE; |
| 398 | 399 | ||
| 399 | args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused++]); | 400 | args->buffer = page_address(*(rqstp->rq_next_page++)); |
| 400 | 401 | ||
| 401 | return xdr_argsize_check(rqstp, p); | 402 | return xdr_argsize_check(rqstp, p); |
| 402 | } | 403 | } |
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index e036894bce57..d1c229feed52 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h | |||
| @@ -150,6 +150,12 @@ struct nfsd4_channel_attrs { | |||
| 150 | u32 rdma_attrs; | 150 | u32 rdma_attrs; |
| 151 | }; | 151 | }; |
| 152 | 152 | ||
| 153 | struct nfsd4_cb_sec { | ||
| 154 | u32 flavor; /* (u32)(-1) used to mean "no valid flavor" */ | ||
| 155 | u32 uid; | ||
| 156 | u32 gid; | ||
| 157 | }; | ||
| 158 | |||
| 153 | struct nfsd4_create_session { | 159 | struct nfsd4_create_session { |
| 154 | clientid_t clientid; | 160 | clientid_t clientid; |
| 155 | struct nfs4_sessionid sessionid; | 161 | struct nfs4_sessionid sessionid; |
| @@ -158,8 +164,12 @@ struct nfsd4_create_session { | |||
| 158 | struct nfsd4_channel_attrs fore_channel; | 164 | struct nfsd4_channel_attrs fore_channel; |
| 159 | struct nfsd4_channel_attrs back_channel; | 165 | struct nfsd4_channel_attrs back_channel; |
| 160 | u32 callback_prog; | 166 | u32 callback_prog; |
| 161 | u32 uid; | 167 | struct nfsd4_cb_sec cb_sec; |
| 162 | u32 gid; | 168 | }; |
| 169 | |||
| 170 | struct nfsd4_backchannel_ctl { | ||
| 171 | u32 bc_cb_program; | ||
| 172 | struct nfsd4_cb_sec bc_cb_sec; | ||
| 163 | }; | 173 | }; |
| 164 | 174 | ||
| 165 | struct nfsd4_bind_conn_to_session { | 175 | struct nfsd4_bind_conn_to_session { |
| @@ -192,6 +202,7 @@ struct nfsd4_session { | |||
| 192 | struct nfs4_sessionid se_sessionid; | 202 | struct nfs4_sessionid se_sessionid; |
| 193 | struct nfsd4_channel_attrs se_fchannel; | 203 | struct nfsd4_channel_attrs se_fchannel; |
| 194 | struct nfsd4_channel_attrs se_bchannel; | 204 | struct nfsd4_channel_attrs se_bchannel; |
| 205 | struct nfsd4_cb_sec se_cb_sec; | ||
| 195 | struct list_head se_conns; | 206 | struct list_head se_conns; |
| 196 | u32 se_cb_prog; | 207 | u32 se_cb_prog; |
| 197 | u32 se_cb_seq_nr; | 208 | u32 se_cb_seq_nr; |
| @@ -221,13 +232,12 @@ struct nfsd4_sessionid { | |||
| 221 | */ | 232 | */ |
| 222 | struct nfs4_client { | 233 | struct nfs4_client { |
| 223 | struct list_head cl_idhash; /* hash by cl_clientid.id */ | 234 | struct list_head cl_idhash; /* hash by cl_clientid.id */ |
| 224 | struct list_head cl_strhash; /* hash by cl_name */ | 235 | struct rb_node cl_namenode; /* link into by-name trees */ |
| 225 | struct list_head cl_openowners; | 236 | struct list_head cl_openowners; |
| 226 | struct idr cl_stateids; /* stateid lookup */ | 237 | struct idr cl_stateids; /* stateid lookup */ |
| 227 | struct list_head cl_delegations; | 238 | struct list_head cl_delegations; |
| 228 | struct list_head cl_lru; /* tail queue */ | 239 | struct list_head cl_lru; /* tail queue */ |
| 229 | struct xdr_netobj cl_name; /* id generated by client */ | 240 | struct xdr_netobj cl_name; /* id generated by client */ |
| 230 | char cl_recdir[HEXDIR_LEN]; /* recovery dir */ | ||
| 231 | nfs4_verifier cl_verifier; /* generated by client */ | 241 | nfs4_verifier cl_verifier; /* generated by client */ |
| 232 | time_t cl_time; /* time of last lease renewal */ | 242 | time_t cl_time; /* time of last lease renewal */ |
| 233 | struct sockaddr_storage cl_addr; /* client ipaddress */ | 243 | struct sockaddr_storage cl_addr; /* client ipaddress */ |
| @@ -242,9 +252,11 @@ struct nfs4_client { | |||
| 242 | #define NFSD4_CLIENT_CB_KILL (1) | 252 | #define NFSD4_CLIENT_CB_KILL (1) |
| 243 | #define NFSD4_CLIENT_STABLE (2) /* client on stable storage */ | 253 | #define NFSD4_CLIENT_STABLE (2) /* client on stable storage */ |
| 244 | #define NFSD4_CLIENT_RECLAIM_COMPLETE (3) /* reclaim_complete done */ | 254 | #define NFSD4_CLIENT_RECLAIM_COMPLETE (3) /* reclaim_complete done */ |
| 255 | #define NFSD4_CLIENT_CONFIRMED (4) /* client is confirmed */ | ||
| 245 | #define NFSD4_CLIENT_CB_FLAG_MASK (1 << NFSD4_CLIENT_CB_UPDATE | \ | 256 | #define NFSD4_CLIENT_CB_FLAG_MASK (1 << NFSD4_CLIENT_CB_UPDATE | \ |
| 246 | 1 << NFSD4_CLIENT_CB_KILL) | 257 | 1 << NFSD4_CLIENT_CB_KILL) |
| 247 | unsigned long cl_flags; | 258 | unsigned long cl_flags; |
| 259 | struct rpc_cred *cl_cb_cred; | ||
| 248 | struct rpc_clnt *cl_cb_client; | 260 | struct rpc_clnt *cl_cb_client; |
| 249 | u32 cl_cb_ident; | 261 | u32 cl_cb_ident; |
| 250 | #define NFSD4_CB_UP 0 | 262 | #define NFSD4_CB_UP 0 |
| @@ -271,6 +283,7 @@ struct nfs4_client { | |||
| 271 | unsigned long cl_cb_slot_busy; | 283 | unsigned long cl_cb_slot_busy; |
| 272 | struct rpc_wait_queue cl_cb_waitq; /* backchannel callers may */ | 284 | struct rpc_wait_queue cl_cb_waitq; /* backchannel callers may */ |
| 273 | /* wait here for slots */ | 285 | /* wait here for slots */ |
| 286 | struct net *net; | ||
| 274 | }; | 287 | }; |
| 275 | 288 | ||
| 276 | static inline void | 289 | static inline void |
| @@ -292,6 +305,7 @@ is_client_expired(struct nfs4_client *clp) | |||
| 292 | */ | 305 | */ |
| 293 | struct nfs4_client_reclaim { | 306 | struct nfs4_client_reclaim { |
| 294 | struct list_head cr_strhash; /* hash by cr_name */ | 307 | struct list_head cr_strhash; /* hash by cr_name */ |
| 308 | struct nfs4_client *cr_clp; /* pointer to associated clp */ | ||
| 295 | char cr_recdir[HEXDIR_LEN]; /* recover dir */ | 309 | char cr_recdir[HEXDIR_LEN]; /* recover dir */ |
| 296 | }; | 310 | }; |
| 297 | 311 | ||
| @@ -452,25 +466,26 @@ extern __be32 nfs4_preprocess_stateid_op(struct net *net, | |||
| 452 | stateid_t *stateid, int flags, struct file **filp); | 466 | stateid_t *stateid, int flags, struct file **filp); |
| 453 | extern void nfs4_lock_state(void); | 467 | extern void nfs4_lock_state(void); |
| 454 | extern void nfs4_unlock_state(void); | 468 | extern void nfs4_unlock_state(void); |
| 455 | extern int nfs4_in_grace(void); | 469 | void nfs4_remove_reclaim_record(struct nfs4_client_reclaim *, struct nfsd_net *); |
| 456 | extern void nfs4_release_reclaim(void); | 470 | extern void nfs4_release_reclaim(struct nfsd_net *); |
| 457 | extern struct nfs4_client_reclaim *nfsd4_find_reclaim_client(struct nfs4_client *crp); | 471 | extern struct nfs4_client_reclaim *nfsd4_find_reclaim_client(const char *recdir, |
| 458 | extern __be32 nfs4_check_open_reclaim(clientid_t *clid, bool sessions); | 472 | struct nfsd_net *nn); |
| 473 | extern __be32 nfs4_check_open_reclaim(clientid_t *clid, bool sessions, struct nfsd_net *nn); | ||
| 459 | extern void nfs4_free_openowner(struct nfs4_openowner *); | 474 | extern void nfs4_free_openowner(struct nfs4_openowner *); |
| 460 | extern void nfs4_free_lockowner(struct nfs4_lockowner *); | 475 | extern void nfs4_free_lockowner(struct nfs4_lockowner *); |
| 461 | extern int set_callback_cred(void); | 476 | extern int set_callback_cred(void); |
| 477 | extern void nfsd4_init_callback(struct nfsd4_callback *); | ||
| 462 | extern void nfsd4_probe_callback(struct nfs4_client *clp); | 478 | extern void nfsd4_probe_callback(struct nfs4_client *clp); |
| 463 | extern void nfsd4_probe_callback_sync(struct nfs4_client *clp); | 479 | extern void nfsd4_probe_callback_sync(struct nfs4_client *clp); |
| 464 | extern void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *); | 480 | extern void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *); |
| 465 | extern void nfsd4_do_callback_rpc(struct work_struct *); | ||
| 466 | extern void nfsd4_cb_recall(struct nfs4_delegation *dp); | 481 | extern void nfsd4_cb_recall(struct nfs4_delegation *dp); |
| 467 | extern int nfsd4_create_callback_queue(void); | 482 | extern int nfsd4_create_callback_queue(void); |
| 468 | extern void nfsd4_destroy_callback_queue(void); | 483 | extern void nfsd4_destroy_callback_queue(void); |
| 469 | extern void nfsd4_shutdown_callback(struct nfs4_client *); | 484 | extern void nfsd4_shutdown_callback(struct nfs4_client *); |
| 470 | extern void nfs4_put_delegation(struct nfs4_delegation *dp); | 485 | extern void nfs4_put_delegation(struct nfs4_delegation *dp); |
| 471 | extern __be32 nfs4_make_rec_clidname(char *clidname, struct xdr_netobj *clname); | 486 | extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(const char *name, |
| 472 | extern int nfs4_client_to_reclaim(const char *name); | 487 | struct nfsd_net *nn); |
| 473 | extern int nfs4_has_reclaimed_state(const char *name, bool use_exchange_id); | 488 | extern bool nfs4_has_reclaimed_state(const char *name, struct nfsd_net *nn); |
| 474 | extern void release_session_client(struct nfsd4_session *); | 489 | extern void release_session_client(struct nfsd4_session *); |
| 475 | extern void nfsd4_purge_closed_stateid(struct nfs4_stateowner *); | 490 | extern void nfsd4_purge_closed_stateid(struct nfs4_stateowner *); |
| 476 | 491 | ||
| @@ -480,5 +495,28 @@ extern void nfsd4_client_tracking_exit(struct net *net); | |||
| 480 | extern void nfsd4_client_record_create(struct nfs4_client *clp); | 495 | extern void nfsd4_client_record_create(struct nfs4_client *clp); |
| 481 | extern void nfsd4_client_record_remove(struct nfs4_client *clp); | 496 | extern void nfsd4_client_record_remove(struct nfs4_client *clp); |
| 482 | extern int nfsd4_client_record_check(struct nfs4_client *clp); | 497 | extern int nfsd4_client_record_check(struct nfs4_client *clp); |
| 483 | extern void nfsd4_record_grace_done(struct net *net, time_t boot_time); | 498 | extern void nfsd4_record_grace_done(struct nfsd_net *nn, time_t boot_time); |
| 499 | |||
| 500 | /* nfs fault injection functions */ | ||
| 501 | #ifdef CONFIG_NFSD_FAULT_INJECTION | ||
| 502 | int nfsd_fault_inject_init(void); | ||
| 503 | void nfsd_fault_inject_cleanup(void); | ||
| 504 | u64 nfsd_for_n_state(u64, u64 (*)(struct nfs4_client *, u64)); | ||
| 505 | struct nfs4_client *nfsd_find_client(struct sockaddr_storage *, size_t); | ||
| 506 | |||
| 507 | u64 nfsd_forget_client(struct nfs4_client *, u64); | ||
| 508 | u64 nfsd_forget_client_locks(struct nfs4_client*, u64); | ||
| 509 | u64 nfsd_forget_client_openowners(struct nfs4_client *, u64); | ||
| 510 | u64 nfsd_forget_client_delegations(struct nfs4_client *, u64); | ||
| 511 | u64 nfsd_recall_client_delegations(struct nfs4_client *, u64); | ||
| 512 | |||
| 513 | u64 nfsd_print_client(struct nfs4_client *, u64); | ||
| 514 | u64 nfsd_print_client_locks(struct nfs4_client *, u64); | ||
| 515 | u64 nfsd_print_client_openowners(struct nfs4_client *, u64); | ||
| 516 | u64 nfsd_print_client_delegations(struct nfs4_client *, u64); | ||
| 517 | #else /* CONFIG_NFSD_FAULT_INJECTION */ | ||
| 518 | static inline int nfsd_fault_inject_init(void) { return 0; } | ||
| 519 | static inline void nfsd_fault_inject_cleanup(void) {} | ||
| 520 | #endif /* CONFIG_NFSD_FAULT_INJECTION */ | ||
| 521 | |||
| 484 | #endif /* NFSD4_STATE_H */ | 522 | #endif /* NFSD4_STATE_H */ |
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index c120b48ec305..f0a6d88d7fff 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
| @@ -886,7 +886,7 @@ nfsd_splice_actor(struct pipe_inode_info *pipe, struct pipe_buffer *buf, | |||
| 886 | struct splice_desc *sd) | 886 | struct splice_desc *sd) |
| 887 | { | 887 | { |
| 888 | struct svc_rqst *rqstp = sd->u.data; | 888 | struct svc_rqst *rqstp = sd->u.data; |
| 889 | struct page **pp = rqstp->rq_respages + rqstp->rq_resused; | 889 | struct page **pp = rqstp->rq_next_page; |
| 890 | struct page *page = buf->page; | 890 | struct page *page = buf->page; |
| 891 | size_t size; | 891 | size_t size; |
| 892 | 892 | ||
| @@ -894,17 +894,15 @@ nfsd_splice_actor(struct pipe_inode_info *pipe, struct pipe_buffer *buf, | |||
| 894 | 894 | ||
| 895 | if (rqstp->rq_res.page_len == 0) { | 895 | if (rqstp->rq_res.page_len == 0) { |
| 896 | get_page(page); | 896 | get_page(page); |
| 897 | put_page(*pp); | 897 | put_page(*rqstp->rq_next_page); |
| 898 | *pp = page; | 898 | *(rqstp->rq_next_page++) = page; |
| 899 | rqstp->rq_resused++; | ||
| 900 | rqstp->rq_res.page_base = buf->offset; | 899 | rqstp->rq_res.page_base = buf->offset; |
| 901 | rqstp->rq_res.page_len = size; | 900 | rqstp->rq_res.page_len = size; |
| 902 | } else if (page != pp[-1]) { | 901 | } else if (page != pp[-1]) { |
| 903 | get_page(page); | 902 | get_page(page); |
| 904 | if (*pp) | 903 | if (*rqstp->rq_next_page) |
| 905 | put_page(*pp); | 904 | put_page(*rqstp->rq_next_page); |
| 906 | *pp = page; | 905 | *(rqstp->rq_next_page++) = page; |
| 907 | rqstp->rq_resused++; | ||
| 908 | rqstp->rq_res.page_len += size; | 906 | rqstp->rq_res.page_len += size; |
| 909 | } else | 907 | } else |
| 910 | rqstp->rq_res.page_len += size; | 908 | rqstp->rq_res.page_len += size; |
| @@ -936,7 +934,8 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |||
| 936 | .u.data = rqstp, | 934 | .u.data = rqstp, |
| 937 | }; | 935 | }; |
| 938 | 936 | ||
| 939 | rqstp->rq_resused = 1; | 937 | WARN_ON_ONCE(rqstp->rq_next_page != rqstp->rq_respages + 1); |
| 938 | rqstp->rq_next_page = rqstp->rq_respages + 1; | ||
| 940 | host_err = splice_direct_to_actor(file, &sd, nfsd_direct_splice_actor); | 939 | host_err = splice_direct_to_actor(file, &sd, nfsd_direct_splice_actor); |
| 941 | } else { | 940 | } else { |
| 942 | oldfs = get_fs(); | 941 | oldfs = get_fs(); |
| @@ -1020,28 +1019,10 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |||
| 1020 | inode = dentry->d_inode; | 1019 | inode = dentry->d_inode; |
| 1021 | exp = fhp->fh_export; | 1020 | exp = fhp->fh_export; |
| 1022 | 1021 | ||
| 1023 | /* | ||
| 1024 | * Request sync writes if | ||
| 1025 | * - the sync export option has been set, or | ||
| 1026 | * - the client requested O_SYNC behavior (NFSv3 feature). | ||
| 1027 | * - The file system doesn't support fsync(). | ||
| 1028 | * When NFSv2 gathered writes have been configured for this volume, | ||
| 1029 | * flushing the data to disk is handled separately below. | ||
| 1030 | */ | ||
| 1031 | use_wgather = (rqstp->rq_vers == 2) && EX_WGATHER(exp); | 1022 | use_wgather = (rqstp->rq_vers == 2) && EX_WGATHER(exp); |
| 1032 | 1023 | ||
| 1033 | if (!file->f_op->fsync) {/* COMMIT3 cannot work */ | ||
| 1034 | stable = 2; | ||
| 1035 | *stablep = 2; /* FILE_SYNC */ | ||
| 1036 | } | ||
| 1037 | |||
| 1038 | if (!EX_ISSYNC(exp)) | 1024 | if (!EX_ISSYNC(exp)) |
| 1039 | stable = 0; | 1025 | stable = 0; |
| 1040 | if (stable && !use_wgather) { | ||
| 1041 | spin_lock(&file->f_lock); | ||
| 1042 | file->f_flags |= O_SYNC; | ||
| 1043 | spin_unlock(&file->f_lock); | ||
| 1044 | } | ||
| 1045 | 1026 | ||
| 1046 | /* Write the data. */ | 1027 | /* Write the data. */ |
| 1047 | oldfs = get_fs(); set_fs(KERNEL_DS); | 1028 | oldfs = get_fs(); set_fs(KERNEL_DS); |
| @@ -1057,8 +1038,12 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |||
| 1057 | if (inode->i_mode & (S_ISUID | S_ISGID)) | 1038 | if (inode->i_mode & (S_ISUID | S_ISGID)) |
| 1058 | kill_suid(dentry); | 1039 | kill_suid(dentry); |
| 1059 | 1040 | ||
| 1060 | if (stable && use_wgather) | 1041 | if (stable) { |
| 1061 | host_err = wait_for_concurrent_writes(file); | 1042 | if (use_wgather) |
| 1043 | host_err = wait_for_concurrent_writes(file); | ||
| 1044 | else | ||
| 1045 | host_err = vfs_fsync_range(file, offset, offset+*cnt, 0); | ||
| 1046 | } | ||
| 1062 | 1047 | ||
| 1063 | out_nfserr: | 1048 | out_nfserr: |
| 1064 | dprintk("nfsd: write complete host_err=%d\n", host_err); | 1049 | dprintk("nfsd: write complete host_err=%d\n", host_err); |
| @@ -1485,13 +1470,19 @@ do_nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
| 1485 | case NFS3_CREATE_EXCLUSIVE: | 1470 | case NFS3_CREATE_EXCLUSIVE: |
| 1486 | if ( dchild->d_inode->i_mtime.tv_sec == v_mtime | 1471 | if ( dchild->d_inode->i_mtime.tv_sec == v_mtime |
| 1487 | && dchild->d_inode->i_atime.tv_sec == v_atime | 1472 | && dchild->d_inode->i_atime.tv_sec == v_atime |
| 1488 | && dchild->d_inode->i_size == 0 ) | 1473 | && dchild->d_inode->i_size == 0 ) { |
| 1474 | if (created) | ||
| 1475 | *created = 1; | ||
| 1489 | break; | 1476 | break; |
| 1477 | } | ||
| 1490 | case NFS4_CREATE_EXCLUSIVE4_1: | 1478 | case NFS4_CREATE_EXCLUSIVE4_1: |
| 1491 | if ( dchild->d_inode->i_mtime.tv_sec == v_mtime | 1479 | if ( dchild->d_inode->i_mtime.tv_sec == v_mtime |
| 1492 | && dchild->d_inode->i_atime.tv_sec == v_atime | 1480 | && dchild->d_inode->i_atime.tv_sec == v_atime |
| 1493 | && dchild->d_inode->i_size == 0 ) | 1481 | && dchild->d_inode->i_size == 0 ) { |
| 1482 | if (created) | ||
| 1483 | *created = 1; | ||
| 1494 | goto set_attr; | 1484 | goto set_attr; |
| 1485 | } | ||
| 1495 | /* fallthru */ | 1486 | /* fallthru */ |
| 1496 | case NFS3_CREATE_GUARDED: | 1487 | case NFS3_CREATE_GUARDED: |
| 1497 | err = nfserr_exist; | 1488 | err = nfserr_exist; |
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index acd127d4ee82..0889bfb43dc9 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h | |||
| @@ -385,7 +385,8 @@ struct nfsd4_write { | |||
| 385 | u64 wr_offset; /* request */ | 385 | u64 wr_offset; /* request */ |
| 386 | u32 wr_stable_how; /* request */ | 386 | u32 wr_stable_how; /* request */ |
| 387 | u32 wr_buflen; /* request */ | 387 | u32 wr_buflen; /* request */ |
| 388 | int wr_vlen; | 388 | struct kvec wr_head; |
| 389 | struct page ** wr_pagelist; /* request */ | ||
| 389 | 390 | ||
| 390 | u32 wr_bytes_written; /* response */ | 391 | u32 wr_bytes_written; /* response */ |
| 391 | u32 wr_how_written; /* response */ | 392 | u32 wr_how_written; /* response */ |
| @@ -462,6 +463,7 @@ struct nfsd4_op { | |||
| 462 | 463 | ||
| 463 | /* NFSv4.1 */ | 464 | /* NFSv4.1 */ |
| 464 | struct nfsd4_exchange_id exchange_id; | 465 | struct nfsd4_exchange_id exchange_id; |
| 466 | struct nfsd4_backchannel_ctl backchannel_ctl; | ||
| 465 | struct nfsd4_bind_conn_to_session bind_conn_to_session; | 467 | struct nfsd4_bind_conn_to_session bind_conn_to_session; |
| 466 | struct nfsd4_create_session create_session; | 468 | struct nfsd4_create_session create_session; |
| 467 | struct nfsd4_destroy_session destroy_session; | 469 | struct nfsd4_destroy_session destroy_session; |
| @@ -526,6 +528,14 @@ static inline bool nfsd4_not_cached(struct nfsd4_compoundres *resp) | |||
| 526 | || nfsd4_is_solo_sequence(resp); | 528 | || nfsd4_is_solo_sequence(resp); |
| 527 | } | 529 | } |
| 528 | 530 | ||
| 531 | static inline bool nfsd4_last_compound_op(struct svc_rqst *rqstp) | ||
| 532 | { | ||
| 533 | struct nfsd4_compoundres *resp = rqstp->rq_resp; | ||
| 534 | struct nfsd4_compoundargs *argp = rqstp->rq_argp; | ||
| 535 | |||
| 536 | return argp->opcnt == resp->opcnt; | ||
| 537 | } | ||
| 538 | |||
| 529 | #define NFS4_SVC_XDRSIZE sizeof(struct nfsd4_compoundargs) | 539 | #define NFS4_SVC_XDRSIZE sizeof(struct nfsd4_compoundargs) |
| 530 | 540 | ||
| 531 | static inline void | 541 | static inline void |
| @@ -566,6 +576,7 @@ extern __be32 nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp, | |||
| 566 | struct nfsd4_sequence *seq); | 576 | struct nfsd4_sequence *seq); |
| 567 | extern __be32 nfsd4_exchange_id(struct svc_rqst *rqstp, | 577 | extern __be32 nfsd4_exchange_id(struct svc_rqst *rqstp, |
| 568 | struct nfsd4_compound_state *, struct nfsd4_exchange_id *); | 578 | struct nfsd4_compound_state *, struct nfsd4_exchange_id *); |
| 579 | extern __be32 nfsd4_backchannel_ctl(struct svc_rqst *, struct nfsd4_compound_state *, struct nfsd4_backchannel_ctl *); | ||
| 569 | extern __be32 nfsd4_bind_conn_to_session(struct svc_rqst *, struct nfsd4_compound_state *, struct nfsd4_bind_conn_to_session *); | 580 | extern __be32 nfsd4_bind_conn_to_session(struct svc_rqst *, struct nfsd4_compound_state *, struct nfsd4_bind_conn_to_session *); |
| 570 | extern __be32 nfsd4_create_session(struct svc_rqst *, | 581 | extern __be32 nfsd4_create_session(struct svc_rqst *, |
| 571 | struct nfsd4_compound_state *, | 582 | struct nfsd4_compound_state *, |
| @@ -579,7 +590,7 @@ extern __be32 nfsd4_destroy_session(struct svc_rqst *, | |||
| 579 | extern __be32 nfsd4_destroy_clientid(struct svc_rqst *, struct nfsd4_compound_state *, struct nfsd4_destroy_clientid *); | 590 | extern __be32 nfsd4_destroy_clientid(struct svc_rqst *, struct nfsd4_compound_state *, struct nfsd4_destroy_clientid *); |
| 580 | __be32 nfsd4_reclaim_complete(struct svc_rqst *, struct nfsd4_compound_state *, struct nfsd4_reclaim_complete *); | 591 | __be32 nfsd4_reclaim_complete(struct svc_rqst *, struct nfsd4_compound_state *, struct nfsd4_reclaim_complete *); |
| 581 | extern __be32 nfsd4_process_open1(struct nfsd4_compound_state *, | 592 | extern __be32 nfsd4_process_open1(struct nfsd4_compound_state *, |
| 582 | struct nfsd4_open *open); | 593 | struct nfsd4_open *open, struct nfsd_net *nn); |
| 583 | extern __be32 nfsd4_process_open2(struct svc_rqst *rqstp, | 594 | extern __be32 nfsd4_process_open2(struct svc_rqst *rqstp, |
| 584 | struct svc_fh *current_fh, struct nfsd4_open *open); | 595 | struct svc_fh *current_fh, struct nfsd4_open *open); |
| 585 | extern void nfsd4_cleanup_open_state(struct nfsd4_open *open, __be32 status); | 596 | extern void nfsd4_cleanup_open_state(struct nfsd4_open *open, __be32 status); |
diff --git a/include/linux/exportfs.h b/include/linux/exportfs.h index c7e6b6392ab8..5b9b5b317180 100644 --- a/include/linux/exportfs.h +++ b/include/linux/exportfs.h | |||
| @@ -83,6 +83,11 @@ enum fid_type { | |||
| 83 | * 64 bit parent inode number. | 83 | * 64 bit parent inode number. |
| 84 | */ | 84 | */ |
| 85 | FILEID_NILFS_WITH_PARENT = 0x62, | 85 | FILEID_NILFS_WITH_PARENT = 0x62, |
| 86 | |||
| 87 | /* | ||
| 88 | * Filesystems must not use 0xff file ID. | ||
| 89 | */ | ||
| 90 | FILEID_INVALID = 0xff, | ||
| 86 | }; | 91 | }; |
| 87 | 92 | ||
| 88 | struct fid { | 93 | struct fid { |
diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h index f792794f6634..5dc9ee4d616e 100644 --- a/include/linux/sunrpc/cache.h +++ b/include/linux/sunrpc/cache.h | |||
| @@ -217,6 +217,8 @@ extern int qword_get(char **bpp, char *dest, int bufsize); | |||
| 217 | static inline int get_int(char **bpp, int *anint) | 217 | static inline int get_int(char **bpp, int *anint) |
| 218 | { | 218 | { |
| 219 | char buf[50]; | 219 | char buf[50]; |
| 220 | char *ep; | ||
| 221 | int rv; | ||
| 220 | int len = qword_get(bpp, buf, sizeof(buf)); | 222 | int len = qword_get(bpp, buf, sizeof(buf)); |
| 221 | 223 | ||
| 222 | if (len < 0) | 224 | if (len < 0) |
| @@ -224,9 +226,11 @@ static inline int get_int(char **bpp, int *anint) | |||
| 224 | if (len == 0) | 226 | if (len == 0) |
| 225 | return -ENOENT; | 227 | return -ENOENT; |
| 226 | 228 | ||
| 227 | if (kstrtoint(buf, 0, anint)) | 229 | rv = simple_strtol(buf, &ep, 0); |
| 230 | if (*ep) | ||
| 228 | return -EINVAL; | 231 | return -EINVAL; |
| 229 | 232 | ||
| 233 | *anint = rv; | ||
| 230 | return 0; | 234 | return 0; |
| 231 | } | 235 | } |
| 232 | 236 | ||
diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index d83db800fe02..676ddf53b3ee 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h | |||
| @@ -243,6 +243,7 @@ struct svc_rqst { | |||
| 243 | struct page * rq_pages[RPCSVC_MAXPAGES]; | 243 | struct page * rq_pages[RPCSVC_MAXPAGES]; |
| 244 | struct page * *rq_respages; /* points into rq_pages */ | 244 | struct page * *rq_respages; /* points into rq_pages */ |
| 245 | int rq_resused; /* number of pages used for result */ | 245 | int rq_resused; /* number of pages used for result */ |
| 246 | struct page * *rq_next_page; /* next reply page to use */ | ||
| 246 | 247 | ||
| 247 | struct kvec rq_vec[RPCSVC_MAXPAGES]; /* generally useful.. */ | 248 | struct kvec rq_vec[RPCSVC_MAXPAGES]; /* generally useful.. */ |
| 248 | 249 | ||
| @@ -338,9 +339,8 @@ xdr_ressize_check(struct svc_rqst *rqstp, __be32 *p) | |||
| 338 | 339 | ||
| 339 | static inline void svc_free_res_pages(struct svc_rqst *rqstp) | 340 | static inline void svc_free_res_pages(struct svc_rqst *rqstp) |
| 340 | { | 341 | { |
| 341 | while (rqstp->rq_resused) { | 342 | while (rqstp->rq_next_page != rqstp->rq_respages) { |
| 342 | struct page **pp = (rqstp->rq_respages + | 343 | struct page **pp = --rqstp->rq_next_page; |
| 343 | --rqstp->rq_resused); | ||
| 344 | if (*pp) { | 344 | if (*pp) { |
| 345 | put_page(*pp); | 345 | put_page(*pp); |
| 346 | *pp = NULL; | 346 | *pp = NULL; |
diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h index 92ad02f0dcc0..62fd1b756e99 100644 --- a/include/linux/sunrpc/svcsock.h +++ b/include/linux/sunrpc/svcsock.h | |||
| @@ -26,11 +26,28 @@ struct svc_sock { | |||
| 26 | void (*sk_owspace)(struct sock *); | 26 | void (*sk_owspace)(struct sock *); |
| 27 | 27 | ||
| 28 | /* private TCP part */ | 28 | /* private TCP part */ |
| 29 | u32 sk_reclen; /* length of record */ | 29 | /* On-the-wire fragment header: */ |
| 30 | u32 sk_tcplen; /* current read length */ | 30 | __be32 sk_reclen; |
| 31 | /* As we receive a record, this includes the length received so | ||
| 32 | * far (including the fragment header): */ | ||
| 33 | u32 sk_tcplen; | ||
| 34 | /* Total length of the data (not including fragment headers) | ||
| 35 | * received so far in the fragments making up this rpc: */ | ||
| 36 | u32 sk_datalen; | ||
| 37 | |||
| 31 | struct page * sk_pages[RPCSVC_MAXPAGES]; /* received data */ | 38 | struct page * sk_pages[RPCSVC_MAXPAGES]; /* received data */ |
| 32 | }; | 39 | }; |
| 33 | 40 | ||
| 41 | static inline u32 svc_sock_reclen(struct svc_sock *svsk) | ||
| 42 | { | ||
| 43 | return ntohl(svsk->sk_reclen) & RPC_FRAGMENT_SIZE_MASK; | ||
| 44 | } | ||
| 45 | |||
| 46 | static inline u32 svc_sock_final_rec(struct svc_sock *svsk) | ||
| 47 | { | ||
| 48 | return ntohl(svsk->sk_reclen) & RPC_LAST_STREAM_FRAGMENT; | ||
| 49 | } | ||
| 50 | |||
| 34 | /* | 51 | /* |
| 35 | * Function prototypes. | 52 | * Function prototypes. |
| 36 | */ | 53 | */ |
diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index 411f332de0b3..795a0f4e920b 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c | |||
| @@ -23,7 +23,6 @@ | |||
| 23 | #include <linux/errno.h> | 23 | #include <linux/errno.h> |
| 24 | #include <linux/mutex.h> | 24 | #include <linux/mutex.h> |
| 25 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
| 26 | #include <linux/nsproxy.h> | ||
| 27 | #include <net/ipv6.h> | 26 | #include <net/ipv6.h> |
| 28 | 27 | ||
| 29 | #include <linux/sunrpc/clnt.h> | 28 | #include <linux/sunrpc/clnt.h> |
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index dfa4ba69ff45..dbf12ac5ecb7 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c | |||
| @@ -20,7 +20,6 @@ | |||
| 20 | #include <linux/module.h> | 20 | #include <linux/module.h> |
| 21 | #include <linux/kthread.h> | 21 | #include <linux/kthread.h> |
| 22 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
| 23 | #include <linux/nsproxy.h> | ||
| 24 | 23 | ||
| 25 | #include <linux/sunrpc/types.h> | 24 | #include <linux/sunrpc/types.h> |
| 26 | #include <linux/sunrpc/xdr.h> | 25 | #include <linux/sunrpc/xdr.h> |
| @@ -1041,7 +1040,7 @@ static void svc_unregister(const struct svc_serv *serv, struct net *net) | |||
| 1041 | } | 1040 | } |
| 1042 | 1041 | ||
| 1043 | /* | 1042 | /* |
| 1044 | * Printk the given error with the address of the client that caused it. | 1043 | * dprintk the given error with the address of the client that caused it. |
| 1045 | */ | 1044 | */ |
| 1046 | static __printf(2, 3) | 1045 | static __printf(2, 3) |
| 1047 | void svc_printk(struct svc_rqst *rqstp, const char *fmt, ...) | 1046 | void svc_printk(struct svc_rqst *rqstp, const char *fmt, ...) |
| @@ -1055,8 +1054,7 @@ void svc_printk(struct svc_rqst *rqstp, const char *fmt, ...) | |||
| 1055 | vaf.fmt = fmt; | 1054 | vaf.fmt = fmt; |
| 1056 | vaf.va = &args; | 1055 | vaf.va = &args; |
| 1057 | 1056 | ||
| 1058 | net_warn_ratelimited("svc: %s: %pV", | 1057 | dprintk("svc: %s: %pV", svc_print_addr(rqstp, buf, sizeof(buf)), &vaf); |
| 1059 | svc_print_addr(rqstp, buf, sizeof(buf)), &vaf); | ||
| 1060 | 1058 | ||
| 1061 | va_end(args); | 1059 | va_end(args); |
| 1062 | } | 1060 | } |
| @@ -1305,7 +1303,7 @@ svc_process(struct svc_rqst *rqstp) | |||
| 1305 | * Setup response xdr_buf. | 1303 | * Setup response xdr_buf. |
| 1306 | * Initially it has just one page | 1304 | * Initially it has just one page |
| 1307 | */ | 1305 | */ |
| 1308 | rqstp->rq_resused = 1; | 1306 | rqstp->rq_next_page = &rqstp->rq_respages[1]; |
| 1309 | resv->iov_base = page_address(rqstp->rq_respages[0]); | 1307 | resv->iov_base = page_address(rqstp->rq_respages[0]); |
| 1310 | resv->iov_len = 0; | 1308 | resv->iov_len = 0; |
| 1311 | rqstp->rq_res.pages = rqstp->rq_respages + 1; | 1309 | rqstp->rq_res.pages = rqstp->rq_respages + 1; |
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index cc3020d16789..0a148c9d2a5c 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c | |||
| @@ -605,6 +605,7 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp) | |||
| 605 | rqstp->rq_respages = rqstp->rq_pages + 1 + | 605 | rqstp->rq_respages = rqstp->rq_pages + 1 + |
| 606 | DIV_ROUND_UP(rqstp->rq_arg.page_len, PAGE_SIZE); | 606 | DIV_ROUND_UP(rqstp->rq_arg.page_len, PAGE_SIZE); |
| 607 | } | 607 | } |
| 608 | rqstp->rq_next_page = rqstp->rq_respages+1; | ||
| 608 | 609 | ||
| 609 | if (serv->sv_stats) | 610 | if (serv->sv_stats) |
| 610 | serv->sv_stats->netudpcnt++; | 611 | serv->sv_stats->netudpcnt++; |
| @@ -878,9 +879,9 @@ static unsigned int svc_tcp_restore_pages(struct svc_sock *svsk, struct svc_rqst | |||
| 878 | { | 879 | { |
| 879 | unsigned int i, len, npages; | 880 | unsigned int i, len, npages; |
| 880 | 881 | ||
| 881 | if (svsk->sk_tcplen <= sizeof(rpc_fraghdr)) | 882 | if (svsk->sk_datalen == 0) |
| 882 | return 0; | 883 | return 0; |
| 883 | len = svsk->sk_tcplen - sizeof(rpc_fraghdr); | 884 | len = svsk->sk_datalen; |
| 884 | npages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; | 885 | npages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; |
| 885 | for (i = 0; i < npages; i++) { | 886 | for (i = 0; i < npages; i++) { |
| 886 | if (rqstp->rq_pages[i] != NULL) | 887 | if (rqstp->rq_pages[i] != NULL) |
| @@ -897,9 +898,9 @@ static void svc_tcp_save_pages(struct svc_sock *svsk, struct svc_rqst *rqstp) | |||
| 897 | { | 898 | { |
| 898 | unsigned int i, len, npages; | 899 | unsigned int i, len, npages; |
| 899 | 900 | ||
| 900 | if (svsk->sk_tcplen <= sizeof(rpc_fraghdr)) | 901 | if (svsk->sk_datalen == 0) |
| 901 | return; | 902 | return; |
| 902 | len = svsk->sk_tcplen - sizeof(rpc_fraghdr); | 903 | len = svsk->sk_datalen; |
| 903 | npages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; | 904 | npages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; |
| 904 | for (i = 0; i < npages; i++) { | 905 | for (i = 0; i < npages; i++) { |
| 905 | svsk->sk_pages[i] = rqstp->rq_pages[i]; | 906 | svsk->sk_pages[i] = rqstp->rq_pages[i]; |
| @@ -911,9 +912,9 @@ static void svc_tcp_clear_pages(struct svc_sock *svsk) | |||
| 911 | { | 912 | { |
| 912 | unsigned int i, len, npages; | 913 | unsigned int i, len, npages; |
| 913 | 914 | ||
| 914 | if (svsk->sk_tcplen <= sizeof(rpc_fraghdr)) | 915 | if (svsk->sk_datalen == 0) |
| 915 | goto out; | 916 | goto out; |
| 916 | len = svsk->sk_tcplen - sizeof(rpc_fraghdr); | 917 | len = svsk->sk_datalen; |
| 917 | npages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; | 918 | npages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; |
| 918 | for (i = 0; i < npages; i++) { | 919 | for (i = 0; i < npages; i++) { |
| 919 | BUG_ON(svsk->sk_pages[i] == NULL); | 920 | BUG_ON(svsk->sk_pages[i] == NULL); |
| @@ -922,13 +923,12 @@ static void svc_tcp_clear_pages(struct svc_sock *svsk) | |||
| 922 | } | 923 | } |
| 923 | out: | 924 | out: |
| 924 | svsk->sk_tcplen = 0; | 925 | svsk->sk_tcplen = 0; |
| 926 | svsk->sk_datalen = 0; | ||
| 925 | } | 927 | } |
| 926 | 928 | ||
| 927 | /* | 929 | /* |
| 928 | * Receive data. | 930 | * Receive fragment record header. |
| 929 | * If we haven't gotten the record length yet, get the next four bytes. | 931 | * If we haven't gotten the record length yet, get the next four bytes. |
| 930 | * Otherwise try to gobble up as much as possible up to the complete | ||
| 931 | * record length. | ||
| 932 | */ | 932 | */ |
| 933 | static int svc_tcp_recv_record(struct svc_sock *svsk, struct svc_rqst *rqstp) | 933 | static int svc_tcp_recv_record(struct svc_sock *svsk, struct svc_rqst *rqstp) |
| 934 | { | 934 | { |
| @@ -954,32 +954,16 @@ static int svc_tcp_recv_record(struct svc_sock *svsk, struct svc_rqst *rqstp) | |||
| 954 | return -EAGAIN; | 954 | return -EAGAIN; |
| 955 | } | 955 | } |
| 956 | 956 | ||
| 957 | svsk->sk_reclen = ntohl(svsk->sk_reclen); | 957 | dprintk("svc: TCP record, %d bytes\n", svc_sock_reclen(svsk)); |
| 958 | if (!(svsk->sk_reclen & RPC_LAST_STREAM_FRAGMENT)) { | 958 | if (svc_sock_reclen(svsk) + svsk->sk_datalen > |
| 959 | /* FIXME: technically, a record can be fragmented, | 959 | serv->sv_max_mesg) { |
| 960 | * and non-terminal fragments will not have the top | 960 | net_notice_ratelimited("RPC: fragment too large: %d\n", |
| 961 | * bit set in the fragment length header. | 961 | svc_sock_reclen(svsk)); |
| 962 | * But apparently no known nfs clients send fragmented | ||
| 963 | * records. */ | ||
| 964 | net_notice_ratelimited("RPC: multiple fragments per record not supported\n"); | ||
| 965 | goto err_delete; | ||
| 966 | } | ||
| 967 | |||
| 968 | svsk->sk_reclen &= RPC_FRAGMENT_SIZE_MASK; | ||
| 969 | dprintk("svc: TCP record, %d bytes\n", svsk->sk_reclen); | ||
| 970 | if (svsk->sk_reclen > serv->sv_max_mesg) { | ||
| 971 | net_notice_ratelimited("RPC: fragment too large: 0x%08lx\n", | ||
| 972 | (unsigned long)svsk->sk_reclen); | ||
| 973 | goto err_delete; | 962 | goto err_delete; |
| 974 | } | 963 | } |
| 975 | } | 964 | } |
| 976 | 965 | ||
| 977 | if (svsk->sk_reclen < 8) | 966 | return svc_sock_reclen(svsk); |
| 978 | goto err_delete; /* client is nuts. */ | ||
| 979 | |||
| 980 | len = svsk->sk_reclen; | ||
| 981 | |||
| 982 | return len; | ||
| 983 | error: | 967 | error: |
| 984 | dprintk("RPC: TCP recv_record got %d\n", len); | 968 | dprintk("RPC: TCP recv_record got %d\n", len); |
| 985 | return len; | 969 | return len; |
| @@ -1023,7 +1007,7 @@ static int receive_cb_reply(struct svc_sock *svsk, struct svc_rqst *rqstp) | |||
| 1023 | if (dst->iov_len < src->iov_len) | 1007 | if (dst->iov_len < src->iov_len) |
| 1024 | return -EAGAIN; /* whatever; just giving up. */ | 1008 | return -EAGAIN; /* whatever; just giving up. */ |
| 1025 | memcpy(dst->iov_base, src->iov_base, src->iov_len); | 1009 | memcpy(dst->iov_base, src->iov_base, src->iov_len); |
| 1026 | xprt_complete_rqst(req->rq_task, svsk->sk_reclen); | 1010 | xprt_complete_rqst(req->rq_task, rqstp->rq_arg.len); |
| 1027 | rqstp->rq_arg.len = 0; | 1011 | rqstp->rq_arg.len = 0; |
| 1028 | return 0; | 1012 | return 0; |
| 1029 | } | 1013 | } |
| @@ -1042,6 +1026,17 @@ static int copy_pages_to_kvecs(struct kvec *vec, struct page **pages, int len) | |||
| 1042 | return i; | 1026 | return i; |
| 1043 | } | 1027 | } |
| 1044 | 1028 | ||
| 1029 | static void svc_tcp_fragment_received(struct svc_sock *svsk) | ||
| 1030 | { | ||
| 1031 | /* If we have more data, signal svc_xprt_enqueue() to try again */ | ||
| 1032 | if (svc_recv_available(svsk) > sizeof(rpc_fraghdr)) | ||
| 1033 | set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags); | ||
| 1034 | dprintk("svc: TCP %s record (%d bytes)\n", | ||
| 1035 | svc_sock_final_rec(svsk) ? "final" : "nonfinal", | ||
| 1036 | svc_sock_reclen(svsk)); | ||
| 1037 | svsk->sk_tcplen = 0; | ||
| 1038 | svsk->sk_reclen = 0; | ||
| 1039 | } | ||
| 1045 | 1040 | ||
| 1046 | /* | 1041 | /* |
| 1047 | * Receive data from a TCP socket. | 1042 | * Receive data from a TCP socket. |
| @@ -1068,29 +1063,39 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) | |||
| 1068 | goto error; | 1063 | goto error; |
| 1069 | 1064 | ||
| 1070 | base = svc_tcp_restore_pages(svsk, rqstp); | 1065 | base = svc_tcp_restore_pages(svsk, rqstp); |
| 1071 | want = svsk->sk_reclen - base; | 1066 | want = svc_sock_reclen(svsk) - (svsk->sk_tcplen - sizeof(rpc_fraghdr)); |
| 1072 | 1067 | ||
| 1073 | vec = rqstp->rq_vec; | 1068 | vec = rqstp->rq_vec; |
| 1074 | 1069 | ||
| 1075 | pnum = copy_pages_to_kvecs(&vec[0], &rqstp->rq_pages[0], | 1070 | pnum = copy_pages_to_kvecs(&vec[0], &rqstp->rq_pages[0], |
| 1076 | svsk->sk_reclen); | 1071 | svsk->sk_datalen + want); |
| 1077 | 1072 | ||
| 1078 | rqstp->rq_respages = &rqstp->rq_pages[pnum]; | 1073 | rqstp->rq_respages = &rqstp->rq_pages[pnum]; |
| 1074 | rqstp->rq_next_page = rqstp->rq_respages + 1; | ||
| 1079 | 1075 | ||
| 1080 | /* Now receive data */ | 1076 | /* Now receive data */ |
| 1081 | len = svc_partial_recvfrom(rqstp, vec, pnum, want, base); | 1077 | len = svc_partial_recvfrom(rqstp, vec, pnum, want, base); |
| 1082 | if (len >= 0) | 1078 | if (len >= 0) { |
| 1083 | svsk->sk_tcplen += len; | 1079 | svsk->sk_tcplen += len; |
| 1084 | if (len != want) { | 1080 | svsk->sk_datalen += len; |
| 1081 | } | ||
| 1082 | if (len != want || !svc_sock_final_rec(svsk)) { | ||
| 1085 | svc_tcp_save_pages(svsk, rqstp); | 1083 | svc_tcp_save_pages(svsk, rqstp); |
| 1086 | if (len < 0 && len != -EAGAIN) | 1084 | if (len < 0 && len != -EAGAIN) |
| 1087 | goto err_other; | 1085 | goto err_delete; |
| 1088 | dprintk("svc: incomplete TCP record (%d of %d)\n", | 1086 | if (len == want) |
| 1089 | svsk->sk_tcplen, svsk->sk_reclen); | 1087 | svc_tcp_fragment_received(svsk); |
| 1088 | else | ||
| 1089 | dprintk("svc: incomplete TCP record (%d of %d)\n", | ||
| 1090 | (int)(svsk->sk_tcplen - sizeof(rpc_fraghdr)), | ||
| 1091 | svc_sock_reclen(svsk)); | ||
| 1090 | goto err_noclose; | 1092 | goto err_noclose; |
| 1091 | } | 1093 | } |
| 1092 | 1094 | ||
| 1093 | rqstp->rq_arg.len = svsk->sk_reclen; | 1095 | if (svc_sock_reclen(svsk) < 8) |
| 1096 | goto err_delete; /* client is nuts. */ | ||
| 1097 | |||
| 1098 | rqstp->rq_arg.len = svsk->sk_datalen; | ||
| 1094 | rqstp->rq_arg.page_base = 0; | 1099 | rqstp->rq_arg.page_base = 0; |
| 1095 | if (rqstp->rq_arg.len <= rqstp->rq_arg.head[0].iov_len) { | 1100 | if (rqstp->rq_arg.len <= rqstp->rq_arg.head[0].iov_len) { |
| 1096 | rqstp->rq_arg.head[0].iov_len = rqstp->rq_arg.len; | 1101 | rqstp->rq_arg.head[0].iov_len = rqstp->rq_arg.len; |
| @@ -1107,11 +1112,8 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) | |||
| 1107 | len = receive_cb_reply(svsk, rqstp); | 1112 | len = receive_cb_reply(svsk, rqstp); |
| 1108 | 1113 | ||
| 1109 | /* Reset TCP read info */ | 1114 | /* Reset TCP read info */ |
| 1110 | svsk->sk_reclen = 0; | 1115 | svsk->sk_datalen = 0; |
| 1111 | svsk->sk_tcplen = 0; | 1116 | svc_tcp_fragment_received(svsk); |
| 1112 | /* If we have more data, signal svc_xprt_enqueue() to try again */ | ||
| 1113 | if (svc_recv_available(svsk) > sizeof(rpc_fraghdr)) | ||
| 1114 | set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags); | ||
| 1115 | 1117 | ||
| 1116 | if (len < 0) | 1118 | if (len < 0) |
| 1117 | goto error; | 1119 | goto error; |
| @@ -1120,15 +1122,14 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) | |||
| 1120 | if (serv->sv_stats) | 1122 | if (serv->sv_stats) |
| 1121 | serv->sv_stats->nettcpcnt++; | 1123 | serv->sv_stats->nettcpcnt++; |
| 1122 | 1124 | ||
| 1123 | dprintk("svc: TCP complete record (%d bytes)\n", rqstp->rq_arg.len); | ||
| 1124 | return rqstp->rq_arg.len; | 1125 | return rqstp->rq_arg.len; |
| 1125 | 1126 | ||
| 1126 | error: | 1127 | error: |
| 1127 | if (len != -EAGAIN) | 1128 | if (len != -EAGAIN) |
| 1128 | goto err_other; | 1129 | goto err_delete; |
| 1129 | dprintk("RPC: TCP recvfrom got EAGAIN\n"); | 1130 | dprintk("RPC: TCP recvfrom got EAGAIN\n"); |
| 1130 | return 0; | 1131 | return 0; |
| 1131 | err_other: | 1132 | err_delete: |
| 1132 | printk(KERN_NOTICE "%s: recvfrom returned errno %d\n", | 1133 | printk(KERN_NOTICE "%s: recvfrom returned errno %d\n", |
| 1133 | svsk->sk_xprt.xpt_server->sv_name, -len); | 1134 | svsk->sk_xprt.xpt_server->sv_name, -len); |
| 1134 | set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags); | 1135 | set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags); |
| @@ -1305,6 +1306,7 @@ static void svc_tcp_init(struct svc_sock *svsk, struct svc_serv *serv) | |||
| 1305 | 1306 | ||
| 1306 | svsk->sk_reclen = 0; | 1307 | svsk->sk_reclen = 0; |
| 1307 | svsk->sk_tcplen = 0; | 1308 | svsk->sk_tcplen = 0; |
| 1309 | svsk->sk_datalen = 0; | ||
| 1308 | memset(&svsk->sk_pages[0], 0, sizeof(svsk->sk_pages)); | 1310 | memset(&svsk->sk_pages[0], 0, sizeof(svsk->sk_pages)); |
| 1309 | 1311 | ||
| 1310 | tcp_sk(sk)->nonagle |= TCP_NAGLE_OFF; | 1312 | tcp_sk(sk)->nonagle |= TCP_NAGLE_OFF; |
diff --git a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c index 41cb63b623df..0ce75524ed21 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c +++ b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c | |||
| @@ -521,11 +521,11 @@ next_sge: | |||
| 521 | rqstp->rq_pages[ch_no] = NULL; | 521 | rqstp->rq_pages[ch_no] = NULL; |
| 522 | 522 | ||
| 523 | /* | 523 | /* |
| 524 | * Detach res pages. svc_release must see a resused count of | 524 | * Detach res pages. If svc_release sees any it will attempt to |
| 525 | * zero or it will attempt to put them. | 525 | * put them. |
| 526 | */ | 526 | */ |
| 527 | while (rqstp->rq_resused) | 527 | while (rqstp->rq_next_page != rqstp->rq_respages) |
| 528 | rqstp->rq_respages[--rqstp->rq_resused] = NULL; | 528 | *(--rqstp->rq_next_page) = NULL; |
| 529 | 529 | ||
| 530 | return err; | 530 | return err; |
| 531 | } | 531 | } |
| @@ -550,7 +550,7 @@ static int rdma_read_complete(struct svc_rqst *rqstp, | |||
| 550 | 550 | ||
| 551 | /* rq_respages starts after the last arg page */ | 551 | /* rq_respages starts after the last arg page */ |
| 552 | rqstp->rq_respages = &rqstp->rq_arg.pages[page_no]; | 552 | rqstp->rq_respages = &rqstp->rq_arg.pages[page_no]; |
| 553 | rqstp->rq_resused = 0; | 553 | rqstp->rq_next_page = &rqstp->rq_arg.pages[page_no]; |
| 554 | 554 | ||
| 555 | /* Rebuild rq_arg head and tail. */ | 555 | /* Rebuild rq_arg head and tail. */ |
| 556 | rqstp->rq_arg.head[0] = head->arg.head[0]; | 556 | rqstp->rq_arg.head[0] = head->arg.head[0]; |
diff --git a/net/sunrpc/xprtrdma/svc_rdma_sendto.c b/net/sunrpc/xprtrdma/svc_rdma_sendto.c index 42eb7ba0b903..c1d124dc772b 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_sendto.c +++ b/net/sunrpc/xprtrdma/svc_rdma_sendto.c | |||
| @@ -548,6 +548,7 @@ static int send_reply(struct svcxprt_rdma *rdma, | |||
| 548 | int sge_no; | 548 | int sge_no; |
| 549 | int sge_bytes; | 549 | int sge_bytes; |
| 550 | int page_no; | 550 | int page_no; |
| 551 | int pages; | ||
| 551 | int ret; | 552 | int ret; |
| 552 | 553 | ||
| 553 | /* Post a recv buffer to handle another request. */ | 554 | /* Post a recv buffer to handle another request. */ |
| @@ -611,7 +612,8 @@ static int send_reply(struct svcxprt_rdma *rdma, | |||
| 611 | * respages array. They are our pages until the I/O | 612 | * respages array. They are our pages until the I/O |
| 612 | * completes. | 613 | * completes. |
| 613 | */ | 614 | */ |
| 614 | for (page_no = 0; page_no < rqstp->rq_resused; page_no++) { | 615 | pages = rqstp->rq_next_page - rqstp->rq_respages; |
| 616 | for (page_no = 0; page_no < pages; page_no++) { | ||
| 615 | ctxt->pages[page_no+1] = rqstp->rq_respages[page_no]; | 617 | ctxt->pages[page_no+1] = rqstp->rq_respages[page_no]; |
| 616 | ctxt->count++; | 618 | ctxt->count++; |
| 617 | rqstp->rq_respages[page_no] = NULL; | 619 | rqstp->rq_respages[page_no] = NULL; |
