Commit 797a9d797f8483bb67f265c761b76dcd5a077a23
Committed by
J. Bruce Fields
1 parent
4ca1f872cd
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
nfsd: only register cld pipe notifier when CONFIG_NFSD_V4 is enabled
Otherwise, we get a warning or error similar to this when building with CONFIG_NFSD_V4 disabled: ERROR: "nfsd4_cld_block" [fs/nfsd/nfsd.ko] undefined! Fix this by wrapping the calls to rpc_pipefs_notifier_register and ..._unregister in another function and providing no-op replacements when CONFIG_NFSD_V4 is disabled. Reported-by: Paul Gortmaker <paul.gortmaker@windriver.com> Signed-off-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Showing 4 changed files with 21 additions and 5 deletions Inline Diff
fs/nfsd/netns.h
1 | /* | 1 | /* |
2 | * per net namespace data structures for nfsd | 2 | * per net namespace data structures for nfsd |
3 | * | 3 | * |
4 | * Copyright (C) 2012, Jeff Layton <jlayton@redhat.com> | 4 | * Copyright (C) 2012, Jeff Layton <jlayton@redhat.com> |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify it | 6 | * This program is free software; you can redistribute it and/or modify it |
7 | * under the terms of the GNU General Public License as published by the Free | 7 | * under the terms of the GNU General Public License as published by the Free |
8 | * Software Foundation; either version 2 of the License, or (at your option) | 8 | * Software Foundation; either version 2 of the License, or (at your option) |
9 | * any later version. | 9 | * any later version. |
10 | * | 10 | * |
11 | * This program is distributed in the hope that it will be useful, but WITHOUT | 11 | * This program is distributed in the hope that it will be useful, but WITHOUT |
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
14 | * more details. | 14 | * more details. |
15 | * | 15 | * |
16 | * You should have received a copy of the GNU General Public License along with | 16 | * You should have received a copy of the GNU General Public License along with |
17 | * this program; if not, write to the Free Software Foundation, Inc., 51 | 17 | * this program; if not, write to the Free Software Foundation, Inc., 51 |
18 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 18 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #ifndef __NFSD_NETNS_H__ | 21 | #ifndef __NFSD_NETNS_H__ |
22 | #define __NFSD_NETNS_H__ | 22 | #define __NFSD_NETNS_H__ |
23 | 23 | ||
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 | struct cld_net; | 27 | struct cld_net; |
28 | 28 | ||
29 | struct nfsd_net { | 29 | struct nfsd_net { |
30 | struct cld_net *cld_net; | 30 | struct cld_net *cld_net; |
31 | }; | 31 | }; |
32 | 32 | ||
33 | extern int nfsd_net_id; | 33 | extern int nfsd_net_id; |
34 | extern struct notifier_block nfsd4_cld_block; | ||
35 | #endif /* __NFSD_NETNS_H__ */ | 34 | #endif /* __NFSD_NETNS_H__ */ |
36 | 35 |
fs/nfsd/nfs4recover.c
1 | /* | 1 | /* |
2 | * Copyright (c) 2004 The Regents of the University of Michigan. | 2 | * Copyright (c) 2004 The Regents of the University of Michigan. |
3 | * Copyright (c) 2012 Jeff Layton <jlayton@redhat.com> | 3 | * Copyright (c) 2012 Jeff Layton <jlayton@redhat.com> |
4 | * All rights reserved. | 4 | * All rights reserved. |
5 | * | 5 | * |
6 | * Andy Adamson <andros@citi.umich.edu> | 6 | * Andy Adamson <andros@citi.umich.edu> |
7 | * | 7 | * |
8 | * Redistribution and use in source and binary forms, with or without | 8 | * Redistribution and use in source and binary forms, with or without |
9 | * modification, are permitted provided that the following conditions | 9 | * modification, are permitted provided that the following conditions |
10 | * are met: | 10 | * are met: |
11 | * | 11 | * |
12 | * 1. Redistributions of source code must retain the above copyright | 12 | * 1. Redistributions of source code must retain the above copyright |
13 | * notice, this list of conditions and the following disclaimer. | 13 | * notice, this list of conditions and the following disclaimer. |
14 | * 2. Redistributions in binary form must reproduce the above copyright | 14 | * 2. Redistributions in binary form must reproduce the above copyright |
15 | * notice, this list of conditions and the following disclaimer in the | 15 | * notice, this list of conditions and the following disclaimer in the |
16 | * documentation and/or other materials provided with the distribution. | 16 | * documentation and/or other materials provided with the distribution. |
17 | * 3. Neither the name of the University nor the names of its | 17 | * 3. Neither the name of the University nor the names of its |
18 | * contributors may be used to endorse or promote products derived | 18 | * contributors may be used to endorse or promote products derived |
19 | * from this software without specific prior written permission. | 19 | * from this software without specific prior written permission. |
20 | * | 20 | * |
21 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | 21 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED |
22 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | 22 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
23 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | 23 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
24 | * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 24 | * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
26 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 26 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
27 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | 27 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
28 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | 28 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
29 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | 29 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
30 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | 30 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
31 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 31 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
32 | * | 32 | * |
33 | */ | 33 | */ |
34 | 34 | ||
35 | #include <linux/file.h> | 35 | #include <linux/file.h> |
36 | #include <linux/slab.h> | 36 | #include <linux/slab.h> |
37 | #include <linux/namei.h> | 37 | #include <linux/namei.h> |
38 | #include <linux/crypto.h> | 38 | #include <linux/crypto.h> |
39 | #include <linux/sched.h> | 39 | #include <linux/sched.h> |
40 | #include <linux/fs.h> | 40 | #include <linux/fs.h> |
41 | #include <linux/module.h> | 41 | #include <linux/module.h> |
42 | #include <net/net_namespace.h> | 42 | #include <net/net_namespace.h> |
43 | #include <linux/sunrpc/rpc_pipe_fs.h> | 43 | #include <linux/sunrpc/rpc_pipe_fs.h> |
44 | #include <linux/sunrpc/clnt.h> | 44 | #include <linux/sunrpc/clnt.h> |
45 | #include <linux/nfsd/cld.h> | 45 | #include <linux/nfsd/cld.h> |
46 | 46 | ||
47 | #include "nfsd.h" | 47 | #include "nfsd.h" |
48 | #include "state.h" | 48 | #include "state.h" |
49 | #include "vfs.h" | 49 | #include "vfs.h" |
50 | #include "netns.h" | 50 | #include "netns.h" |
51 | 51 | ||
52 | #define NFSDDBG_FACILITY NFSDDBG_PROC | 52 | #define NFSDDBG_FACILITY NFSDDBG_PROC |
53 | 53 | ||
54 | /* Declarations */ | 54 | /* Declarations */ |
55 | struct nfsd4_client_tracking_ops { | 55 | struct nfsd4_client_tracking_ops { |
56 | int (*init)(struct net *); | 56 | int (*init)(struct net *); |
57 | void (*exit)(struct net *); | 57 | void (*exit)(struct net *); |
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 net *, time_t); |
62 | }; | 62 | }; |
63 | 63 | ||
64 | /* Globals */ | 64 | /* Globals */ |
65 | static struct file *rec_file; | 65 | static struct file *rec_file; |
66 | static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery"; | 66 | static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery"; |
67 | static struct nfsd4_client_tracking_ops *client_tracking_ops; | 67 | static struct nfsd4_client_tracking_ops *client_tracking_ops; |
68 | 68 | ||
69 | static int | 69 | static int |
70 | nfs4_save_creds(const struct cred **original_creds) | 70 | nfs4_save_creds(const struct cred **original_creds) |
71 | { | 71 | { |
72 | struct cred *new; | 72 | struct cred *new; |
73 | 73 | ||
74 | new = prepare_creds(); | 74 | new = prepare_creds(); |
75 | if (!new) | 75 | if (!new) |
76 | return -ENOMEM; | 76 | return -ENOMEM; |
77 | 77 | ||
78 | new->fsuid = 0; | 78 | new->fsuid = 0; |
79 | new->fsgid = 0; | 79 | new->fsgid = 0; |
80 | *original_creds = override_creds(new); | 80 | *original_creds = override_creds(new); |
81 | put_cred(new); | 81 | put_cred(new); |
82 | return 0; | 82 | return 0; |
83 | } | 83 | } |
84 | 84 | ||
85 | static void | 85 | static void |
86 | nfs4_reset_creds(const struct cred *original) | 86 | nfs4_reset_creds(const struct cred *original) |
87 | { | 87 | { |
88 | revert_creds(original); | 88 | revert_creds(original); |
89 | } | 89 | } |
90 | 90 | ||
91 | static void | 91 | static void |
92 | md5_to_hex(char *out, char *md5) | 92 | md5_to_hex(char *out, char *md5) |
93 | { | 93 | { |
94 | int i; | 94 | int i; |
95 | 95 | ||
96 | for (i=0; i<16; i++) { | 96 | for (i=0; i<16; i++) { |
97 | unsigned char c = md5[i]; | 97 | unsigned char c = md5[i]; |
98 | 98 | ||
99 | *out++ = '0' + ((c&0xf0)>>4) + (c>=0xa0)*('a'-'9'-1); | 99 | *out++ = '0' + ((c&0xf0)>>4) + (c>=0xa0)*('a'-'9'-1); |
100 | *out++ = '0' + (c&0x0f) + ((c&0x0f)>=0x0a)*('a'-'9'-1); | 100 | *out++ = '0' + (c&0x0f) + ((c&0x0f)>=0x0a)*('a'-'9'-1); |
101 | } | 101 | } |
102 | *out = '\0'; | 102 | *out = '\0'; |
103 | } | 103 | } |
104 | 104 | ||
105 | __be32 | 105 | __be32 |
106 | nfs4_make_rec_clidname(char *dname, struct xdr_netobj *clname) | 106 | nfs4_make_rec_clidname(char *dname, struct xdr_netobj *clname) |
107 | { | 107 | { |
108 | struct xdr_netobj cksum; | 108 | struct xdr_netobj cksum; |
109 | struct hash_desc desc; | 109 | struct hash_desc desc; |
110 | struct scatterlist sg; | 110 | struct scatterlist sg; |
111 | __be32 status = nfserr_jukebox; | 111 | __be32 status = nfserr_jukebox; |
112 | 112 | ||
113 | dprintk("NFSD: nfs4_make_rec_clidname for %.*s\n", | 113 | dprintk("NFSD: nfs4_make_rec_clidname for %.*s\n", |
114 | clname->len, clname->data); | 114 | clname->len, clname->data); |
115 | desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP; | 115 | desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP; |
116 | desc.tfm = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC); | 116 | desc.tfm = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC); |
117 | if (IS_ERR(desc.tfm)) | 117 | if (IS_ERR(desc.tfm)) |
118 | goto out_no_tfm; | 118 | goto out_no_tfm; |
119 | cksum.len = crypto_hash_digestsize(desc.tfm); | 119 | cksum.len = crypto_hash_digestsize(desc.tfm); |
120 | cksum.data = kmalloc(cksum.len, GFP_KERNEL); | 120 | cksum.data = kmalloc(cksum.len, GFP_KERNEL); |
121 | if (cksum.data == NULL) | 121 | if (cksum.data == NULL) |
122 | goto out; | 122 | goto out; |
123 | 123 | ||
124 | sg_init_one(&sg, clname->data, clname->len); | 124 | sg_init_one(&sg, clname->data, clname->len); |
125 | 125 | ||
126 | if (crypto_hash_digest(&desc, &sg, sg.length, cksum.data)) | 126 | if (crypto_hash_digest(&desc, &sg, sg.length, cksum.data)) |
127 | goto out; | 127 | goto out; |
128 | 128 | ||
129 | md5_to_hex(dname, cksum.data); | 129 | md5_to_hex(dname, cksum.data); |
130 | 130 | ||
131 | status = nfs_ok; | 131 | status = nfs_ok; |
132 | out: | 132 | out: |
133 | kfree(cksum.data); | 133 | kfree(cksum.data); |
134 | crypto_free_hash(desc.tfm); | 134 | crypto_free_hash(desc.tfm); |
135 | out_no_tfm: | 135 | out_no_tfm: |
136 | return status; | 136 | return status; |
137 | } | 137 | } |
138 | 138 | ||
139 | static void | 139 | static void |
140 | nfsd4_create_clid_dir(struct nfs4_client *clp) | 140 | nfsd4_create_clid_dir(struct nfs4_client *clp) |
141 | { | 141 | { |
142 | const struct cred *original_cred; | 142 | const struct cred *original_cred; |
143 | char *dname = clp->cl_recdir; | 143 | char *dname = clp->cl_recdir; |
144 | struct dentry *dir, *dentry; | 144 | struct dentry *dir, *dentry; |
145 | int status; | 145 | int status; |
146 | 146 | ||
147 | dprintk("NFSD: nfsd4_create_clid_dir for \"%s\"\n", dname); | 147 | dprintk("NFSD: nfsd4_create_clid_dir for \"%s\"\n", dname); |
148 | 148 | ||
149 | if (test_and_set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) | 149 | if (test_and_set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) |
150 | return; | 150 | return; |
151 | if (!rec_file) | 151 | if (!rec_file) |
152 | return; | 152 | return; |
153 | status = nfs4_save_creds(&original_cred); | 153 | status = nfs4_save_creds(&original_cred); |
154 | if (status < 0) | 154 | if (status < 0) |
155 | return; | 155 | return; |
156 | 156 | ||
157 | dir = rec_file->f_path.dentry; | 157 | dir = rec_file->f_path.dentry; |
158 | /* lock the parent */ | 158 | /* lock the parent */ |
159 | mutex_lock(&dir->d_inode->i_mutex); | 159 | mutex_lock(&dir->d_inode->i_mutex); |
160 | 160 | ||
161 | dentry = lookup_one_len(dname, dir, HEXDIR_LEN-1); | 161 | dentry = lookup_one_len(dname, dir, HEXDIR_LEN-1); |
162 | if (IS_ERR(dentry)) { | 162 | if (IS_ERR(dentry)) { |
163 | status = PTR_ERR(dentry); | 163 | status = PTR_ERR(dentry); |
164 | goto out_unlock; | 164 | goto out_unlock; |
165 | } | 165 | } |
166 | if (dentry->d_inode) | 166 | if (dentry->d_inode) |
167 | /* | 167 | /* |
168 | * In the 4.1 case, where we're called from | 168 | * In the 4.1 case, where we're called from |
169 | * reclaim_complete(), records from the previous reboot | 169 | * reclaim_complete(), records from the previous reboot |
170 | * may still be left, so this is OK. | 170 | * may still be left, so this is OK. |
171 | * | 171 | * |
172 | * In the 4.0 case, we should never get here; but we may | 172 | * In the 4.0 case, we should never get here; but we may |
173 | * as well be forgiving and just succeed silently. | 173 | * as well be forgiving and just succeed silently. |
174 | */ | 174 | */ |
175 | goto out_put; | 175 | goto out_put; |
176 | status = mnt_want_write_file(rec_file); | 176 | status = mnt_want_write_file(rec_file); |
177 | if (status) | 177 | if (status) |
178 | goto out_put; | 178 | goto out_put; |
179 | status = vfs_mkdir(dir->d_inode, dentry, S_IRWXU); | 179 | status = vfs_mkdir(dir->d_inode, dentry, S_IRWXU); |
180 | mnt_drop_write_file(rec_file); | 180 | mnt_drop_write_file(rec_file); |
181 | out_put: | 181 | out_put: |
182 | dput(dentry); | 182 | dput(dentry); |
183 | out_unlock: | 183 | out_unlock: |
184 | mutex_unlock(&dir->d_inode->i_mutex); | 184 | mutex_unlock(&dir->d_inode->i_mutex); |
185 | if (status == 0) | 185 | if (status == 0) |
186 | vfs_fsync(rec_file, 0); | 186 | vfs_fsync(rec_file, 0); |
187 | else | 187 | else |
188 | printk(KERN_ERR "NFSD: failed to write recovery record" | 188 | printk(KERN_ERR "NFSD: failed to write recovery record" |
189 | " (err %d); please check that %s exists" | 189 | " (err %d); please check that %s exists" |
190 | " and is writeable", status, | 190 | " and is writeable", status, |
191 | user_recovery_dirname); | 191 | user_recovery_dirname); |
192 | nfs4_reset_creds(original_cred); | 192 | nfs4_reset_creds(original_cred); |
193 | } | 193 | } |
194 | 194 | ||
195 | typedef int (recdir_func)(struct dentry *, struct dentry *); | 195 | typedef int (recdir_func)(struct dentry *, struct dentry *); |
196 | 196 | ||
197 | struct name_list { | 197 | struct name_list { |
198 | char name[HEXDIR_LEN]; | 198 | char name[HEXDIR_LEN]; |
199 | struct list_head list; | 199 | struct list_head list; |
200 | }; | 200 | }; |
201 | 201 | ||
202 | static int | 202 | static int |
203 | nfsd4_build_namelist(void *arg, const char *name, int namlen, | 203 | nfsd4_build_namelist(void *arg, const char *name, int namlen, |
204 | loff_t offset, u64 ino, unsigned int d_type) | 204 | loff_t offset, u64 ino, unsigned int d_type) |
205 | { | 205 | { |
206 | struct list_head *names = arg; | 206 | struct list_head *names = arg; |
207 | struct name_list *entry; | 207 | struct name_list *entry; |
208 | 208 | ||
209 | if (namlen != HEXDIR_LEN - 1) | 209 | if (namlen != HEXDIR_LEN - 1) |
210 | return 0; | 210 | return 0; |
211 | entry = kmalloc(sizeof(struct name_list), GFP_KERNEL); | 211 | entry = kmalloc(sizeof(struct name_list), GFP_KERNEL); |
212 | if (entry == NULL) | 212 | if (entry == NULL) |
213 | return -ENOMEM; | 213 | return -ENOMEM; |
214 | memcpy(entry->name, name, HEXDIR_LEN - 1); | 214 | memcpy(entry->name, name, HEXDIR_LEN - 1); |
215 | entry->name[HEXDIR_LEN - 1] = '\0'; | 215 | entry->name[HEXDIR_LEN - 1] = '\0'; |
216 | list_add(&entry->list, names); | 216 | list_add(&entry->list, names); |
217 | return 0; | 217 | return 0; |
218 | } | 218 | } |
219 | 219 | ||
220 | static int | 220 | static int |
221 | nfsd4_list_rec_dir(recdir_func *f) | 221 | nfsd4_list_rec_dir(recdir_func *f) |
222 | { | 222 | { |
223 | const struct cred *original_cred; | 223 | const struct cred *original_cred; |
224 | struct dentry *dir = rec_file->f_path.dentry; | 224 | struct dentry *dir = rec_file->f_path.dentry; |
225 | LIST_HEAD(names); | 225 | LIST_HEAD(names); |
226 | int status; | 226 | int status; |
227 | 227 | ||
228 | status = nfs4_save_creds(&original_cred); | 228 | status = nfs4_save_creds(&original_cred); |
229 | if (status < 0) | 229 | if (status < 0) |
230 | return status; | 230 | return status; |
231 | 231 | ||
232 | status = vfs_llseek(rec_file, 0, SEEK_SET); | 232 | status = vfs_llseek(rec_file, 0, SEEK_SET); |
233 | if (status < 0) { | 233 | if (status < 0) { |
234 | nfs4_reset_creds(original_cred); | 234 | nfs4_reset_creds(original_cred); |
235 | return status; | 235 | return status; |
236 | } | 236 | } |
237 | 237 | ||
238 | status = vfs_readdir(rec_file, nfsd4_build_namelist, &names); | 238 | status = vfs_readdir(rec_file, nfsd4_build_namelist, &names); |
239 | mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT); | 239 | mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT); |
240 | while (!list_empty(&names)) { | 240 | while (!list_empty(&names)) { |
241 | struct name_list *entry; | 241 | struct name_list *entry; |
242 | entry = list_entry(names.next, struct name_list, list); | 242 | entry = list_entry(names.next, struct name_list, list); |
243 | if (!status) { | 243 | if (!status) { |
244 | struct dentry *dentry; | 244 | struct dentry *dentry; |
245 | dentry = lookup_one_len(entry->name, dir, HEXDIR_LEN-1); | 245 | dentry = lookup_one_len(entry->name, dir, HEXDIR_LEN-1); |
246 | if (IS_ERR(dentry)) { | 246 | if (IS_ERR(dentry)) { |
247 | status = PTR_ERR(dentry); | 247 | status = PTR_ERR(dentry); |
248 | break; | 248 | break; |
249 | } | 249 | } |
250 | status = f(dir, dentry); | 250 | status = f(dir, dentry); |
251 | dput(dentry); | 251 | dput(dentry); |
252 | } | 252 | } |
253 | list_del(&entry->list); | 253 | list_del(&entry->list); |
254 | kfree(entry); | 254 | kfree(entry); |
255 | } | 255 | } |
256 | mutex_unlock(&dir->d_inode->i_mutex); | 256 | mutex_unlock(&dir->d_inode->i_mutex); |
257 | nfs4_reset_creds(original_cred); | 257 | nfs4_reset_creds(original_cred); |
258 | return status; | 258 | return status; |
259 | } | 259 | } |
260 | 260 | ||
261 | static int | 261 | static int |
262 | nfsd4_unlink_clid_dir(char *name, int namlen) | 262 | nfsd4_unlink_clid_dir(char *name, int namlen) |
263 | { | 263 | { |
264 | struct dentry *dir, *dentry; | 264 | struct dentry *dir, *dentry; |
265 | int status; | 265 | int status; |
266 | 266 | ||
267 | dprintk("NFSD: nfsd4_unlink_clid_dir. name %.*s\n", namlen, name); | 267 | dprintk("NFSD: nfsd4_unlink_clid_dir. name %.*s\n", namlen, name); |
268 | 268 | ||
269 | dir = rec_file->f_path.dentry; | 269 | dir = rec_file->f_path.dentry; |
270 | mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT); | 270 | mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT); |
271 | dentry = lookup_one_len(name, dir, namlen); | 271 | dentry = lookup_one_len(name, dir, namlen); |
272 | if (IS_ERR(dentry)) { | 272 | if (IS_ERR(dentry)) { |
273 | status = PTR_ERR(dentry); | 273 | status = PTR_ERR(dentry); |
274 | goto out_unlock; | 274 | goto out_unlock; |
275 | } | 275 | } |
276 | status = -ENOENT; | 276 | status = -ENOENT; |
277 | if (!dentry->d_inode) | 277 | if (!dentry->d_inode) |
278 | goto out; | 278 | goto out; |
279 | status = vfs_rmdir(dir->d_inode, dentry); | 279 | status = vfs_rmdir(dir->d_inode, dentry); |
280 | out: | 280 | out: |
281 | dput(dentry); | 281 | dput(dentry); |
282 | out_unlock: | 282 | out_unlock: |
283 | mutex_unlock(&dir->d_inode->i_mutex); | 283 | mutex_unlock(&dir->d_inode->i_mutex); |
284 | return status; | 284 | return status; |
285 | } | 285 | } |
286 | 286 | ||
287 | static void | 287 | static void |
288 | nfsd4_remove_clid_dir(struct nfs4_client *clp) | 288 | nfsd4_remove_clid_dir(struct nfs4_client *clp) |
289 | { | 289 | { |
290 | const struct cred *original_cred; | 290 | const struct cred *original_cred; |
291 | int status; | 291 | int status; |
292 | 292 | ||
293 | if (!rec_file || !test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) | 293 | if (!rec_file || !test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) |
294 | return; | 294 | return; |
295 | 295 | ||
296 | status = mnt_want_write_file(rec_file); | 296 | status = mnt_want_write_file(rec_file); |
297 | if (status) | 297 | if (status) |
298 | goto out; | 298 | goto out; |
299 | clear_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags); | 299 | clear_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags); |
300 | 300 | ||
301 | status = nfs4_save_creds(&original_cred); | 301 | status = nfs4_save_creds(&original_cred); |
302 | if (status < 0) | 302 | if (status < 0) |
303 | goto out; | 303 | goto out; |
304 | 304 | ||
305 | status = nfsd4_unlink_clid_dir(clp->cl_recdir, HEXDIR_LEN-1); | 305 | status = nfsd4_unlink_clid_dir(clp->cl_recdir, HEXDIR_LEN-1); |
306 | nfs4_reset_creds(original_cred); | 306 | nfs4_reset_creds(original_cred); |
307 | if (status == 0) | 307 | if (status == 0) |
308 | vfs_fsync(rec_file, 0); | 308 | vfs_fsync(rec_file, 0); |
309 | mnt_drop_write_file(rec_file); | 309 | mnt_drop_write_file(rec_file); |
310 | out: | 310 | out: |
311 | if (status) | 311 | if (status) |
312 | printk("NFSD: Failed to remove expired client state directory" | 312 | printk("NFSD: Failed to remove expired client state directory" |
313 | " %.*s\n", HEXDIR_LEN, clp->cl_recdir); | 313 | " %.*s\n", HEXDIR_LEN, clp->cl_recdir); |
314 | } | 314 | } |
315 | 315 | ||
316 | static int | 316 | static int |
317 | purge_old(struct dentry *parent, struct dentry *child) | 317 | purge_old(struct dentry *parent, struct dentry *child) |
318 | { | 318 | { |
319 | int status; | 319 | int status; |
320 | 320 | ||
321 | if (nfs4_has_reclaimed_state(child->d_name.name, false)) | 321 | if (nfs4_has_reclaimed_state(child->d_name.name, false)) |
322 | return 0; | 322 | return 0; |
323 | 323 | ||
324 | status = vfs_rmdir(parent->d_inode, child); | 324 | status = vfs_rmdir(parent->d_inode, child); |
325 | if (status) | 325 | if (status) |
326 | printk("failed to remove client recovery directory %s\n", | 326 | printk("failed to remove client recovery directory %s\n", |
327 | child->d_name.name); | 327 | child->d_name.name); |
328 | /* Keep trying, success or failure: */ | 328 | /* Keep trying, success or failure: */ |
329 | return 0; | 329 | return 0; |
330 | } | 330 | } |
331 | 331 | ||
332 | static void | 332 | static void |
333 | nfsd4_recdir_purge_old(struct net *net, time_t boot_time) | 333 | nfsd4_recdir_purge_old(struct net *net, time_t boot_time) |
334 | { | 334 | { |
335 | int status; | 335 | int status; |
336 | 336 | ||
337 | if (!rec_file) | 337 | if (!rec_file) |
338 | return; | 338 | return; |
339 | status = mnt_want_write_file(rec_file); | 339 | status = mnt_want_write_file(rec_file); |
340 | if (status) | 340 | if (status) |
341 | goto out; | 341 | goto out; |
342 | status = nfsd4_list_rec_dir(purge_old); | 342 | status = nfsd4_list_rec_dir(purge_old); |
343 | if (status == 0) | 343 | if (status == 0) |
344 | vfs_fsync(rec_file, 0); | 344 | vfs_fsync(rec_file, 0); |
345 | mnt_drop_write_file(rec_file); | 345 | mnt_drop_write_file(rec_file); |
346 | out: | 346 | out: |
347 | if (status) | 347 | if (status) |
348 | printk("nfsd4: failed to purge old clients from recovery" | 348 | printk("nfsd4: failed to purge old clients from recovery" |
349 | " directory %s\n", rec_file->f_path.dentry->d_name.name); | 349 | " directory %s\n", rec_file->f_path.dentry->d_name.name); |
350 | } | 350 | } |
351 | 351 | ||
352 | static int | 352 | static int |
353 | load_recdir(struct dentry *parent, struct dentry *child) | 353 | load_recdir(struct dentry *parent, struct dentry *child) |
354 | { | 354 | { |
355 | if (child->d_name.len != HEXDIR_LEN - 1) { | 355 | if (child->d_name.len != HEXDIR_LEN - 1) { |
356 | printk("nfsd4: illegal name %s in recovery directory\n", | 356 | printk("nfsd4: illegal name %s in recovery directory\n", |
357 | child->d_name.name); | 357 | child->d_name.name); |
358 | /* Keep trying; maybe the others are OK: */ | 358 | /* Keep trying; maybe the others are OK: */ |
359 | return 0; | 359 | return 0; |
360 | } | 360 | } |
361 | nfs4_client_to_reclaim(child->d_name.name); | 361 | nfs4_client_to_reclaim(child->d_name.name); |
362 | return 0; | 362 | return 0; |
363 | } | 363 | } |
364 | 364 | ||
365 | static int | 365 | static int |
366 | nfsd4_recdir_load(void) { | 366 | nfsd4_recdir_load(void) { |
367 | int status; | 367 | int status; |
368 | 368 | ||
369 | if (!rec_file) | 369 | if (!rec_file) |
370 | return 0; | 370 | return 0; |
371 | 371 | ||
372 | status = nfsd4_list_rec_dir(load_recdir); | 372 | status = nfsd4_list_rec_dir(load_recdir); |
373 | if (status) | 373 | if (status) |
374 | printk("nfsd4: failed loading clients from recovery" | 374 | printk("nfsd4: failed loading clients from recovery" |
375 | " directory %s\n", rec_file->f_path.dentry->d_name.name); | 375 | " directory %s\n", rec_file->f_path.dentry->d_name.name); |
376 | return status; | 376 | return status; |
377 | } | 377 | } |
378 | 378 | ||
379 | /* | 379 | /* |
380 | * Hold reference to the recovery directory. | 380 | * Hold reference to the recovery directory. |
381 | */ | 381 | */ |
382 | 382 | ||
383 | static int | 383 | static int |
384 | nfsd4_init_recdir(void) | 384 | nfsd4_init_recdir(void) |
385 | { | 385 | { |
386 | const struct cred *original_cred; | 386 | const struct cred *original_cred; |
387 | int status; | 387 | int status; |
388 | 388 | ||
389 | printk("NFSD: Using %s as the NFSv4 state recovery directory\n", | 389 | printk("NFSD: Using %s as the NFSv4 state recovery directory\n", |
390 | user_recovery_dirname); | 390 | user_recovery_dirname); |
391 | 391 | ||
392 | BUG_ON(rec_file); | 392 | BUG_ON(rec_file); |
393 | 393 | ||
394 | status = nfs4_save_creds(&original_cred); | 394 | status = nfs4_save_creds(&original_cred); |
395 | if (status < 0) { | 395 | if (status < 0) { |
396 | printk("NFSD: Unable to change credentials to find recovery" | 396 | printk("NFSD: Unable to change credentials to find recovery" |
397 | " directory: error %d\n", | 397 | " directory: error %d\n", |
398 | status); | 398 | status); |
399 | return status; | 399 | return status; |
400 | } | 400 | } |
401 | 401 | ||
402 | rec_file = filp_open(user_recovery_dirname, O_RDONLY | O_DIRECTORY, 0); | 402 | rec_file = filp_open(user_recovery_dirname, O_RDONLY | O_DIRECTORY, 0); |
403 | if (IS_ERR(rec_file)) { | 403 | if (IS_ERR(rec_file)) { |
404 | printk("NFSD: unable to find recovery directory %s\n", | 404 | printk("NFSD: unable to find recovery directory %s\n", |
405 | user_recovery_dirname); | 405 | user_recovery_dirname); |
406 | status = PTR_ERR(rec_file); | 406 | status = PTR_ERR(rec_file); |
407 | rec_file = NULL; | 407 | rec_file = NULL; |
408 | } | 408 | } |
409 | 409 | ||
410 | nfs4_reset_creds(original_cred); | 410 | nfs4_reset_creds(original_cred); |
411 | return status; | 411 | return status; |
412 | } | 412 | } |
413 | 413 | ||
414 | static int | 414 | static int |
415 | nfsd4_load_reboot_recovery_data(struct net *net) | 415 | nfsd4_load_reboot_recovery_data(struct net *net) |
416 | { | 416 | { |
417 | int status; | 417 | int status; |
418 | 418 | ||
419 | /* XXX: The legacy code won't work in a container */ | 419 | /* XXX: The legacy code won't work in a container */ |
420 | if (net != &init_net) { | 420 | if (net != &init_net) { |
421 | WARN(1, KERN_ERR "NFSD: attempt to initialize legacy client " | 421 | WARN(1, KERN_ERR "NFSD: attempt to initialize legacy client " |
422 | "tracking in a container!\n"); | 422 | "tracking in a container!\n"); |
423 | return -EINVAL; | 423 | return -EINVAL; |
424 | } | 424 | } |
425 | 425 | ||
426 | nfs4_lock_state(); | 426 | nfs4_lock_state(); |
427 | status = nfsd4_init_recdir(); | 427 | status = nfsd4_init_recdir(); |
428 | if (!status) | 428 | if (!status) |
429 | status = nfsd4_recdir_load(); | 429 | status = nfsd4_recdir_load(); |
430 | nfs4_unlock_state(); | 430 | nfs4_unlock_state(); |
431 | if (status) | 431 | if (status) |
432 | printk(KERN_ERR "NFSD: Failure reading reboot recovery data\n"); | 432 | printk(KERN_ERR "NFSD: Failure reading reboot recovery data\n"); |
433 | return status; | 433 | return status; |
434 | } | 434 | } |
435 | 435 | ||
436 | static void | 436 | static void |
437 | nfsd4_shutdown_recdir(void) | 437 | nfsd4_shutdown_recdir(void) |
438 | { | 438 | { |
439 | if (!rec_file) | 439 | if (!rec_file) |
440 | return; | 440 | return; |
441 | fput(rec_file); | 441 | fput(rec_file); |
442 | rec_file = NULL; | 442 | rec_file = NULL; |
443 | } | 443 | } |
444 | 444 | ||
445 | static void | 445 | static void |
446 | nfsd4_legacy_tracking_exit(struct net *net) | 446 | nfsd4_legacy_tracking_exit(struct net *net) |
447 | { | 447 | { |
448 | nfs4_release_reclaim(); | 448 | nfs4_release_reclaim(); |
449 | nfsd4_shutdown_recdir(); | 449 | nfsd4_shutdown_recdir(); |
450 | } | 450 | } |
451 | 451 | ||
452 | /* | 452 | /* |
453 | * Change the NFSv4 recovery directory to recdir. | 453 | * Change the NFSv4 recovery directory to recdir. |
454 | */ | 454 | */ |
455 | int | 455 | int |
456 | nfs4_reset_recoverydir(char *recdir) | 456 | nfs4_reset_recoverydir(char *recdir) |
457 | { | 457 | { |
458 | int status; | 458 | int status; |
459 | struct path path; | 459 | struct path path; |
460 | 460 | ||
461 | status = kern_path(recdir, LOOKUP_FOLLOW, &path); | 461 | status = kern_path(recdir, LOOKUP_FOLLOW, &path); |
462 | if (status) | 462 | if (status) |
463 | return status; | 463 | return status; |
464 | status = -ENOTDIR; | 464 | status = -ENOTDIR; |
465 | if (S_ISDIR(path.dentry->d_inode->i_mode)) { | 465 | if (S_ISDIR(path.dentry->d_inode->i_mode)) { |
466 | strcpy(user_recovery_dirname, recdir); | 466 | strcpy(user_recovery_dirname, recdir); |
467 | status = 0; | 467 | status = 0; |
468 | } | 468 | } |
469 | path_put(&path); | 469 | path_put(&path); |
470 | return status; | 470 | return status; |
471 | } | 471 | } |
472 | 472 | ||
473 | char * | 473 | char * |
474 | nfs4_recoverydir(void) | 474 | nfs4_recoverydir(void) |
475 | { | 475 | { |
476 | return user_recovery_dirname; | 476 | return user_recovery_dirname; |
477 | } | 477 | } |
478 | 478 | ||
479 | static int | 479 | static int |
480 | nfsd4_check_legacy_client(struct nfs4_client *clp) | 480 | nfsd4_check_legacy_client(struct nfs4_client *clp) |
481 | { | 481 | { |
482 | /* did we already find that this client is stable? */ | 482 | /* did we already find that this client is stable? */ |
483 | if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) | 483 | if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) |
484 | return 0; | 484 | return 0; |
485 | 485 | ||
486 | /* look for it in the reclaim hashtable otherwise */ | 486 | /* look for it in the reclaim hashtable otherwise */ |
487 | if (nfsd4_find_reclaim_client(clp)) { | 487 | if (nfsd4_find_reclaim_client(clp)) { |
488 | set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags); | 488 | set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags); |
489 | return 0; | 489 | return 0; |
490 | } | 490 | } |
491 | 491 | ||
492 | return -ENOENT; | 492 | return -ENOENT; |
493 | } | 493 | } |
494 | 494 | ||
495 | static struct nfsd4_client_tracking_ops nfsd4_legacy_tracking_ops = { | 495 | static struct nfsd4_client_tracking_ops nfsd4_legacy_tracking_ops = { |
496 | .init = nfsd4_load_reboot_recovery_data, | 496 | .init = nfsd4_load_reboot_recovery_data, |
497 | .exit = nfsd4_legacy_tracking_exit, | 497 | .exit = nfsd4_legacy_tracking_exit, |
498 | .create = nfsd4_create_clid_dir, | 498 | .create = nfsd4_create_clid_dir, |
499 | .remove = nfsd4_remove_clid_dir, | 499 | .remove = nfsd4_remove_clid_dir, |
500 | .check = nfsd4_check_legacy_client, | 500 | .check = nfsd4_check_legacy_client, |
501 | .grace_done = nfsd4_recdir_purge_old, | 501 | .grace_done = nfsd4_recdir_purge_old, |
502 | }; | 502 | }; |
503 | 503 | ||
504 | /* Globals */ | 504 | /* Globals */ |
505 | #define NFSD_PIPE_DIR "nfsd" | 505 | #define NFSD_PIPE_DIR "nfsd" |
506 | #define NFSD_CLD_PIPE "cld" | 506 | #define NFSD_CLD_PIPE "cld" |
507 | 507 | ||
508 | /* per-net-ns structure for holding cld upcall info */ | 508 | /* per-net-ns structure for holding cld upcall info */ |
509 | struct cld_net { | 509 | struct cld_net { |
510 | struct rpc_pipe *cn_pipe; | 510 | struct rpc_pipe *cn_pipe; |
511 | spinlock_t cn_lock; | 511 | spinlock_t cn_lock; |
512 | struct list_head cn_list; | 512 | struct list_head cn_list; |
513 | unsigned int cn_xid; | 513 | unsigned int cn_xid; |
514 | }; | 514 | }; |
515 | 515 | ||
516 | struct cld_upcall { | 516 | struct cld_upcall { |
517 | struct list_head cu_list; | 517 | struct list_head cu_list; |
518 | struct cld_net *cu_net; | 518 | struct cld_net *cu_net; |
519 | struct task_struct *cu_task; | 519 | struct task_struct *cu_task; |
520 | struct cld_msg cu_msg; | 520 | struct cld_msg cu_msg; |
521 | }; | 521 | }; |
522 | 522 | ||
523 | static int | 523 | static int |
524 | __cld_pipe_upcall(struct rpc_pipe *pipe, struct cld_msg *cmsg) | 524 | __cld_pipe_upcall(struct rpc_pipe *pipe, struct cld_msg *cmsg) |
525 | { | 525 | { |
526 | int ret; | 526 | int ret; |
527 | struct rpc_pipe_msg msg; | 527 | struct rpc_pipe_msg msg; |
528 | 528 | ||
529 | memset(&msg, 0, sizeof(msg)); | 529 | memset(&msg, 0, sizeof(msg)); |
530 | msg.data = cmsg; | 530 | msg.data = cmsg; |
531 | msg.len = sizeof(*cmsg); | 531 | msg.len = sizeof(*cmsg); |
532 | 532 | ||
533 | /* | 533 | /* |
534 | * Set task state before we queue the upcall. That prevents | 534 | * Set task state before we queue the upcall. That prevents |
535 | * wake_up_process in the downcall from racing with schedule. | 535 | * wake_up_process in the downcall from racing with schedule. |
536 | */ | 536 | */ |
537 | set_current_state(TASK_UNINTERRUPTIBLE); | 537 | set_current_state(TASK_UNINTERRUPTIBLE); |
538 | ret = rpc_queue_upcall(pipe, &msg); | 538 | ret = rpc_queue_upcall(pipe, &msg); |
539 | if (ret < 0) { | 539 | if (ret < 0) { |
540 | set_current_state(TASK_RUNNING); | 540 | set_current_state(TASK_RUNNING); |
541 | goto out; | 541 | goto out; |
542 | } | 542 | } |
543 | 543 | ||
544 | schedule(); | 544 | schedule(); |
545 | set_current_state(TASK_RUNNING); | 545 | set_current_state(TASK_RUNNING); |
546 | 546 | ||
547 | if (msg.errno < 0) | 547 | if (msg.errno < 0) |
548 | ret = msg.errno; | 548 | ret = msg.errno; |
549 | out: | 549 | out: |
550 | return ret; | 550 | return ret; |
551 | } | 551 | } |
552 | 552 | ||
553 | static int | 553 | static int |
554 | cld_pipe_upcall(struct rpc_pipe *pipe, struct cld_msg *cmsg) | 554 | cld_pipe_upcall(struct rpc_pipe *pipe, struct cld_msg *cmsg) |
555 | { | 555 | { |
556 | int ret; | 556 | int ret; |
557 | 557 | ||
558 | /* | 558 | /* |
559 | * -EAGAIN occurs when pipe is closed and reopened while there are | 559 | * -EAGAIN occurs when pipe is closed and reopened while there are |
560 | * upcalls queued. | 560 | * upcalls queued. |
561 | */ | 561 | */ |
562 | do { | 562 | do { |
563 | ret = __cld_pipe_upcall(pipe, cmsg); | 563 | ret = __cld_pipe_upcall(pipe, cmsg); |
564 | } while (ret == -EAGAIN); | 564 | } while (ret == -EAGAIN); |
565 | 565 | ||
566 | return ret; | 566 | return ret; |
567 | } | 567 | } |
568 | 568 | ||
569 | static ssize_t | 569 | static ssize_t |
570 | cld_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) | 570 | cld_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) |
571 | { | 571 | { |
572 | struct cld_upcall *tmp, *cup; | 572 | struct cld_upcall *tmp, *cup; |
573 | struct cld_msg *cmsg = (struct cld_msg *)src; | 573 | struct cld_msg *cmsg = (struct cld_msg *)src; |
574 | uint32_t xid; | 574 | uint32_t xid; |
575 | struct nfsd_net *nn = net_generic(filp->f_dentry->d_sb->s_fs_info, | 575 | struct nfsd_net *nn = net_generic(filp->f_dentry->d_sb->s_fs_info, |
576 | nfsd_net_id); | 576 | nfsd_net_id); |
577 | struct cld_net *cn = nn->cld_net; | 577 | struct cld_net *cn = nn->cld_net; |
578 | 578 | ||
579 | if (mlen != sizeof(*cmsg)) { | 579 | if (mlen != sizeof(*cmsg)) { |
580 | dprintk("%s: got %lu bytes, expected %lu\n", __func__, mlen, | 580 | dprintk("%s: got %lu bytes, expected %lu\n", __func__, mlen, |
581 | sizeof(*cmsg)); | 581 | sizeof(*cmsg)); |
582 | return -EINVAL; | 582 | return -EINVAL; |
583 | } | 583 | } |
584 | 584 | ||
585 | /* copy just the xid so we can try to find that */ | 585 | /* copy just the xid so we can try to find that */ |
586 | if (copy_from_user(&xid, &cmsg->cm_xid, sizeof(xid)) != 0) { | 586 | if (copy_from_user(&xid, &cmsg->cm_xid, sizeof(xid)) != 0) { |
587 | dprintk("%s: error when copying xid from userspace", __func__); | 587 | dprintk("%s: error when copying xid from userspace", __func__); |
588 | return -EFAULT; | 588 | return -EFAULT; |
589 | } | 589 | } |
590 | 590 | ||
591 | /* walk the list and find corresponding xid */ | 591 | /* walk the list and find corresponding xid */ |
592 | cup = NULL; | 592 | cup = NULL; |
593 | spin_lock(&cn->cn_lock); | 593 | spin_lock(&cn->cn_lock); |
594 | list_for_each_entry(tmp, &cn->cn_list, cu_list) { | 594 | list_for_each_entry(tmp, &cn->cn_list, cu_list) { |
595 | if (get_unaligned(&tmp->cu_msg.cm_xid) == xid) { | 595 | if (get_unaligned(&tmp->cu_msg.cm_xid) == xid) { |
596 | cup = tmp; | 596 | cup = tmp; |
597 | list_del_init(&cup->cu_list); | 597 | list_del_init(&cup->cu_list); |
598 | break; | 598 | break; |
599 | } | 599 | } |
600 | } | 600 | } |
601 | spin_unlock(&cn->cn_lock); | 601 | spin_unlock(&cn->cn_lock); |
602 | 602 | ||
603 | /* couldn't find upcall? */ | 603 | /* couldn't find upcall? */ |
604 | if (!cup) { | 604 | if (!cup) { |
605 | dprintk("%s: couldn't find upcall -- xid=%u\n", __func__, xid); | 605 | dprintk("%s: couldn't find upcall -- xid=%u\n", __func__, xid); |
606 | return -EINVAL; | 606 | return -EINVAL; |
607 | } | 607 | } |
608 | 608 | ||
609 | if (copy_from_user(&cup->cu_msg, src, mlen) != 0) | 609 | if (copy_from_user(&cup->cu_msg, src, mlen) != 0) |
610 | return -EFAULT; | 610 | return -EFAULT; |
611 | 611 | ||
612 | wake_up_process(cup->cu_task); | 612 | wake_up_process(cup->cu_task); |
613 | return mlen; | 613 | return mlen; |
614 | } | 614 | } |
615 | 615 | ||
616 | static void | 616 | static void |
617 | cld_pipe_destroy_msg(struct rpc_pipe_msg *msg) | 617 | cld_pipe_destroy_msg(struct rpc_pipe_msg *msg) |
618 | { | 618 | { |
619 | struct cld_msg *cmsg = msg->data; | 619 | struct cld_msg *cmsg = msg->data; |
620 | struct cld_upcall *cup = container_of(cmsg, struct cld_upcall, | 620 | struct cld_upcall *cup = container_of(cmsg, struct cld_upcall, |
621 | cu_msg); | 621 | cu_msg); |
622 | 622 | ||
623 | /* errno >= 0 means we got a downcall */ | 623 | /* errno >= 0 means we got a downcall */ |
624 | if (msg->errno >= 0) | 624 | if (msg->errno >= 0) |
625 | return; | 625 | return; |
626 | 626 | ||
627 | wake_up_process(cup->cu_task); | 627 | wake_up_process(cup->cu_task); |
628 | } | 628 | } |
629 | 629 | ||
630 | static const struct rpc_pipe_ops cld_upcall_ops = { | 630 | static const struct rpc_pipe_ops cld_upcall_ops = { |
631 | .upcall = rpc_pipe_generic_upcall, | 631 | .upcall = rpc_pipe_generic_upcall, |
632 | .downcall = cld_pipe_downcall, | 632 | .downcall = cld_pipe_downcall, |
633 | .destroy_msg = cld_pipe_destroy_msg, | 633 | .destroy_msg = cld_pipe_destroy_msg, |
634 | }; | 634 | }; |
635 | 635 | ||
636 | static struct dentry * | 636 | static struct dentry * |
637 | nfsd4_cld_register_sb(struct super_block *sb, struct rpc_pipe *pipe) | 637 | nfsd4_cld_register_sb(struct super_block *sb, struct rpc_pipe *pipe) |
638 | { | 638 | { |
639 | struct dentry *dir, *dentry; | 639 | struct dentry *dir, *dentry; |
640 | 640 | ||
641 | dir = rpc_d_lookup_sb(sb, NFSD_PIPE_DIR); | 641 | dir = rpc_d_lookup_sb(sb, NFSD_PIPE_DIR); |
642 | if (dir == NULL) | 642 | if (dir == NULL) |
643 | return ERR_PTR(-ENOENT); | 643 | return ERR_PTR(-ENOENT); |
644 | dentry = rpc_mkpipe_dentry(dir, NFSD_CLD_PIPE, NULL, pipe); | 644 | dentry = rpc_mkpipe_dentry(dir, NFSD_CLD_PIPE, NULL, pipe); |
645 | dput(dir); | 645 | dput(dir); |
646 | return dentry; | 646 | return dentry; |
647 | } | 647 | } |
648 | 648 | ||
649 | static void | 649 | static void |
650 | nfsd4_cld_unregister_sb(struct rpc_pipe *pipe) | 650 | nfsd4_cld_unregister_sb(struct rpc_pipe *pipe) |
651 | { | 651 | { |
652 | if (pipe->dentry) | 652 | if (pipe->dentry) |
653 | rpc_unlink(pipe->dentry); | 653 | rpc_unlink(pipe->dentry); |
654 | } | 654 | } |
655 | 655 | ||
656 | static struct dentry * | 656 | static struct dentry * |
657 | nfsd4_cld_register_net(struct net *net, struct rpc_pipe *pipe) | 657 | nfsd4_cld_register_net(struct net *net, struct rpc_pipe *pipe) |
658 | { | 658 | { |
659 | struct super_block *sb; | 659 | struct super_block *sb; |
660 | struct dentry *dentry; | 660 | struct dentry *dentry; |
661 | 661 | ||
662 | sb = rpc_get_sb_net(net); | 662 | sb = rpc_get_sb_net(net); |
663 | if (!sb) | 663 | if (!sb) |
664 | return NULL; | 664 | return NULL; |
665 | dentry = nfsd4_cld_register_sb(sb, pipe); | 665 | dentry = nfsd4_cld_register_sb(sb, pipe); |
666 | rpc_put_sb_net(net); | 666 | rpc_put_sb_net(net); |
667 | return dentry; | 667 | return dentry; |
668 | } | 668 | } |
669 | 669 | ||
670 | static void | 670 | static void |
671 | nfsd4_cld_unregister_net(struct net *net, struct rpc_pipe *pipe) | 671 | nfsd4_cld_unregister_net(struct net *net, struct rpc_pipe *pipe) |
672 | { | 672 | { |
673 | struct super_block *sb; | 673 | struct super_block *sb; |
674 | 674 | ||
675 | sb = rpc_get_sb_net(net); | 675 | sb = rpc_get_sb_net(net); |
676 | if (sb) { | 676 | if (sb) { |
677 | nfsd4_cld_unregister_sb(pipe); | 677 | nfsd4_cld_unregister_sb(pipe); |
678 | rpc_put_sb_net(net); | 678 | rpc_put_sb_net(net); |
679 | } | 679 | } |
680 | } | 680 | } |
681 | 681 | ||
682 | /* Initialize rpc_pipefs pipe for communication with client tracking daemon */ | 682 | /* Initialize rpc_pipefs pipe for communication with client tracking daemon */ |
683 | static int | 683 | static int |
684 | nfsd4_init_cld_pipe(struct net *net) | 684 | nfsd4_init_cld_pipe(struct net *net) |
685 | { | 685 | { |
686 | int ret; | 686 | int ret; |
687 | struct dentry *dentry; | 687 | struct dentry *dentry; |
688 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | 688 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); |
689 | struct cld_net *cn; | 689 | struct cld_net *cn; |
690 | 690 | ||
691 | if (nn->cld_net) | 691 | if (nn->cld_net) |
692 | return 0; | 692 | return 0; |
693 | 693 | ||
694 | cn = kzalloc(sizeof(*cn), GFP_KERNEL); | 694 | cn = kzalloc(sizeof(*cn), GFP_KERNEL); |
695 | if (!cn) { | 695 | if (!cn) { |
696 | ret = -ENOMEM; | 696 | ret = -ENOMEM; |
697 | goto err; | 697 | goto err; |
698 | } | 698 | } |
699 | 699 | ||
700 | cn->cn_pipe = rpc_mkpipe_data(&cld_upcall_ops, RPC_PIPE_WAIT_FOR_OPEN); | 700 | cn->cn_pipe = rpc_mkpipe_data(&cld_upcall_ops, RPC_PIPE_WAIT_FOR_OPEN); |
701 | if (IS_ERR(cn->cn_pipe)) { | 701 | if (IS_ERR(cn->cn_pipe)) { |
702 | ret = PTR_ERR(cn->cn_pipe); | 702 | ret = PTR_ERR(cn->cn_pipe); |
703 | goto err; | 703 | goto err; |
704 | } | 704 | } |
705 | spin_lock_init(&cn->cn_lock); | 705 | spin_lock_init(&cn->cn_lock); |
706 | INIT_LIST_HEAD(&cn->cn_list); | 706 | INIT_LIST_HEAD(&cn->cn_list); |
707 | 707 | ||
708 | dentry = nfsd4_cld_register_net(net, cn->cn_pipe); | 708 | dentry = nfsd4_cld_register_net(net, cn->cn_pipe); |
709 | if (IS_ERR(dentry)) { | 709 | if (IS_ERR(dentry)) { |
710 | ret = PTR_ERR(dentry); | 710 | ret = PTR_ERR(dentry); |
711 | goto err_destroy_data; | 711 | goto err_destroy_data; |
712 | } | 712 | } |
713 | 713 | ||
714 | cn->cn_pipe->dentry = dentry; | 714 | cn->cn_pipe->dentry = dentry; |
715 | nn->cld_net = cn; | 715 | nn->cld_net = cn; |
716 | return 0; | 716 | return 0; |
717 | 717 | ||
718 | err_destroy_data: | 718 | err_destroy_data: |
719 | rpc_destroy_pipe_data(cn->cn_pipe); | 719 | rpc_destroy_pipe_data(cn->cn_pipe); |
720 | err: | 720 | err: |
721 | kfree(cn); | 721 | kfree(cn); |
722 | printk(KERN_ERR "NFSD: unable to create nfsdcld upcall pipe (%d)\n", | 722 | printk(KERN_ERR "NFSD: unable to create nfsdcld upcall pipe (%d)\n", |
723 | ret); | 723 | ret); |
724 | return ret; | 724 | return ret; |
725 | } | 725 | } |
726 | 726 | ||
727 | static void | 727 | static void |
728 | nfsd4_remove_cld_pipe(struct net *net) | 728 | nfsd4_remove_cld_pipe(struct net *net) |
729 | { | 729 | { |
730 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | 730 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); |
731 | struct cld_net *cn = nn->cld_net; | 731 | struct cld_net *cn = nn->cld_net; |
732 | 732 | ||
733 | nfsd4_cld_unregister_net(net, cn->cn_pipe); | 733 | nfsd4_cld_unregister_net(net, cn->cn_pipe); |
734 | rpc_destroy_pipe_data(cn->cn_pipe); | 734 | rpc_destroy_pipe_data(cn->cn_pipe); |
735 | kfree(nn->cld_net); | 735 | kfree(nn->cld_net); |
736 | nn->cld_net = NULL; | 736 | nn->cld_net = NULL; |
737 | } | 737 | } |
738 | 738 | ||
739 | static struct cld_upcall * | 739 | static struct cld_upcall * |
740 | alloc_cld_upcall(struct cld_net *cn) | 740 | alloc_cld_upcall(struct cld_net *cn) |
741 | { | 741 | { |
742 | struct cld_upcall *new, *tmp; | 742 | struct cld_upcall *new, *tmp; |
743 | 743 | ||
744 | new = kzalloc(sizeof(*new), GFP_KERNEL); | 744 | new = kzalloc(sizeof(*new), GFP_KERNEL); |
745 | if (!new) | 745 | if (!new) |
746 | return new; | 746 | return new; |
747 | 747 | ||
748 | /* FIXME: hard cap on number in flight? */ | 748 | /* FIXME: hard cap on number in flight? */ |
749 | restart_search: | 749 | restart_search: |
750 | spin_lock(&cn->cn_lock); | 750 | spin_lock(&cn->cn_lock); |
751 | list_for_each_entry(tmp, &cn->cn_list, cu_list) { | 751 | list_for_each_entry(tmp, &cn->cn_list, cu_list) { |
752 | if (tmp->cu_msg.cm_xid == cn->cn_xid) { | 752 | if (tmp->cu_msg.cm_xid == cn->cn_xid) { |
753 | cn->cn_xid++; | 753 | cn->cn_xid++; |
754 | spin_unlock(&cn->cn_lock); | 754 | spin_unlock(&cn->cn_lock); |
755 | goto restart_search; | 755 | goto restart_search; |
756 | } | 756 | } |
757 | } | 757 | } |
758 | new->cu_task = current; | 758 | new->cu_task = current; |
759 | new->cu_msg.cm_vers = CLD_UPCALL_VERSION; | 759 | new->cu_msg.cm_vers = CLD_UPCALL_VERSION; |
760 | put_unaligned(cn->cn_xid++, &new->cu_msg.cm_xid); | 760 | put_unaligned(cn->cn_xid++, &new->cu_msg.cm_xid); |
761 | new->cu_net = cn; | 761 | new->cu_net = cn; |
762 | list_add(&new->cu_list, &cn->cn_list); | 762 | list_add(&new->cu_list, &cn->cn_list); |
763 | spin_unlock(&cn->cn_lock); | 763 | spin_unlock(&cn->cn_lock); |
764 | 764 | ||
765 | dprintk("%s: allocated xid %u\n", __func__, new->cu_msg.cm_xid); | 765 | dprintk("%s: allocated xid %u\n", __func__, new->cu_msg.cm_xid); |
766 | 766 | ||
767 | return new; | 767 | return new; |
768 | } | 768 | } |
769 | 769 | ||
770 | static void | 770 | static void |
771 | free_cld_upcall(struct cld_upcall *victim) | 771 | free_cld_upcall(struct cld_upcall *victim) |
772 | { | 772 | { |
773 | struct cld_net *cn = victim->cu_net; | 773 | struct cld_net *cn = victim->cu_net; |
774 | 774 | ||
775 | spin_lock(&cn->cn_lock); | 775 | spin_lock(&cn->cn_lock); |
776 | list_del(&victim->cu_list); | 776 | list_del(&victim->cu_list); |
777 | spin_unlock(&cn->cn_lock); | 777 | spin_unlock(&cn->cn_lock); |
778 | kfree(victim); | 778 | kfree(victim); |
779 | } | 779 | } |
780 | 780 | ||
781 | /* Ask daemon to create a new record */ | 781 | /* Ask daemon to create a new record */ |
782 | static void | 782 | static void |
783 | nfsd4_cld_create(struct nfs4_client *clp) | 783 | nfsd4_cld_create(struct nfs4_client *clp) |
784 | { | 784 | { |
785 | int ret; | 785 | int ret; |
786 | struct cld_upcall *cup; | 786 | struct cld_upcall *cup; |
787 | /* FIXME: determine net from clp */ | 787 | /* FIXME: determine net from clp */ |
788 | struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); | 788 | struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); |
789 | struct cld_net *cn = nn->cld_net; | 789 | struct cld_net *cn = nn->cld_net; |
790 | 790 | ||
791 | /* Don't upcall if it's already stored */ | 791 | /* Don't upcall if it's already stored */ |
792 | if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) | 792 | if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) |
793 | return; | 793 | return; |
794 | 794 | ||
795 | cup = alloc_cld_upcall(cn); | 795 | cup = alloc_cld_upcall(cn); |
796 | if (!cup) { | 796 | if (!cup) { |
797 | ret = -ENOMEM; | 797 | ret = -ENOMEM; |
798 | goto out_err; | 798 | goto out_err; |
799 | } | 799 | } |
800 | 800 | ||
801 | cup->cu_msg.cm_cmd = Cld_Create; | 801 | cup->cu_msg.cm_cmd = Cld_Create; |
802 | cup->cu_msg.cm_u.cm_name.cn_len = clp->cl_name.len; | 802 | cup->cu_msg.cm_u.cm_name.cn_len = clp->cl_name.len; |
803 | memcpy(cup->cu_msg.cm_u.cm_name.cn_id, clp->cl_name.data, | 803 | memcpy(cup->cu_msg.cm_u.cm_name.cn_id, clp->cl_name.data, |
804 | clp->cl_name.len); | 804 | clp->cl_name.len); |
805 | 805 | ||
806 | ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg); | 806 | ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg); |
807 | if (!ret) { | 807 | if (!ret) { |
808 | ret = cup->cu_msg.cm_status; | 808 | ret = cup->cu_msg.cm_status; |
809 | set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags); | 809 | set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags); |
810 | } | 810 | } |
811 | 811 | ||
812 | free_cld_upcall(cup); | 812 | free_cld_upcall(cup); |
813 | out_err: | 813 | out_err: |
814 | if (ret) | 814 | if (ret) |
815 | printk(KERN_ERR "NFSD: Unable to create client " | 815 | printk(KERN_ERR "NFSD: Unable to create client " |
816 | "record on stable storage: %d\n", ret); | 816 | "record on stable storage: %d\n", ret); |
817 | } | 817 | } |
818 | 818 | ||
819 | /* Ask daemon to create a new record */ | 819 | /* Ask daemon to create a new record */ |
820 | static void | 820 | static void |
821 | nfsd4_cld_remove(struct nfs4_client *clp) | 821 | nfsd4_cld_remove(struct nfs4_client *clp) |
822 | { | 822 | { |
823 | int ret; | 823 | int ret; |
824 | struct cld_upcall *cup; | 824 | struct cld_upcall *cup; |
825 | /* FIXME: determine net from clp */ | 825 | /* FIXME: determine net from clp */ |
826 | struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); | 826 | struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); |
827 | struct cld_net *cn = nn->cld_net; | 827 | struct cld_net *cn = nn->cld_net; |
828 | 828 | ||
829 | /* Don't upcall if it's already removed */ | 829 | /* Don't upcall if it's already removed */ |
830 | if (!test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) | 830 | if (!test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) |
831 | return; | 831 | return; |
832 | 832 | ||
833 | cup = alloc_cld_upcall(cn); | 833 | cup = alloc_cld_upcall(cn); |
834 | if (!cup) { | 834 | if (!cup) { |
835 | ret = -ENOMEM; | 835 | ret = -ENOMEM; |
836 | goto out_err; | 836 | goto out_err; |
837 | } | 837 | } |
838 | 838 | ||
839 | cup->cu_msg.cm_cmd = Cld_Remove; | 839 | cup->cu_msg.cm_cmd = Cld_Remove; |
840 | cup->cu_msg.cm_u.cm_name.cn_len = clp->cl_name.len; | 840 | cup->cu_msg.cm_u.cm_name.cn_len = clp->cl_name.len; |
841 | memcpy(cup->cu_msg.cm_u.cm_name.cn_id, clp->cl_name.data, | 841 | memcpy(cup->cu_msg.cm_u.cm_name.cn_id, clp->cl_name.data, |
842 | clp->cl_name.len); | 842 | clp->cl_name.len); |
843 | 843 | ||
844 | ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg); | 844 | ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg); |
845 | if (!ret) { | 845 | if (!ret) { |
846 | ret = cup->cu_msg.cm_status; | 846 | ret = cup->cu_msg.cm_status; |
847 | clear_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags); | 847 | clear_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags); |
848 | } | 848 | } |
849 | 849 | ||
850 | free_cld_upcall(cup); | 850 | free_cld_upcall(cup); |
851 | out_err: | 851 | out_err: |
852 | if (ret) | 852 | if (ret) |
853 | printk(KERN_ERR "NFSD: Unable to remove client " | 853 | printk(KERN_ERR "NFSD: Unable to remove client " |
854 | "record from stable storage: %d\n", ret); | 854 | "record from stable storage: %d\n", ret); |
855 | } | 855 | } |
856 | 856 | ||
857 | /* Check for presence of a record, and update its timestamp */ | 857 | /* Check for presence of a record, and update its timestamp */ |
858 | static int | 858 | static int |
859 | nfsd4_cld_check(struct nfs4_client *clp) | 859 | nfsd4_cld_check(struct nfs4_client *clp) |
860 | { | 860 | { |
861 | int ret; | 861 | int ret; |
862 | struct cld_upcall *cup; | 862 | struct cld_upcall *cup; |
863 | /* FIXME: determine net from clp */ | 863 | /* FIXME: determine net from clp */ |
864 | struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); | 864 | struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); |
865 | struct cld_net *cn = nn->cld_net; | 865 | struct cld_net *cn = nn->cld_net; |
866 | 866 | ||
867 | /* Don't upcall if one was already stored during this grace pd */ | 867 | /* Don't upcall if one was already stored during this grace pd */ |
868 | if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) | 868 | if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) |
869 | return 0; | 869 | return 0; |
870 | 870 | ||
871 | cup = alloc_cld_upcall(cn); | 871 | cup = alloc_cld_upcall(cn); |
872 | if (!cup) { | 872 | if (!cup) { |
873 | printk(KERN_ERR "NFSD: Unable to check client record on " | 873 | printk(KERN_ERR "NFSD: Unable to check client record on " |
874 | "stable storage: %d\n", -ENOMEM); | 874 | "stable storage: %d\n", -ENOMEM); |
875 | return -ENOMEM; | 875 | return -ENOMEM; |
876 | } | 876 | } |
877 | 877 | ||
878 | cup->cu_msg.cm_cmd = Cld_Check; | 878 | cup->cu_msg.cm_cmd = Cld_Check; |
879 | cup->cu_msg.cm_u.cm_name.cn_len = clp->cl_name.len; | 879 | cup->cu_msg.cm_u.cm_name.cn_len = clp->cl_name.len; |
880 | memcpy(cup->cu_msg.cm_u.cm_name.cn_id, clp->cl_name.data, | 880 | memcpy(cup->cu_msg.cm_u.cm_name.cn_id, clp->cl_name.data, |
881 | clp->cl_name.len); | 881 | clp->cl_name.len); |
882 | 882 | ||
883 | ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg); | 883 | ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg); |
884 | if (!ret) { | 884 | if (!ret) { |
885 | ret = cup->cu_msg.cm_status; | 885 | ret = cup->cu_msg.cm_status; |
886 | set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags); | 886 | set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags); |
887 | } | 887 | } |
888 | 888 | ||
889 | free_cld_upcall(cup); | 889 | free_cld_upcall(cup); |
890 | return ret; | 890 | return ret; |
891 | } | 891 | } |
892 | 892 | ||
893 | static void | 893 | static void |
894 | nfsd4_cld_grace_done(struct net *net, time_t boot_time) | 894 | nfsd4_cld_grace_done(struct net *net, time_t boot_time) |
895 | { | 895 | { |
896 | int ret; | 896 | int ret; |
897 | struct cld_upcall *cup; | 897 | struct cld_upcall *cup; |
898 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | 898 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); |
899 | struct cld_net *cn = nn->cld_net; | 899 | struct cld_net *cn = nn->cld_net; |
900 | 900 | ||
901 | cup = alloc_cld_upcall(cn); | 901 | cup = alloc_cld_upcall(cn); |
902 | if (!cup) { | 902 | if (!cup) { |
903 | ret = -ENOMEM; | 903 | ret = -ENOMEM; |
904 | goto out_err; | 904 | goto out_err; |
905 | } | 905 | } |
906 | 906 | ||
907 | cup->cu_msg.cm_cmd = Cld_GraceDone; | 907 | cup->cu_msg.cm_cmd = Cld_GraceDone; |
908 | cup->cu_msg.cm_u.cm_gracetime = (int64_t)boot_time; | 908 | cup->cu_msg.cm_u.cm_gracetime = (int64_t)boot_time; |
909 | ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg); | 909 | ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg); |
910 | if (!ret) | 910 | if (!ret) |
911 | ret = cup->cu_msg.cm_status; | 911 | ret = cup->cu_msg.cm_status; |
912 | 912 | ||
913 | free_cld_upcall(cup); | 913 | free_cld_upcall(cup); |
914 | out_err: | 914 | out_err: |
915 | if (ret) | 915 | if (ret) |
916 | printk(KERN_ERR "NFSD: Unable to end grace period: %d\n", ret); | 916 | printk(KERN_ERR "NFSD: Unable to end grace period: %d\n", ret); |
917 | } | 917 | } |
918 | 918 | ||
919 | static struct nfsd4_client_tracking_ops nfsd4_cld_tracking_ops = { | 919 | static struct nfsd4_client_tracking_ops nfsd4_cld_tracking_ops = { |
920 | .init = nfsd4_init_cld_pipe, | 920 | .init = nfsd4_init_cld_pipe, |
921 | .exit = nfsd4_remove_cld_pipe, | 921 | .exit = nfsd4_remove_cld_pipe, |
922 | .create = nfsd4_cld_create, | 922 | .create = nfsd4_cld_create, |
923 | .remove = nfsd4_cld_remove, | 923 | .remove = nfsd4_cld_remove, |
924 | .check = nfsd4_cld_check, | 924 | .check = nfsd4_cld_check, |
925 | .grace_done = nfsd4_cld_grace_done, | 925 | .grace_done = nfsd4_cld_grace_done, |
926 | }; | 926 | }; |
927 | 927 | ||
928 | int | 928 | int |
929 | nfsd4_client_tracking_init(struct net *net) | 929 | nfsd4_client_tracking_init(struct net *net) |
930 | { | 930 | { |
931 | int status; | 931 | int status; |
932 | struct path path; | 932 | struct path path; |
933 | 933 | ||
934 | if (!client_tracking_ops) { | 934 | if (!client_tracking_ops) { |
935 | client_tracking_ops = &nfsd4_cld_tracking_ops; | 935 | client_tracking_ops = &nfsd4_cld_tracking_ops; |
936 | status = kern_path(nfs4_recoverydir(), LOOKUP_FOLLOW, &path); | 936 | status = kern_path(nfs4_recoverydir(), LOOKUP_FOLLOW, &path); |
937 | if (!status) { | 937 | if (!status) { |
938 | if (S_ISDIR(path.dentry->d_inode->i_mode)) | 938 | if (S_ISDIR(path.dentry->d_inode->i_mode)) |
939 | client_tracking_ops = | 939 | client_tracking_ops = |
940 | &nfsd4_legacy_tracking_ops; | 940 | &nfsd4_legacy_tracking_ops; |
941 | path_put(&path); | 941 | path_put(&path); |
942 | } | 942 | } |
943 | } | 943 | } |
944 | 944 | ||
945 | status = client_tracking_ops->init(net); | 945 | status = client_tracking_ops->init(net); |
946 | if (status) { | 946 | if (status) { |
947 | printk(KERN_WARNING "NFSD: Unable to initialize client " | 947 | printk(KERN_WARNING "NFSD: Unable to initialize client " |
948 | "recovery tracking! (%d)\n", status); | 948 | "recovery tracking! (%d)\n", status); |
949 | client_tracking_ops = NULL; | 949 | client_tracking_ops = NULL; |
950 | } | 950 | } |
951 | return status; | 951 | return status; |
952 | } | 952 | } |
953 | 953 | ||
954 | void | 954 | void |
955 | nfsd4_client_tracking_exit(struct net *net) | 955 | nfsd4_client_tracking_exit(struct net *net) |
956 | { | 956 | { |
957 | if (client_tracking_ops) { | 957 | if (client_tracking_ops) { |
958 | client_tracking_ops->exit(net); | 958 | client_tracking_ops->exit(net); |
959 | client_tracking_ops = NULL; | 959 | client_tracking_ops = NULL; |
960 | } | 960 | } |
961 | } | 961 | } |
962 | 962 | ||
963 | void | 963 | void |
964 | nfsd4_client_record_create(struct nfs4_client *clp) | 964 | nfsd4_client_record_create(struct nfs4_client *clp) |
965 | { | 965 | { |
966 | if (client_tracking_ops) | 966 | if (client_tracking_ops) |
967 | client_tracking_ops->create(clp); | 967 | client_tracking_ops->create(clp); |
968 | } | 968 | } |
969 | 969 | ||
970 | void | 970 | void |
971 | nfsd4_client_record_remove(struct nfs4_client *clp) | 971 | nfsd4_client_record_remove(struct nfs4_client *clp) |
972 | { | 972 | { |
973 | if (client_tracking_ops) | 973 | if (client_tracking_ops) |
974 | client_tracking_ops->remove(clp); | 974 | client_tracking_ops->remove(clp); |
975 | } | 975 | } |
976 | 976 | ||
977 | int | 977 | int |
978 | nfsd4_client_record_check(struct nfs4_client *clp) | 978 | nfsd4_client_record_check(struct nfs4_client *clp) |
979 | { | 979 | { |
980 | if (client_tracking_ops) | 980 | if (client_tracking_ops) |
981 | return client_tracking_ops->check(clp); | 981 | return client_tracking_ops->check(clp); |
982 | 982 | ||
983 | return -EOPNOTSUPP; | 983 | return -EOPNOTSUPP; |
984 | } | 984 | } |
985 | 985 | ||
986 | void | 986 | void |
987 | nfsd4_record_grace_done(struct net *net, time_t boot_time) | 987 | nfsd4_record_grace_done(struct net *net, time_t boot_time) |
988 | { | 988 | { |
989 | if (client_tracking_ops) | 989 | if (client_tracking_ops) |
990 | client_tracking_ops->grace_done(net, boot_time); | 990 | client_tracking_ops->grace_done(net, boot_time); |
991 | } | 991 | } |
992 | 992 | ||
993 | static int | 993 | static int |
994 | rpc_pipefs_event(struct notifier_block *nb, unsigned long event, void *ptr) | 994 | rpc_pipefs_event(struct notifier_block *nb, unsigned long event, void *ptr) |
995 | { | 995 | { |
996 | struct super_block *sb = ptr; | 996 | struct super_block *sb = ptr; |
997 | struct net *net = sb->s_fs_info; | 997 | struct net *net = sb->s_fs_info; |
998 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | 998 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); |
999 | struct cld_net *cn = nn->cld_net; | 999 | struct cld_net *cn = nn->cld_net; |
1000 | struct dentry *dentry; | 1000 | struct dentry *dentry; |
1001 | int ret = 0; | 1001 | int ret = 0; |
1002 | 1002 | ||
1003 | if (!try_module_get(THIS_MODULE)) | 1003 | if (!try_module_get(THIS_MODULE)) |
1004 | return 0; | 1004 | return 0; |
1005 | 1005 | ||
1006 | if (!cn) { | 1006 | if (!cn) { |
1007 | module_put(THIS_MODULE); | 1007 | module_put(THIS_MODULE); |
1008 | return 0; | 1008 | return 0; |
1009 | } | 1009 | } |
1010 | 1010 | ||
1011 | switch (event) { | 1011 | switch (event) { |
1012 | case RPC_PIPEFS_MOUNT: | 1012 | case RPC_PIPEFS_MOUNT: |
1013 | dentry = nfsd4_cld_register_sb(sb, cn->cn_pipe); | 1013 | dentry = nfsd4_cld_register_sb(sb, cn->cn_pipe); |
1014 | if (IS_ERR(dentry)) { | 1014 | if (IS_ERR(dentry)) { |
1015 | ret = PTR_ERR(dentry); | 1015 | ret = PTR_ERR(dentry); |
1016 | break; | 1016 | break; |
1017 | } | 1017 | } |
1018 | cn->cn_pipe->dentry = dentry; | 1018 | cn->cn_pipe->dentry = dentry; |
1019 | break; | 1019 | break; |
1020 | case RPC_PIPEFS_UMOUNT: | 1020 | case RPC_PIPEFS_UMOUNT: |
1021 | if (cn->cn_pipe->dentry) | 1021 | if (cn->cn_pipe->dentry) |
1022 | nfsd4_cld_unregister_sb(cn->cn_pipe); | 1022 | nfsd4_cld_unregister_sb(cn->cn_pipe); |
1023 | break; | 1023 | break; |
1024 | default: | 1024 | default: |
1025 | ret = -ENOTSUPP; | 1025 | ret = -ENOTSUPP; |
1026 | break; | 1026 | break; |
1027 | } | 1027 | } |
1028 | module_put(THIS_MODULE); | 1028 | module_put(THIS_MODULE); |
1029 | return ret; | 1029 | return ret; |
1030 | } | 1030 | } |
1031 | 1031 | ||
1032 | struct notifier_block nfsd4_cld_block = { | 1032 | struct notifier_block nfsd4_cld_block = { |
1033 | .notifier_call = rpc_pipefs_event, | 1033 | .notifier_call = rpc_pipefs_event, |
1034 | }; | 1034 | }; |
1035 | |||
1036 | int | ||
1037 | register_cld_notifier(void) | ||
1038 | { | ||
1039 | return rpc_pipefs_notifier_register(&nfsd4_cld_block); | ||
1040 | } | ||
1041 | |||
1042 | void | ||
1043 | unregister_cld_notifier(void) | ||
1044 | { | ||
1045 | rpc_pipefs_notifier_unregister(&nfsd4_cld_block); | ||
1046 | } | ||
1035 | 1047 |
fs/nfsd/nfsctl.c
1 | /* | 1 | /* |
2 | * Syscall interface to knfsd. | 2 | * Syscall interface to knfsd. |
3 | * | 3 | * |
4 | * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> | 4 | * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> |
5 | */ | 5 | */ |
6 | 6 | ||
7 | #include <linux/slab.h> | 7 | #include <linux/slab.h> |
8 | #include <linux/namei.h> | 8 | #include <linux/namei.h> |
9 | #include <linux/ctype.h> | 9 | #include <linux/ctype.h> |
10 | 10 | ||
11 | #include <linux/sunrpc/svcsock.h> | 11 | #include <linux/sunrpc/svcsock.h> |
12 | #include <linux/lockd/lockd.h> | 12 | #include <linux/lockd/lockd.h> |
13 | #include <linux/sunrpc/clnt.h> | 13 | #include <linux/sunrpc/clnt.h> |
14 | #include <linux/sunrpc/gss_api.h> | 14 | #include <linux/sunrpc/gss_api.h> |
15 | #include <linux/sunrpc/gss_krb5_enctypes.h> | 15 | #include <linux/sunrpc/gss_krb5_enctypes.h> |
16 | #include <linux/sunrpc/rpc_pipe_fs.h> | 16 | #include <linux/sunrpc/rpc_pipe_fs.h> |
17 | #include <linux/module.h> | 17 | #include <linux/module.h> |
18 | 18 | ||
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 "fault_inject.h" |
23 | #include "netns.h" | 23 | #include "netns.h" |
24 | 24 | ||
25 | /* | 25 | /* |
26 | * We have a single directory with several nodes in it. | 26 | * We have a single directory with several nodes in it. |
27 | */ | 27 | */ |
28 | enum { | 28 | enum { |
29 | NFSD_Root = 1, | 29 | NFSD_Root = 1, |
30 | NFSD_List, | 30 | NFSD_List, |
31 | NFSD_Export_features, | 31 | NFSD_Export_features, |
32 | NFSD_Fh, | 32 | NFSD_Fh, |
33 | NFSD_FO_UnlockIP, | 33 | NFSD_FO_UnlockIP, |
34 | NFSD_FO_UnlockFS, | 34 | NFSD_FO_UnlockFS, |
35 | NFSD_Threads, | 35 | NFSD_Threads, |
36 | NFSD_Pool_Threads, | 36 | NFSD_Pool_Threads, |
37 | NFSD_Pool_Stats, | 37 | NFSD_Pool_Stats, |
38 | NFSD_Versions, | 38 | NFSD_Versions, |
39 | NFSD_Ports, | 39 | NFSD_Ports, |
40 | NFSD_MaxBlkSize, | 40 | NFSD_MaxBlkSize, |
41 | NFSD_SupportedEnctypes, | 41 | NFSD_SupportedEnctypes, |
42 | /* | 42 | /* |
43 | * The below MUST come last. Otherwise we leave a hole in nfsd_files[] | 43 | * The below MUST come last. Otherwise we leave a hole in nfsd_files[] |
44 | * with !CONFIG_NFSD_V4 and simple_fill_super() goes oops | 44 | * with !CONFIG_NFSD_V4 and simple_fill_super() goes oops |
45 | */ | 45 | */ |
46 | #ifdef CONFIG_NFSD_V4 | 46 | #ifdef CONFIG_NFSD_V4 |
47 | NFSD_Leasetime, | 47 | NFSD_Leasetime, |
48 | NFSD_Gracetime, | 48 | NFSD_Gracetime, |
49 | NFSD_RecoveryDir, | 49 | NFSD_RecoveryDir, |
50 | #endif | 50 | #endif |
51 | }; | 51 | }; |
52 | 52 | ||
53 | /* | 53 | /* |
54 | * write() for these nodes. | 54 | * write() for these nodes. |
55 | */ | 55 | */ |
56 | static ssize_t write_filehandle(struct file *file, char *buf, size_t size); | 56 | static ssize_t write_filehandle(struct file *file, char *buf, size_t size); |
57 | static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size); | 57 | static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size); |
58 | static ssize_t write_unlock_fs(struct file *file, char *buf, size_t size); | 58 | static ssize_t write_unlock_fs(struct file *file, char *buf, size_t size); |
59 | static ssize_t write_threads(struct file *file, char *buf, size_t size); | 59 | static ssize_t write_threads(struct file *file, char *buf, size_t size); |
60 | static ssize_t write_pool_threads(struct file *file, char *buf, size_t size); | 60 | static ssize_t write_pool_threads(struct file *file, char *buf, size_t size); |
61 | static ssize_t write_versions(struct file *file, char *buf, size_t size); | 61 | static ssize_t write_versions(struct file *file, char *buf, size_t size); |
62 | static ssize_t write_ports(struct file *file, char *buf, size_t size); | 62 | static ssize_t write_ports(struct file *file, char *buf, size_t size); |
63 | static ssize_t write_maxblksize(struct file *file, char *buf, size_t size); | 63 | static ssize_t write_maxblksize(struct file *file, char *buf, size_t size); |
64 | #ifdef CONFIG_NFSD_V4 | 64 | #ifdef CONFIG_NFSD_V4 |
65 | static ssize_t write_leasetime(struct file *file, char *buf, size_t size); | 65 | static ssize_t write_leasetime(struct file *file, char *buf, size_t size); |
66 | static ssize_t write_gracetime(struct file *file, char *buf, size_t size); | 66 | static ssize_t write_gracetime(struct file *file, char *buf, size_t size); |
67 | static ssize_t write_recoverydir(struct file *file, char *buf, size_t size); | 67 | static ssize_t write_recoverydir(struct file *file, char *buf, size_t size); |
68 | #endif | 68 | #endif |
69 | 69 | ||
70 | static ssize_t (*write_op[])(struct file *, char *, size_t) = { | 70 | static ssize_t (*write_op[])(struct file *, char *, size_t) = { |
71 | [NFSD_Fh] = write_filehandle, | 71 | [NFSD_Fh] = write_filehandle, |
72 | [NFSD_FO_UnlockIP] = write_unlock_ip, | 72 | [NFSD_FO_UnlockIP] = write_unlock_ip, |
73 | [NFSD_FO_UnlockFS] = write_unlock_fs, | 73 | [NFSD_FO_UnlockFS] = write_unlock_fs, |
74 | [NFSD_Threads] = write_threads, | 74 | [NFSD_Threads] = write_threads, |
75 | [NFSD_Pool_Threads] = write_pool_threads, | 75 | [NFSD_Pool_Threads] = write_pool_threads, |
76 | [NFSD_Versions] = write_versions, | 76 | [NFSD_Versions] = write_versions, |
77 | [NFSD_Ports] = write_ports, | 77 | [NFSD_Ports] = write_ports, |
78 | [NFSD_MaxBlkSize] = write_maxblksize, | 78 | [NFSD_MaxBlkSize] = write_maxblksize, |
79 | #ifdef CONFIG_NFSD_V4 | 79 | #ifdef CONFIG_NFSD_V4 |
80 | [NFSD_Leasetime] = write_leasetime, | 80 | [NFSD_Leasetime] = write_leasetime, |
81 | [NFSD_Gracetime] = write_gracetime, | 81 | [NFSD_Gracetime] = write_gracetime, |
82 | [NFSD_RecoveryDir] = write_recoverydir, | 82 | [NFSD_RecoveryDir] = write_recoverydir, |
83 | #endif | 83 | #endif |
84 | }; | 84 | }; |
85 | 85 | ||
86 | static ssize_t nfsctl_transaction_write(struct file *file, const char __user *buf, size_t size, loff_t *pos) | 86 | static ssize_t nfsctl_transaction_write(struct file *file, const char __user *buf, size_t size, loff_t *pos) |
87 | { | 87 | { |
88 | ino_t ino = file->f_path.dentry->d_inode->i_ino; | 88 | ino_t ino = file->f_path.dentry->d_inode->i_ino; |
89 | char *data; | 89 | char *data; |
90 | ssize_t rv; | 90 | ssize_t rv; |
91 | 91 | ||
92 | if (ino >= ARRAY_SIZE(write_op) || !write_op[ino]) | 92 | if (ino >= ARRAY_SIZE(write_op) || !write_op[ino]) |
93 | return -EINVAL; | 93 | return -EINVAL; |
94 | 94 | ||
95 | data = simple_transaction_get(file, buf, size); | 95 | data = simple_transaction_get(file, buf, size); |
96 | if (IS_ERR(data)) | 96 | if (IS_ERR(data)) |
97 | return PTR_ERR(data); | 97 | return PTR_ERR(data); |
98 | 98 | ||
99 | rv = write_op[ino](file, data, size); | 99 | rv = write_op[ino](file, data, size); |
100 | if (rv >= 0) { | 100 | if (rv >= 0) { |
101 | simple_transaction_set(file, rv); | 101 | simple_transaction_set(file, rv); |
102 | rv = size; | 102 | rv = size; |
103 | } | 103 | } |
104 | return rv; | 104 | return rv; |
105 | } | 105 | } |
106 | 106 | ||
107 | static ssize_t nfsctl_transaction_read(struct file *file, char __user *buf, size_t size, loff_t *pos) | 107 | static ssize_t nfsctl_transaction_read(struct file *file, char __user *buf, size_t size, loff_t *pos) |
108 | { | 108 | { |
109 | if (! file->private_data) { | 109 | if (! file->private_data) { |
110 | /* An attempt to read a transaction file without writing | 110 | /* An attempt to read a transaction file without writing |
111 | * causes a 0-byte write so that the file can return | 111 | * causes a 0-byte write so that the file can return |
112 | * state information | 112 | * state information |
113 | */ | 113 | */ |
114 | ssize_t rv = nfsctl_transaction_write(file, buf, 0, pos); | 114 | ssize_t rv = nfsctl_transaction_write(file, buf, 0, pos); |
115 | if (rv < 0) | 115 | if (rv < 0) |
116 | return rv; | 116 | return rv; |
117 | } | 117 | } |
118 | return simple_transaction_read(file, buf, size, pos); | 118 | return simple_transaction_read(file, buf, size, pos); |
119 | } | 119 | } |
120 | 120 | ||
121 | static const struct file_operations transaction_ops = { | 121 | static const struct file_operations transaction_ops = { |
122 | .write = nfsctl_transaction_write, | 122 | .write = nfsctl_transaction_write, |
123 | .read = nfsctl_transaction_read, | 123 | .read = nfsctl_transaction_read, |
124 | .release = simple_transaction_release, | 124 | .release = simple_transaction_release, |
125 | .llseek = default_llseek, | 125 | .llseek = default_llseek, |
126 | }; | 126 | }; |
127 | 127 | ||
128 | static int exports_open(struct inode *inode, struct file *file) | 128 | static int exports_open(struct inode *inode, struct file *file) |
129 | { | 129 | { |
130 | return seq_open(file, &nfs_exports_op); | 130 | return seq_open(file, &nfs_exports_op); |
131 | } | 131 | } |
132 | 132 | ||
133 | static const struct file_operations exports_operations = { | 133 | static const struct file_operations exports_operations = { |
134 | .open = exports_open, | 134 | .open = exports_open, |
135 | .read = seq_read, | 135 | .read = seq_read, |
136 | .llseek = seq_lseek, | 136 | .llseek = seq_lseek, |
137 | .release = seq_release, | 137 | .release = seq_release, |
138 | .owner = THIS_MODULE, | 138 | .owner = THIS_MODULE, |
139 | }; | 139 | }; |
140 | 140 | ||
141 | static int export_features_show(struct seq_file *m, void *v) | 141 | static int export_features_show(struct seq_file *m, void *v) |
142 | { | 142 | { |
143 | seq_printf(m, "0x%x 0x%x\n", NFSEXP_ALLFLAGS, NFSEXP_SECINFO_FLAGS); | 143 | seq_printf(m, "0x%x 0x%x\n", NFSEXP_ALLFLAGS, NFSEXP_SECINFO_FLAGS); |
144 | return 0; | 144 | return 0; |
145 | } | 145 | } |
146 | 146 | ||
147 | static int export_features_open(struct inode *inode, struct file *file) | 147 | static int export_features_open(struct inode *inode, struct file *file) |
148 | { | 148 | { |
149 | return single_open(file, export_features_show, NULL); | 149 | return single_open(file, export_features_show, NULL); |
150 | } | 150 | } |
151 | 151 | ||
152 | static struct file_operations export_features_operations = { | 152 | static struct file_operations export_features_operations = { |
153 | .open = export_features_open, | 153 | .open = export_features_open, |
154 | .read = seq_read, | 154 | .read = seq_read, |
155 | .llseek = seq_lseek, | 155 | .llseek = seq_lseek, |
156 | .release = single_release, | 156 | .release = single_release, |
157 | }; | 157 | }; |
158 | 158 | ||
159 | #if defined(CONFIG_SUNRPC_GSS) || defined(CONFIG_SUNRPC_GSS_MODULE) | 159 | #if defined(CONFIG_SUNRPC_GSS) || defined(CONFIG_SUNRPC_GSS_MODULE) |
160 | static int supported_enctypes_show(struct seq_file *m, void *v) | 160 | static int supported_enctypes_show(struct seq_file *m, void *v) |
161 | { | 161 | { |
162 | seq_printf(m, KRB5_SUPPORTED_ENCTYPES); | 162 | seq_printf(m, KRB5_SUPPORTED_ENCTYPES); |
163 | return 0; | 163 | return 0; |
164 | } | 164 | } |
165 | 165 | ||
166 | static int supported_enctypes_open(struct inode *inode, struct file *file) | 166 | static int supported_enctypes_open(struct inode *inode, struct file *file) |
167 | { | 167 | { |
168 | return single_open(file, supported_enctypes_show, NULL); | 168 | return single_open(file, supported_enctypes_show, NULL); |
169 | } | 169 | } |
170 | 170 | ||
171 | static struct file_operations supported_enctypes_ops = { | 171 | static struct file_operations supported_enctypes_ops = { |
172 | .open = supported_enctypes_open, | 172 | .open = supported_enctypes_open, |
173 | .read = seq_read, | 173 | .read = seq_read, |
174 | .llseek = seq_lseek, | 174 | .llseek = seq_lseek, |
175 | .release = single_release, | 175 | .release = single_release, |
176 | }; | 176 | }; |
177 | #endif /* CONFIG_SUNRPC_GSS or CONFIG_SUNRPC_GSS_MODULE */ | 177 | #endif /* CONFIG_SUNRPC_GSS or CONFIG_SUNRPC_GSS_MODULE */ |
178 | 178 | ||
179 | extern int nfsd_pool_stats_open(struct inode *inode, struct file *file); | 179 | extern int nfsd_pool_stats_open(struct inode *inode, struct file *file); |
180 | extern int nfsd_pool_stats_release(struct inode *inode, struct file *file); | 180 | extern int nfsd_pool_stats_release(struct inode *inode, struct file *file); |
181 | 181 | ||
182 | static const struct file_operations pool_stats_operations = { | 182 | static const struct file_operations pool_stats_operations = { |
183 | .open = nfsd_pool_stats_open, | 183 | .open = nfsd_pool_stats_open, |
184 | .read = seq_read, | 184 | .read = seq_read, |
185 | .llseek = seq_lseek, | 185 | .llseek = seq_lseek, |
186 | .release = nfsd_pool_stats_release, | 186 | .release = nfsd_pool_stats_release, |
187 | .owner = THIS_MODULE, | 187 | .owner = THIS_MODULE, |
188 | }; | 188 | }; |
189 | 189 | ||
190 | /*----------------------------------------------------------------------------*/ | 190 | /*----------------------------------------------------------------------------*/ |
191 | /* | 191 | /* |
192 | * payload - write methods | 192 | * payload - write methods |
193 | */ | 193 | */ |
194 | 194 | ||
195 | 195 | ||
196 | /** | 196 | /** |
197 | * write_unlock_ip - Release all locks used by a client | 197 | * write_unlock_ip - Release all locks used by a client |
198 | * | 198 | * |
199 | * Experimental. | 199 | * Experimental. |
200 | * | 200 | * |
201 | * Input: | 201 | * Input: |
202 | * buf: '\n'-terminated C string containing a | 202 | * buf: '\n'-terminated C string containing a |
203 | * presentation format IP address | 203 | * presentation format IP address |
204 | * size: length of C string in @buf | 204 | * size: length of C string in @buf |
205 | * Output: | 205 | * Output: |
206 | * On success: returns zero if all specified locks were released; | 206 | * On success: returns zero if all specified locks were released; |
207 | * returns one if one or more locks were not released | 207 | * returns one if one or more locks were not released |
208 | * On error: return code is negative errno value | 208 | * On error: return code is negative errno value |
209 | */ | 209 | */ |
210 | static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size) | 210 | static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size) |
211 | { | 211 | { |
212 | struct sockaddr_storage address; | 212 | struct sockaddr_storage address; |
213 | struct sockaddr *sap = (struct sockaddr *)&address; | 213 | struct sockaddr *sap = (struct sockaddr *)&address; |
214 | size_t salen = sizeof(address); | 214 | size_t salen = sizeof(address); |
215 | char *fo_path; | 215 | char *fo_path; |
216 | 216 | ||
217 | /* sanity check */ | 217 | /* sanity check */ |
218 | if (size == 0) | 218 | if (size == 0) |
219 | return -EINVAL; | 219 | return -EINVAL; |
220 | 220 | ||
221 | if (buf[size-1] != '\n') | 221 | if (buf[size-1] != '\n') |
222 | return -EINVAL; | 222 | return -EINVAL; |
223 | 223 | ||
224 | fo_path = buf; | 224 | fo_path = buf; |
225 | if (qword_get(&buf, fo_path, size) < 0) | 225 | if (qword_get(&buf, fo_path, size) < 0) |
226 | return -EINVAL; | 226 | return -EINVAL; |
227 | 227 | ||
228 | if (rpc_pton(&init_net, fo_path, size, sap, salen) == 0) | 228 | if (rpc_pton(&init_net, fo_path, size, sap, salen) == 0) |
229 | return -EINVAL; | 229 | return -EINVAL; |
230 | 230 | ||
231 | return nlmsvc_unlock_all_by_ip(sap); | 231 | return nlmsvc_unlock_all_by_ip(sap); |
232 | } | 232 | } |
233 | 233 | ||
234 | /** | 234 | /** |
235 | * write_unlock_fs - Release all locks on a local file system | 235 | * write_unlock_fs - Release all locks on a local file system |
236 | * | 236 | * |
237 | * Experimental. | 237 | * Experimental. |
238 | * | 238 | * |
239 | * Input: | 239 | * Input: |
240 | * buf: '\n'-terminated C string containing the | 240 | * buf: '\n'-terminated C string containing the |
241 | * absolute pathname of a local file system | 241 | * absolute pathname of a local file system |
242 | * size: length of C string in @buf | 242 | * size: length of C string in @buf |
243 | * Output: | 243 | * Output: |
244 | * On success: returns zero if all specified locks were released; | 244 | * On success: returns zero if all specified locks were released; |
245 | * returns one if one or more locks were not released | 245 | * returns one if one or more locks were not released |
246 | * On error: return code is negative errno value | 246 | * On error: return code is negative errno value |
247 | */ | 247 | */ |
248 | static ssize_t write_unlock_fs(struct file *file, char *buf, size_t size) | 248 | static ssize_t write_unlock_fs(struct file *file, char *buf, size_t size) |
249 | { | 249 | { |
250 | struct path path; | 250 | struct path path; |
251 | char *fo_path; | 251 | char *fo_path; |
252 | int error; | 252 | int error; |
253 | 253 | ||
254 | /* sanity check */ | 254 | /* sanity check */ |
255 | if (size == 0) | 255 | if (size == 0) |
256 | return -EINVAL; | 256 | return -EINVAL; |
257 | 257 | ||
258 | if (buf[size-1] != '\n') | 258 | if (buf[size-1] != '\n') |
259 | return -EINVAL; | 259 | return -EINVAL; |
260 | 260 | ||
261 | fo_path = buf; | 261 | fo_path = buf; |
262 | if (qword_get(&buf, fo_path, size) < 0) | 262 | if (qword_get(&buf, fo_path, size) < 0) |
263 | return -EINVAL; | 263 | return -EINVAL; |
264 | 264 | ||
265 | error = kern_path(fo_path, 0, &path); | 265 | error = kern_path(fo_path, 0, &path); |
266 | if (error) | 266 | if (error) |
267 | return error; | 267 | return error; |
268 | 268 | ||
269 | /* | 269 | /* |
270 | * XXX: Needs better sanity checking. Otherwise we could end up | 270 | * XXX: Needs better sanity checking. Otherwise we could end up |
271 | * releasing locks on the wrong file system. | 271 | * releasing locks on the wrong file system. |
272 | * | 272 | * |
273 | * For example: | 273 | * For example: |
274 | * 1. Does the path refer to a directory? | 274 | * 1. Does the path refer to a directory? |
275 | * 2. Is that directory a mount point, or | 275 | * 2. Is that directory a mount point, or |
276 | * 3. Is that directory the root of an exported file system? | 276 | * 3. Is that directory the root of an exported file system? |
277 | */ | 277 | */ |
278 | error = nlmsvc_unlock_all_by_sb(path.dentry->d_sb); | 278 | error = nlmsvc_unlock_all_by_sb(path.dentry->d_sb); |
279 | 279 | ||
280 | path_put(&path); | 280 | path_put(&path); |
281 | return error; | 281 | return error; |
282 | } | 282 | } |
283 | 283 | ||
284 | /** | 284 | /** |
285 | * write_filehandle - Get a variable-length NFS file handle by path | 285 | * write_filehandle - Get a variable-length NFS file handle by path |
286 | * | 286 | * |
287 | * On input, the buffer contains a '\n'-terminated C string comprised of | 287 | * On input, the buffer contains a '\n'-terminated C string comprised of |
288 | * three alphanumeric words separated by whitespace. The string may | 288 | * three alphanumeric words separated by whitespace. The string may |
289 | * contain escape sequences. | 289 | * contain escape sequences. |
290 | * | 290 | * |
291 | * Input: | 291 | * Input: |
292 | * buf: | 292 | * buf: |
293 | * domain: client domain name | 293 | * domain: client domain name |
294 | * path: export pathname | 294 | * path: export pathname |
295 | * maxsize: numeric maximum size of | 295 | * maxsize: numeric maximum size of |
296 | * @buf | 296 | * @buf |
297 | * size: length of C string in @buf | 297 | * size: length of C string in @buf |
298 | * Output: | 298 | * Output: |
299 | * On success: passed-in buffer filled with '\n'-terminated C | 299 | * On success: passed-in buffer filled with '\n'-terminated C |
300 | * string containing a ASCII hex text version | 300 | * string containing a ASCII hex text version |
301 | * of the NFS file handle; | 301 | * of the NFS file handle; |
302 | * return code is the size in bytes of the string | 302 | * return code is the size in bytes of the string |
303 | * On error: return code is negative errno value | 303 | * On error: return code is negative errno value |
304 | */ | 304 | */ |
305 | static ssize_t write_filehandle(struct file *file, char *buf, size_t size) | 305 | static ssize_t write_filehandle(struct file *file, char *buf, size_t size) |
306 | { | 306 | { |
307 | char *dname, *path; | 307 | char *dname, *path; |
308 | int uninitialized_var(maxsize); | 308 | int uninitialized_var(maxsize); |
309 | char *mesg = buf; | 309 | char *mesg = buf; |
310 | int len; | 310 | int len; |
311 | struct auth_domain *dom; | 311 | struct auth_domain *dom; |
312 | struct knfsd_fh fh; | 312 | struct knfsd_fh fh; |
313 | 313 | ||
314 | if (size == 0) | 314 | if (size == 0) |
315 | return -EINVAL; | 315 | return -EINVAL; |
316 | 316 | ||
317 | if (buf[size-1] != '\n') | 317 | if (buf[size-1] != '\n') |
318 | return -EINVAL; | 318 | return -EINVAL; |
319 | buf[size-1] = 0; | 319 | buf[size-1] = 0; |
320 | 320 | ||
321 | dname = mesg; | 321 | dname = mesg; |
322 | len = qword_get(&mesg, dname, size); | 322 | len = qword_get(&mesg, dname, size); |
323 | if (len <= 0) | 323 | if (len <= 0) |
324 | return -EINVAL; | 324 | return -EINVAL; |
325 | 325 | ||
326 | path = dname+len+1; | 326 | path = dname+len+1; |
327 | len = qword_get(&mesg, path, size); | 327 | len = qword_get(&mesg, path, size); |
328 | if (len <= 0) | 328 | if (len <= 0) |
329 | return -EINVAL; | 329 | return -EINVAL; |
330 | 330 | ||
331 | len = get_int(&mesg, &maxsize); | 331 | len = get_int(&mesg, &maxsize); |
332 | if (len) | 332 | if (len) |
333 | return len; | 333 | return len; |
334 | 334 | ||
335 | if (maxsize < NFS_FHSIZE) | 335 | if (maxsize < NFS_FHSIZE) |
336 | return -EINVAL; | 336 | return -EINVAL; |
337 | if (maxsize > NFS3_FHSIZE) | 337 | if (maxsize > NFS3_FHSIZE) |
338 | maxsize = NFS3_FHSIZE; | 338 | maxsize = NFS3_FHSIZE; |
339 | 339 | ||
340 | if (qword_get(&mesg, mesg, size)>0) | 340 | if (qword_get(&mesg, mesg, size)>0) |
341 | return -EINVAL; | 341 | return -EINVAL; |
342 | 342 | ||
343 | /* we have all the words, they are in buf.. */ | 343 | /* we have all the words, they are in buf.. */ |
344 | dom = unix_domain_find(dname); | 344 | dom = unix_domain_find(dname); |
345 | if (!dom) | 345 | if (!dom) |
346 | return -ENOMEM; | 346 | return -ENOMEM; |
347 | 347 | ||
348 | len = exp_rootfh(dom, path, &fh, maxsize); | 348 | len = exp_rootfh(dom, path, &fh, maxsize); |
349 | auth_domain_put(dom); | 349 | auth_domain_put(dom); |
350 | if (len) | 350 | if (len) |
351 | return len; | 351 | return len; |
352 | 352 | ||
353 | mesg = buf; | 353 | mesg = buf; |
354 | len = SIMPLE_TRANSACTION_LIMIT; | 354 | len = SIMPLE_TRANSACTION_LIMIT; |
355 | qword_addhex(&mesg, &len, (char*)&fh.fh_base, fh.fh_size); | 355 | qword_addhex(&mesg, &len, (char*)&fh.fh_base, fh.fh_size); |
356 | mesg[-1] = '\n'; | 356 | mesg[-1] = '\n'; |
357 | return mesg - buf; | 357 | return mesg - buf; |
358 | } | 358 | } |
359 | 359 | ||
360 | /** | 360 | /** |
361 | * write_threads - Start NFSD, or report the current number of running threads | 361 | * write_threads - Start NFSD, or report the current number of running threads |
362 | * | 362 | * |
363 | * Input: | 363 | * Input: |
364 | * buf: ignored | 364 | * buf: ignored |
365 | * size: zero | 365 | * size: zero |
366 | * Output: | 366 | * Output: |
367 | * On success: passed-in buffer filled with '\n'-terminated C | 367 | * On success: passed-in buffer filled with '\n'-terminated C |
368 | * string numeric value representing the number of | 368 | * string numeric value representing the number of |
369 | * running NFSD threads; | 369 | * running NFSD threads; |
370 | * return code is the size in bytes of the string | 370 | * return code is the size in bytes of the string |
371 | * On error: return code is zero | 371 | * On error: return code is zero |
372 | * | 372 | * |
373 | * OR | 373 | * OR |
374 | * | 374 | * |
375 | * Input: | 375 | * Input: |
376 | * buf: C string containing an unsigned | 376 | * buf: C string containing an unsigned |
377 | * integer value representing the | 377 | * integer value representing the |
378 | * number of NFSD threads to start | 378 | * number of NFSD threads to start |
379 | * size: non-zero length of C string in @buf | 379 | * size: non-zero length of C string in @buf |
380 | * Output: | 380 | * Output: |
381 | * On success: NFS service is started; | 381 | * On success: NFS service is started; |
382 | * passed-in buffer filled with '\n'-terminated C | 382 | * passed-in buffer filled with '\n'-terminated C |
383 | * string numeric value representing the number of | 383 | * string numeric value representing the number of |
384 | * running NFSD threads; | 384 | * running NFSD threads; |
385 | * return code is the size in bytes of the string | 385 | * return code is the size in bytes of the string |
386 | * On error: return code is zero or a negative errno value | 386 | * On error: return code is zero or a negative errno value |
387 | */ | 387 | */ |
388 | static ssize_t write_threads(struct file *file, char *buf, size_t size) | 388 | static ssize_t write_threads(struct file *file, char *buf, size_t size) |
389 | { | 389 | { |
390 | char *mesg = buf; | 390 | char *mesg = buf; |
391 | int rv; | 391 | int rv; |
392 | if (size > 0) { | 392 | if (size > 0) { |
393 | int newthreads; | 393 | int newthreads; |
394 | rv = get_int(&mesg, &newthreads); | 394 | rv = get_int(&mesg, &newthreads); |
395 | if (rv) | 395 | if (rv) |
396 | return rv; | 396 | return rv; |
397 | if (newthreads < 0) | 397 | if (newthreads < 0) |
398 | return -EINVAL; | 398 | return -EINVAL; |
399 | rv = nfsd_svc(NFS_PORT, newthreads); | 399 | rv = nfsd_svc(NFS_PORT, newthreads); |
400 | if (rv < 0) | 400 | if (rv < 0) |
401 | return rv; | 401 | return rv; |
402 | } else | 402 | } else |
403 | rv = nfsd_nrthreads(); | 403 | rv = nfsd_nrthreads(); |
404 | 404 | ||
405 | return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%d\n", rv); | 405 | return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%d\n", rv); |
406 | } | 406 | } |
407 | 407 | ||
408 | /** | 408 | /** |
409 | * write_pool_threads - Set or report the current number of threads per pool | 409 | * write_pool_threads - Set or report the current number of threads per pool |
410 | * | 410 | * |
411 | * Input: | 411 | * Input: |
412 | * buf: ignored | 412 | * buf: ignored |
413 | * size: zero | 413 | * size: zero |
414 | * | 414 | * |
415 | * OR | 415 | * OR |
416 | * | 416 | * |
417 | * Input: | 417 | * Input: |
418 | * buf: C string containing whitespace- | 418 | * buf: C string containing whitespace- |
419 | * separated unsigned integer values | 419 | * separated unsigned integer values |
420 | * representing the number of NFSD | 420 | * representing the number of NFSD |
421 | * threads to start in each pool | 421 | * threads to start in each pool |
422 | * size: non-zero length of C string in @buf | 422 | * size: non-zero length of C string in @buf |
423 | * Output: | 423 | * Output: |
424 | * On success: passed-in buffer filled with '\n'-terminated C | 424 | * On success: passed-in buffer filled with '\n'-terminated C |
425 | * string containing integer values representing the | 425 | * string containing integer values representing the |
426 | * number of NFSD threads in each pool; | 426 | * number of NFSD threads in each pool; |
427 | * return code is the size in bytes of the string | 427 | * return code is the size in bytes of the string |
428 | * On error: return code is zero or a negative errno value | 428 | * On error: return code is zero or a negative errno value |
429 | */ | 429 | */ |
430 | static ssize_t write_pool_threads(struct file *file, char *buf, size_t size) | 430 | static ssize_t write_pool_threads(struct file *file, char *buf, size_t size) |
431 | { | 431 | { |
432 | /* if size > 0, look for an array of number of threads per node | 432 | /* if size > 0, look for an array of number of threads per node |
433 | * and apply them then write out number of threads per node as reply | 433 | * and apply them then write out number of threads per node as reply |
434 | */ | 434 | */ |
435 | char *mesg = buf; | 435 | char *mesg = buf; |
436 | int i; | 436 | int i; |
437 | int rv; | 437 | int rv; |
438 | int len; | 438 | int len; |
439 | int npools; | 439 | int npools; |
440 | int *nthreads; | 440 | int *nthreads; |
441 | 441 | ||
442 | mutex_lock(&nfsd_mutex); | 442 | mutex_lock(&nfsd_mutex); |
443 | npools = nfsd_nrpools(); | 443 | npools = nfsd_nrpools(); |
444 | if (npools == 0) { | 444 | if (npools == 0) { |
445 | /* | 445 | /* |
446 | * NFS is shut down. The admin can start it by | 446 | * NFS is shut down. The admin can start it by |
447 | * writing to the threads file but NOT the pool_threads | 447 | * writing to the threads file but NOT the pool_threads |
448 | * file, sorry. Report zero threads. | 448 | * file, sorry. Report zero threads. |
449 | */ | 449 | */ |
450 | mutex_unlock(&nfsd_mutex); | 450 | mutex_unlock(&nfsd_mutex); |
451 | strcpy(buf, "0\n"); | 451 | strcpy(buf, "0\n"); |
452 | return strlen(buf); | 452 | return strlen(buf); |
453 | } | 453 | } |
454 | 454 | ||
455 | nthreads = kcalloc(npools, sizeof(int), GFP_KERNEL); | 455 | nthreads = kcalloc(npools, sizeof(int), GFP_KERNEL); |
456 | rv = -ENOMEM; | 456 | rv = -ENOMEM; |
457 | if (nthreads == NULL) | 457 | if (nthreads == NULL) |
458 | goto out_free; | 458 | goto out_free; |
459 | 459 | ||
460 | if (size > 0) { | 460 | if (size > 0) { |
461 | for (i = 0; i < npools; i++) { | 461 | for (i = 0; i < npools; i++) { |
462 | rv = get_int(&mesg, &nthreads[i]); | 462 | rv = get_int(&mesg, &nthreads[i]); |
463 | if (rv == -ENOENT) | 463 | if (rv == -ENOENT) |
464 | break; /* fewer numbers than pools */ | 464 | break; /* fewer numbers than pools */ |
465 | if (rv) | 465 | if (rv) |
466 | goto out_free; /* syntax error */ | 466 | goto out_free; /* syntax error */ |
467 | rv = -EINVAL; | 467 | rv = -EINVAL; |
468 | if (nthreads[i] < 0) | 468 | if (nthreads[i] < 0) |
469 | goto out_free; | 469 | goto out_free; |
470 | } | 470 | } |
471 | rv = nfsd_set_nrthreads(i, nthreads); | 471 | rv = nfsd_set_nrthreads(i, nthreads); |
472 | if (rv) | 472 | if (rv) |
473 | goto out_free; | 473 | goto out_free; |
474 | } | 474 | } |
475 | 475 | ||
476 | rv = nfsd_get_nrthreads(npools, nthreads); | 476 | rv = nfsd_get_nrthreads(npools, nthreads); |
477 | if (rv) | 477 | if (rv) |
478 | goto out_free; | 478 | goto out_free; |
479 | 479 | ||
480 | mesg = buf; | 480 | mesg = buf; |
481 | size = SIMPLE_TRANSACTION_LIMIT; | 481 | size = SIMPLE_TRANSACTION_LIMIT; |
482 | for (i = 0; i < npools && size > 0; i++) { | 482 | for (i = 0; i < npools && size > 0; i++) { |
483 | snprintf(mesg, size, "%d%c", nthreads[i], (i == npools-1 ? '\n' : ' ')); | 483 | snprintf(mesg, size, "%d%c", nthreads[i], (i == npools-1 ? '\n' : ' ')); |
484 | len = strlen(mesg); | 484 | len = strlen(mesg); |
485 | size -= len; | 485 | size -= len; |
486 | mesg += len; | 486 | mesg += len; |
487 | } | 487 | } |
488 | rv = mesg - buf; | 488 | rv = mesg - buf; |
489 | out_free: | 489 | out_free: |
490 | kfree(nthreads); | 490 | kfree(nthreads); |
491 | mutex_unlock(&nfsd_mutex); | 491 | mutex_unlock(&nfsd_mutex); |
492 | return rv; | 492 | return rv; |
493 | } | 493 | } |
494 | 494 | ||
495 | static ssize_t __write_versions(struct file *file, char *buf, size_t size) | 495 | static ssize_t __write_versions(struct file *file, char *buf, size_t size) |
496 | { | 496 | { |
497 | char *mesg = buf; | 497 | char *mesg = buf; |
498 | char *vers, *minorp, sign; | 498 | char *vers, *minorp, sign; |
499 | int len, num, remaining; | 499 | int len, num, remaining; |
500 | unsigned minor; | 500 | unsigned minor; |
501 | ssize_t tlen = 0; | 501 | ssize_t tlen = 0; |
502 | char *sep; | 502 | char *sep; |
503 | 503 | ||
504 | if (size>0) { | 504 | if (size>0) { |
505 | if (nfsd_serv) | 505 | if (nfsd_serv) |
506 | /* Cannot change versions without updating | 506 | /* Cannot change versions without updating |
507 | * nfsd_serv->sv_xdrsize, and reallocing | 507 | * nfsd_serv->sv_xdrsize, and reallocing |
508 | * rq_argp and rq_resp | 508 | * rq_argp and rq_resp |
509 | */ | 509 | */ |
510 | return -EBUSY; | 510 | return -EBUSY; |
511 | if (buf[size-1] != '\n') | 511 | if (buf[size-1] != '\n') |
512 | return -EINVAL; | 512 | return -EINVAL; |
513 | buf[size-1] = 0; | 513 | buf[size-1] = 0; |
514 | 514 | ||
515 | vers = mesg; | 515 | vers = mesg; |
516 | len = qword_get(&mesg, vers, size); | 516 | len = qword_get(&mesg, vers, size); |
517 | if (len <= 0) return -EINVAL; | 517 | if (len <= 0) return -EINVAL; |
518 | do { | 518 | do { |
519 | sign = *vers; | 519 | sign = *vers; |
520 | if (sign == '+' || sign == '-') | 520 | if (sign == '+' || sign == '-') |
521 | num = simple_strtol((vers+1), &minorp, 0); | 521 | num = simple_strtol((vers+1), &minorp, 0); |
522 | else | 522 | else |
523 | num = simple_strtol(vers, &minorp, 0); | 523 | num = simple_strtol(vers, &minorp, 0); |
524 | if (*minorp == '.') { | 524 | if (*minorp == '.') { |
525 | if (num < 4) | 525 | if (num < 4) |
526 | return -EINVAL; | 526 | return -EINVAL; |
527 | minor = simple_strtoul(minorp+1, NULL, 0); | 527 | minor = simple_strtoul(minorp+1, NULL, 0); |
528 | if (minor == 0) | 528 | if (minor == 0) |
529 | return -EINVAL; | 529 | return -EINVAL; |
530 | if (nfsd_minorversion(minor, sign == '-' ? | 530 | if (nfsd_minorversion(minor, sign == '-' ? |
531 | NFSD_CLEAR : NFSD_SET) < 0) | 531 | NFSD_CLEAR : NFSD_SET) < 0) |
532 | return -EINVAL; | 532 | return -EINVAL; |
533 | goto next; | 533 | goto next; |
534 | } | 534 | } |
535 | switch(num) { | 535 | switch(num) { |
536 | case 2: | 536 | case 2: |
537 | case 3: | 537 | case 3: |
538 | case 4: | 538 | case 4: |
539 | nfsd_vers(num, sign == '-' ? NFSD_CLEAR : NFSD_SET); | 539 | nfsd_vers(num, sign == '-' ? NFSD_CLEAR : NFSD_SET); |
540 | break; | 540 | break; |
541 | default: | 541 | default: |
542 | return -EINVAL; | 542 | return -EINVAL; |
543 | } | 543 | } |
544 | next: | 544 | next: |
545 | vers += len + 1; | 545 | vers += len + 1; |
546 | } while ((len = qword_get(&mesg, vers, size)) > 0); | 546 | } while ((len = qword_get(&mesg, vers, size)) > 0); |
547 | /* If all get turned off, turn them back on, as | 547 | /* If all get turned off, turn them back on, as |
548 | * having no versions is BAD | 548 | * having no versions is BAD |
549 | */ | 549 | */ |
550 | nfsd_reset_versions(); | 550 | nfsd_reset_versions(); |
551 | } | 551 | } |
552 | 552 | ||
553 | /* Now write current state into reply buffer */ | 553 | /* Now write current state into reply buffer */ |
554 | len = 0; | 554 | len = 0; |
555 | sep = ""; | 555 | sep = ""; |
556 | remaining = SIMPLE_TRANSACTION_LIMIT; | 556 | remaining = SIMPLE_TRANSACTION_LIMIT; |
557 | for (num=2 ; num <= 4 ; num++) | 557 | for (num=2 ; num <= 4 ; num++) |
558 | if (nfsd_vers(num, NFSD_AVAIL)) { | 558 | if (nfsd_vers(num, NFSD_AVAIL)) { |
559 | len = snprintf(buf, remaining, "%s%c%d", sep, | 559 | len = snprintf(buf, remaining, "%s%c%d", sep, |
560 | nfsd_vers(num, NFSD_TEST)?'+':'-', | 560 | nfsd_vers(num, NFSD_TEST)?'+':'-', |
561 | num); | 561 | num); |
562 | sep = " "; | 562 | sep = " "; |
563 | 563 | ||
564 | if (len > remaining) | 564 | if (len > remaining) |
565 | break; | 565 | break; |
566 | remaining -= len; | 566 | remaining -= len; |
567 | buf += len; | 567 | buf += len; |
568 | tlen += len; | 568 | tlen += len; |
569 | } | 569 | } |
570 | if (nfsd_vers(4, NFSD_AVAIL)) | 570 | if (nfsd_vers(4, NFSD_AVAIL)) |
571 | for (minor = 1; minor <= NFSD_SUPPORTED_MINOR_VERSION; | 571 | for (minor = 1; minor <= NFSD_SUPPORTED_MINOR_VERSION; |
572 | minor++) { | 572 | minor++) { |
573 | len = snprintf(buf, remaining, " %c4.%u", | 573 | len = snprintf(buf, remaining, " %c4.%u", |
574 | (nfsd_vers(4, NFSD_TEST) && | 574 | (nfsd_vers(4, NFSD_TEST) && |
575 | nfsd_minorversion(minor, NFSD_TEST)) ? | 575 | nfsd_minorversion(minor, NFSD_TEST)) ? |
576 | '+' : '-', | 576 | '+' : '-', |
577 | minor); | 577 | minor); |
578 | 578 | ||
579 | if (len > remaining) | 579 | if (len > remaining) |
580 | break; | 580 | break; |
581 | remaining -= len; | 581 | remaining -= len; |
582 | buf += len; | 582 | buf += len; |
583 | tlen += len; | 583 | tlen += len; |
584 | } | 584 | } |
585 | 585 | ||
586 | len = snprintf(buf, remaining, "\n"); | 586 | len = snprintf(buf, remaining, "\n"); |
587 | if (len > remaining) | 587 | if (len > remaining) |
588 | return -EINVAL; | 588 | return -EINVAL; |
589 | return tlen + len; | 589 | return tlen + len; |
590 | } | 590 | } |
591 | 591 | ||
592 | /** | 592 | /** |
593 | * write_versions - Set or report the available NFS protocol versions | 593 | * write_versions - Set or report the available NFS protocol versions |
594 | * | 594 | * |
595 | * Input: | 595 | * Input: |
596 | * buf: ignored | 596 | * buf: ignored |
597 | * size: zero | 597 | * size: zero |
598 | * Output: | 598 | * Output: |
599 | * On success: passed-in buffer filled with '\n'-terminated C | 599 | * On success: passed-in buffer filled with '\n'-terminated C |
600 | * string containing positive or negative integer | 600 | * string containing positive or negative integer |
601 | * values representing the current status of each | 601 | * values representing the current status of each |
602 | * protocol version; | 602 | * protocol version; |
603 | * return code is the size in bytes of the string | 603 | * return code is the size in bytes of the string |
604 | * On error: return code is zero or a negative errno value | 604 | * On error: return code is zero or a negative errno value |
605 | * | 605 | * |
606 | * OR | 606 | * OR |
607 | * | 607 | * |
608 | * Input: | 608 | * Input: |
609 | * buf: C string containing whitespace- | 609 | * buf: C string containing whitespace- |
610 | * separated positive or negative | 610 | * separated positive or negative |
611 | * integer values representing NFS | 611 | * integer values representing NFS |
612 | * protocol versions to enable ("+n") | 612 | * protocol versions to enable ("+n") |
613 | * or disable ("-n") | 613 | * or disable ("-n") |
614 | * size: non-zero length of C string in @buf | 614 | * size: non-zero length of C string in @buf |
615 | * Output: | 615 | * Output: |
616 | * On success: status of zero or more protocol versions has | 616 | * On success: status of zero or more protocol versions has |
617 | * been updated; passed-in buffer filled with | 617 | * been updated; passed-in buffer filled with |
618 | * '\n'-terminated C string containing positive | 618 | * '\n'-terminated C string containing positive |
619 | * or negative integer values representing the | 619 | * or negative integer values representing the |
620 | * current status of each protocol version; | 620 | * current status of each protocol version; |
621 | * return code is the size in bytes of the string | 621 | * return code is the size in bytes of the string |
622 | * On error: return code is zero or a negative errno value | 622 | * On error: return code is zero or a negative errno value |
623 | */ | 623 | */ |
624 | static ssize_t write_versions(struct file *file, char *buf, size_t size) | 624 | static ssize_t write_versions(struct file *file, char *buf, size_t size) |
625 | { | 625 | { |
626 | ssize_t rv; | 626 | ssize_t rv; |
627 | 627 | ||
628 | mutex_lock(&nfsd_mutex); | 628 | mutex_lock(&nfsd_mutex); |
629 | rv = __write_versions(file, buf, size); | 629 | rv = __write_versions(file, buf, size); |
630 | mutex_unlock(&nfsd_mutex); | 630 | mutex_unlock(&nfsd_mutex); |
631 | return rv; | 631 | return rv; |
632 | } | 632 | } |
633 | 633 | ||
634 | /* | 634 | /* |
635 | * Zero-length write. Return a list of NFSD's current listener | 635 | * Zero-length write. Return a list of NFSD's current listener |
636 | * transports. | 636 | * transports. |
637 | */ | 637 | */ |
638 | static ssize_t __write_ports_names(char *buf) | 638 | static ssize_t __write_ports_names(char *buf) |
639 | { | 639 | { |
640 | if (nfsd_serv == NULL) | 640 | if (nfsd_serv == NULL) |
641 | return 0; | 641 | return 0; |
642 | return svc_xprt_names(nfsd_serv, buf, SIMPLE_TRANSACTION_LIMIT); | 642 | return svc_xprt_names(nfsd_serv, buf, SIMPLE_TRANSACTION_LIMIT); |
643 | } | 643 | } |
644 | 644 | ||
645 | /* | 645 | /* |
646 | * A single 'fd' number was written, in which case it must be for | 646 | * A single 'fd' number was written, in which case it must be for |
647 | * a socket of a supported family/protocol, and we use it as an | 647 | * a socket of a supported family/protocol, and we use it as an |
648 | * nfsd listener. | 648 | * nfsd listener. |
649 | */ | 649 | */ |
650 | static ssize_t __write_ports_addfd(char *buf) | 650 | static ssize_t __write_ports_addfd(char *buf) |
651 | { | 651 | { |
652 | char *mesg = buf; | 652 | char *mesg = buf; |
653 | int fd, err; | 653 | int fd, err; |
654 | 654 | ||
655 | err = get_int(&mesg, &fd); | 655 | err = get_int(&mesg, &fd); |
656 | if (err != 0 || fd < 0) | 656 | if (err != 0 || fd < 0) |
657 | return -EINVAL; | 657 | return -EINVAL; |
658 | 658 | ||
659 | err = nfsd_create_serv(); | 659 | err = nfsd_create_serv(); |
660 | if (err != 0) | 660 | if (err != 0) |
661 | return err; | 661 | return err; |
662 | 662 | ||
663 | err = svc_addsock(nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT); | 663 | err = svc_addsock(nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT); |
664 | if (err < 0) { | 664 | if (err < 0) { |
665 | svc_destroy(nfsd_serv); | 665 | svc_destroy(nfsd_serv); |
666 | return err; | 666 | return err; |
667 | } | 667 | } |
668 | 668 | ||
669 | /* Decrease the count, but don't shut down the service */ | 669 | /* Decrease the count, but don't shut down the service */ |
670 | nfsd_serv->sv_nrthreads--; | 670 | nfsd_serv->sv_nrthreads--; |
671 | return err; | 671 | return err; |
672 | } | 672 | } |
673 | 673 | ||
674 | /* | 674 | /* |
675 | * A '-' followed by the 'name' of a socket means we close the socket. | 675 | * A '-' followed by the 'name' of a socket means we close the socket. |
676 | */ | 676 | */ |
677 | static ssize_t __write_ports_delfd(char *buf) | 677 | static ssize_t __write_ports_delfd(char *buf) |
678 | { | 678 | { |
679 | char *toclose; | 679 | char *toclose; |
680 | int len = 0; | 680 | int len = 0; |
681 | 681 | ||
682 | toclose = kstrdup(buf + 1, GFP_KERNEL); | 682 | toclose = kstrdup(buf + 1, GFP_KERNEL); |
683 | if (toclose == NULL) | 683 | if (toclose == NULL) |
684 | return -ENOMEM; | 684 | return -ENOMEM; |
685 | 685 | ||
686 | if (nfsd_serv != NULL) | 686 | if (nfsd_serv != NULL) |
687 | len = svc_sock_names(nfsd_serv, buf, | 687 | len = svc_sock_names(nfsd_serv, buf, |
688 | SIMPLE_TRANSACTION_LIMIT, toclose); | 688 | SIMPLE_TRANSACTION_LIMIT, toclose); |
689 | kfree(toclose); | 689 | kfree(toclose); |
690 | return len; | 690 | return len; |
691 | } | 691 | } |
692 | 692 | ||
693 | /* | 693 | /* |
694 | * A transport listener is added by writing it's transport name and | 694 | * A transport listener is added by writing it's transport name and |
695 | * a port number. | 695 | * a port number. |
696 | */ | 696 | */ |
697 | static ssize_t __write_ports_addxprt(char *buf) | 697 | static ssize_t __write_ports_addxprt(char *buf) |
698 | { | 698 | { |
699 | char transport[16]; | 699 | char transport[16]; |
700 | struct svc_xprt *xprt; | 700 | struct svc_xprt *xprt; |
701 | int port, err; | 701 | int port, err; |
702 | 702 | ||
703 | if (sscanf(buf, "%15s %4u", transport, &port) != 2) | 703 | if (sscanf(buf, "%15s %4u", transport, &port) != 2) |
704 | return -EINVAL; | 704 | return -EINVAL; |
705 | 705 | ||
706 | if (port < 1 || port > USHRT_MAX) | 706 | if (port < 1 || port > USHRT_MAX) |
707 | return -EINVAL; | 707 | return -EINVAL; |
708 | 708 | ||
709 | err = nfsd_create_serv(); | 709 | err = nfsd_create_serv(); |
710 | if (err != 0) | 710 | if (err != 0) |
711 | return err; | 711 | return err; |
712 | 712 | ||
713 | err = svc_create_xprt(nfsd_serv, transport, &init_net, | 713 | err = svc_create_xprt(nfsd_serv, transport, &init_net, |
714 | PF_INET, port, SVC_SOCK_ANONYMOUS); | 714 | PF_INET, port, SVC_SOCK_ANONYMOUS); |
715 | if (err < 0) | 715 | if (err < 0) |
716 | goto out_err; | 716 | goto out_err; |
717 | 717 | ||
718 | err = svc_create_xprt(nfsd_serv, transport, &init_net, | 718 | err = svc_create_xprt(nfsd_serv, transport, &init_net, |
719 | PF_INET6, port, SVC_SOCK_ANONYMOUS); | 719 | PF_INET6, port, SVC_SOCK_ANONYMOUS); |
720 | if (err < 0 && err != -EAFNOSUPPORT) | 720 | if (err < 0 && err != -EAFNOSUPPORT) |
721 | goto out_close; | 721 | goto out_close; |
722 | 722 | ||
723 | /* Decrease the count, but don't shut down the service */ | 723 | /* Decrease the count, but don't shut down the service */ |
724 | nfsd_serv->sv_nrthreads--; | 724 | nfsd_serv->sv_nrthreads--; |
725 | return 0; | 725 | return 0; |
726 | out_close: | 726 | out_close: |
727 | xprt = svc_find_xprt(nfsd_serv, transport, &init_net, PF_INET, port); | 727 | xprt = svc_find_xprt(nfsd_serv, transport, &init_net, PF_INET, port); |
728 | if (xprt != NULL) { | 728 | if (xprt != NULL) { |
729 | svc_close_xprt(xprt); | 729 | svc_close_xprt(xprt); |
730 | svc_xprt_put(xprt); | 730 | svc_xprt_put(xprt); |
731 | } | 731 | } |
732 | out_err: | 732 | out_err: |
733 | svc_destroy(nfsd_serv); | 733 | svc_destroy(nfsd_serv); |
734 | return err; | 734 | return err; |
735 | } | 735 | } |
736 | 736 | ||
737 | /* | 737 | /* |
738 | * A transport listener is removed by writing a "-", it's transport | 738 | * A transport listener is removed by writing a "-", it's transport |
739 | * name, and it's port number. | 739 | * name, and it's port number. |
740 | */ | 740 | */ |
741 | static ssize_t __write_ports_delxprt(char *buf) | 741 | static ssize_t __write_ports_delxprt(char *buf) |
742 | { | 742 | { |
743 | struct svc_xprt *xprt; | 743 | struct svc_xprt *xprt; |
744 | char transport[16]; | 744 | char transport[16]; |
745 | int port; | 745 | int port; |
746 | 746 | ||
747 | if (sscanf(&buf[1], "%15s %4u", transport, &port) != 2) | 747 | if (sscanf(&buf[1], "%15s %4u", transport, &port) != 2) |
748 | return -EINVAL; | 748 | return -EINVAL; |
749 | 749 | ||
750 | if (port < 1 || port > USHRT_MAX || nfsd_serv == NULL) | 750 | if (port < 1 || port > USHRT_MAX || nfsd_serv == NULL) |
751 | return -EINVAL; | 751 | return -EINVAL; |
752 | 752 | ||
753 | xprt = svc_find_xprt(nfsd_serv, transport, &init_net, AF_UNSPEC, port); | 753 | xprt = svc_find_xprt(nfsd_serv, transport, &init_net, AF_UNSPEC, port); |
754 | if (xprt == NULL) | 754 | if (xprt == NULL) |
755 | return -ENOTCONN; | 755 | return -ENOTCONN; |
756 | 756 | ||
757 | svc_close_xprt(xprt); | 757 | svc_close_xprt(xprt); |
758 | svc_xprt_put(xprt); | 758 | svc_xprt_put(xprt); |
759 | return 0; | 759 | return 0; |
760 | } | 760 | } |
761 | 761 | ||
762 | static ssize_t __write_ports(struct file *file, char *buf, size_t size) | 762 | static ssize_t __write_ports(struct file *file, char *buf, size_t size) |
763 | { | 763 | { |
764 | if (size == 0) | 764 | if (size == 0) |
765 | return __write_ports_names(buf); | 765 | return __write_ports_names(buf); |
766 | 766 | ||
767 | if (isdigit(buf[0])) | 767 | if (isdigit(buf[0])) |
768 | return __write_ports_addfd(buf); | 768 | return __write_ports_addfd(buf); |
769 | 769 | ||
770 | if (buf[0] == '-' && isdigit(buf[1])) | 770 | if (buf[0] == '-' && isdigit(buf[1])) |
771 | return __write_ports_delfd(buf); | 771 | return __write_ports_delfd(buf); |
772 | 772 | ||
773 | if (isalpha(buf[0])) | 773 | if (isalpha(buf[0])) |
774 | return __write_ports_addxprt(buf); | 774 | return __write_ports_addxprt(buf); |
775 | 775 | ||
776 | if (buf[0] == '-' && isalpha(buf[1])) | 776 | if (buf[0] == '-' && isalpha(buf[1])) |
777 | return __write_ports_delxprt(buf); | 777 | return __write_ports_delxprt(buf); |
778 | 778 | ||
779 | return -EINVAL; | 779 | return -EINVAL; |
780 | } | 780 | } |
781 | 781 | ||
782 | /** | 782 | /** |
783 | * write_ports - Pass a socket file descriptor or transport name to listen on | 783 | * write_ports - Pass a socket file descriptor or transport name to listen on |
784 | * | 784 | * |
785 | * Input: | 785 | * Input: |
786 | * buf: ignored | 786 | * buf: ignored |
787 | * size: zero | 787 | * size: zero |
788 | * Output: | 788 | * Output: |
789 | * On success: passed-in buffer filled with a '\n'-terminated C | 789 | * On success: passed-in buffer filled with a '\n'-terminated C |
790 | * string containing a whitespace-separated list of | 790 | * string containing a whitespace-separated list of |
791 | * named NFSD listeners; | 791 | * named NFSD listeners; |
792 | * return code is the size in bytes of the string | 792 | * return code is the size in bytes of the string |
793 | * On error: return code is zero or a negative errno value | 793 | * On error: return code is zero or a negative errno value |
794 | * | 794 | * |
795 | * OR | 795 | * OR |
796 | * | 796 | * |
797 | * Input: | 797 | * Input: |
798 | * buf: C string containing an unsigned | 798 | * buf: C string containing an unsigned |
799 | * integer value representing a bound | 799 | * integer value representing a bound |
800 | * but unconnected socket that is to be | 800 | * but unconnected socket that is to be |
801 | * used as an NFSD listener; listen(3) | 801 | * used as an NFSD listener; listen(3) |
802 | * must be called for a SOCK_STREAM | 802 | * must be called for a SOCK_STREAM |
803 | * socket, otherwise it is ignored | 803 | * socket, otherwise it is ignored |
804 | * size: non-zero length of C string in @buf | 804 | * size: non-zero length of C string in @buf |
805 | * Output: | 805 | * Output: |
806 | * On success: NFS service is started; | 806 | * On success: NFS service is started; |
807 | * passed-in buffer filled with a '\n'-terminated C | 807 | * passed-in buffer filled with a '\n'-terminated C |
808 | * string containing a unique alphanumeric name of | 808 | * string containing a unique alphanumeric name of |
809 | * the listener; | 809 | * the listener; |
810 | * return code is the size in bytes of the string | 810 | * return code is the size in bytes of the string |
811 | * On error: return code is a negative errno value | 811 | * On error: return code is a negative errno value |
812 | * | 812 | * |
813 | * OR | 813 | * OR |
814 | * | 814 | * |
815 | * Input: | 815 | * Input: |
816 | * buf: C string containing a "-" followed | 816 | * buf: C string containing a "-" followed |
817 | * by an integer value representing a | 817 | * by an integer value representing a |
818 | * previously passed in socket file | 818 | * previously passed in socket file |
819 | * descriptor | 819 | * descriptor |
820 | * size: non-zero length of C string in @buf | 820 | * size: non-zero length of C string in @buf |
821 | * Output: | 821 | * Output: |
822 | * On success: NFS service no longer listens on that socket; | 822 | * On success: NFS service no longer listens on that socket; |
823 | * passed-in buffer filled with a '\n'-terminated C | 823 | * passed-in buffer filled with a '\n'-terminated C |
824 | * string containing a unique name of the listener; | 824 | * string containing a unique name of the listener; |
825 | * return code is the size in bytes of the string | 825 | * return code is the size in bytes of the string |
826 | * On error: return code is a negative errno value | 826 | * On error: return code is a negative errno value |
827 | * | 827 | * |
828 | * OR | 828 | * OR |
829 | * | 829 | * |
830 | * Input: | 830 | * Input: |
831 | * buf: C string containing a transport | 831 | * buf: C string containing a transport |
832 | * name and an unsigned integer value | 832 | * name and an unsigned integer value |
833 | * representing the port to listen on, | 833 | * representing the port to listen on, |
834 | * separated by whitespace | 834 | * separated by whitespace |
835 | * size: non-zero length of C string in @buf | 835 | * size: non-zero length of C string in @buf |
836 | * Output: | 836 | * Output: |
837 | * On success: returns zero; NFS service is started | 837 | * On success: returns zero; NFS service is started |
838 | * On error: return code is a negative errno value | 838 | * On error: return code is a negative errno value |
839 | * | 839 | * |
840 | * OR | 840 | * OR |
841 | * | 841 | * |
842 | * Input: | 842 | * Input: |
843 | * buf: C string containing a "-" followed | 843 | * buf: C string containing a "-" followed |
844 | * by a transport name and an unsigned | 844 | * by a transport name and an unsigned |
845 | * integer value representing the port | 845 | * integer value representing the port |
846 | * to listen on, separated by whitespace | 846 | * to listen on, separated by whitespace |
847 | * size: non-zero length of C string in @buf | 847 | * size: non-zero length of C string in @buf |
848 | * Output: | 848 | * Output: |
849 | * On success: returns zero; NFS service no longer listens | 849 | * On success: returns zero; NFS service no longer listens |
850 | * on that transport | 850 | * on that transport |
851 | * On error: return code is a negative errno value | 851 | * On error: return code is a negative errno value |
852 | */ | 852 | */ |
853 | static ssize_t write_ports(struct file *file, char *buf, size_t size) | 853 | static ssize_t write_ports(struct file *file, char *buf, size_t size) |
854 | { | 854 | { |
855 | ssize_t rv; | 855 | ssize_t rv; |
856 | 856 | ||
857 | mutex_lock(&nfsd_mutex); | 857 | mutex_lock(&nfsd_mutex); |
858 | rv = __write_ports(file, buf, size); | 858 | rv = __write_ports(file, buf, size); |
859 | mutex_unlock(&nfsd_mutex); | 859 | mutex_unlock(&nfsd_mutex); |
860 | return rv; | 860 | return rv; |
861 | } | 861 | } |
862 | 862 | ||
863 | 863 | ||
864 | int nfsd_max_blksize; | 864 | int nfsd_max_blksize; |
865 | 865 | ||
866 | /** | 866 | /** |
867 | * write_maxblksize - Set or report the current NFS blksize | 867 | * write_maxblksize - Set or report the current NFS blksize |
868 | * | 868 | * |
869 | * Input: | 869 | * Input: |
870 | * buf: ignored | 870 | * buf: ignored |
871 | * size: zero | 871 | * size: zero |
872 | * | 872 | * |
873 | * OR | 873 | * OR |
874 | * | 874 | * |
875 | * Input: | 875 | * Input: |
876 | * buf: C string containing an unsigned | 876 | * buf: C string containing an unsigned |
877 | * integer value representing the new | 877 | * integer value representing the new |
878 | * NFS blksize | 878 | * NFS blksize |
879 | * size: non-zero length of C string in @buf | 879 | * size: non-zero length of C string in @buf |
880 | * Output: | 880 | * Output: |
881 | * On success: passed-in buffer filled with '\n'-terminated C string | 881 | * On success: passed-in buffer filled with '\n'-terminated C string |
882 | * containing numeric value of the current NFS blksize | 882 | * containing numeric value of the current NFS blksize |
883 | * setting; | 883 | * setting; |
884 | * return code is the size in bytes of the string | 884 | * return code is the size in bytes of the string |
885 | * On error: return code is zero or a negative errno value | 885 | * On error: return code is zero or a negative errno value |
886 | */ | 886 | */ |
887 | static ssize_t write_maxblksize(struct file *file, char *buf, size_t size) | 887 | static ssize_t write_maxblksize(struct file *file, char *buf, size_t size) |
888 | { | 888 | { |
889 | char *mesg = buf; | 889 | char *mesg = buf; |
890 | if (size > 0) { | 890 | if (size > 0) { |
891 | int bsize; | 891 | int bsize; |
892 | int rv = get_int(&mesg, &bsize); | 892 | int rv = get_int(&mesg, &bsize); |
893 | if (rv) | 893 | if (rv) |
894 | return rv; | 894 | return rv; |
895 | /* force bsize into allowed range and | 895 | /* force bsize into allowed range and |
896 | * required alignment. | 896 | * required alignment. |
897 | */ | 897 | */ |
898 | if (bsize < 1024) | 898 | if (bsize < 1024) |
899 | bsize = 1024; | 899 | bsize = 1024; |
900 | if (bsize > NFSSVC_MAXBLKSIZE) | 900 | if (bsize > NFSSVC_MAXBLKSIZE) |
901 | bsize = NFSSVC_MAXBLKSIZE; | 901 | bsize = NFSSVC_MAXBLKSIZE; |
902 | bsize &= ~(1024-1); | 902 | bsize &= ~(1024-1); |
903 | mutex_lock(&nfsd_mutex); | 903 | mutex_lock(&nfsd_mutex); |
904 | if (nfsd_serv) { | 904 | if (nfsd_serv) { |
905 | mutex_unlock(&nfsd_mutex); | 905 | mutex_unlock(&nfsd_mutex); |
906 | return -EBUSY; | 906 | return -EBUSY; |
907 | } | 907 | } |
908 | nfsd_max_blksize = bsize; | 908 | nfsd_max_blksize = bsize; |
909 | mutex_unlock(&nfsd_mutex); | 909 | mutex_unlock(&nfsd_mutex); |
910 | } | 910 | } |
911 | 911 | ||
912 | return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%d\n", | 912 | return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%d\n", |
913 | nfsd_max_blksize); | 913 | nfsd_max_blksize); |
914 | } | 914 | } |
915 | 915 | ||
916 | #ifdef CONFIG_NFSD_V4 | 916 | #ifdef CONFIG_NFSD_V4 |
917 | static ssize_t __nfsd4_write_time(struct file *file, char *buf, size_t size, time_t *time) | 917 | static ssize_t __nfsd4_write_time(struct file *file, char *buf, size_t size, time_t *time) |
918 | { | 918 | { |
919 | char *mesg = buf; | 919 | char *mesg = buf; |
920 | int rv, i; | 920 | int rv, i; |
921 | 921 | ||
922 | if (size > 0) { | 922 | if (size > 0) { |
923 | if (nfsd_serv) | 923 | if (nfsd_serv) |
924 | return -EBUSY; | 924 | return -EBUSY; |
925 | rv = get_int(&mesg, &i); | 925 | rv = get_int(&mesg, &i); |
926 | if (rv) | 926 | if (rv) |
927 | return rv; | 927 | return rv; |
928 | /* | 928 | /* |
929 | * Some sanity checking. We don't have a reason for | 929 | * Some sanity checking. We don't have a reason for |
930 | * these particular numbers, but problems with the | 930 | * these particular numbers, but problems with the |
931 | * extremes are: | 931 | * extremes are: |
932 | * - Too short: the briefest network outage may | 932 | * - Too short: the briefest network outage may |
933 | * cause clients to lose all their locks. Also, | 933 | * cause clients to lose all their locks. Also, |
934 | * the frequent polling may be wasteful. | 934 | * the frequent polling may be wasteful. |
935 | * - Too long: do you really want reboot recovery | 935 | * - Too long: do you really want reboot recovery |
936 | * to take more than an hour? Or to make other | 936 | * to take more than an hour? Or to make other |
937 | * clients wait an hour before being able to | 937 | * clients wait an hour before being able to |
938 | * revoke a dead client's locks? | 938 | * revoke a dead client's locks? |
939 | */ | 939 | */ |
940 | if (i < 10 || i > 3600) | 940 | if (i < 10 || i > 3600) |
941 | return -EINVAL; | 941 | return -EINVAL; |
942 | *time = i; | 942 | *time = i; |
943 | } | 943 | } |
944 | 944 | ||
945 | return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%ld\n", *time); | 945 | return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%ld\n", *time); |
946 | } | 946 | } |
947 | 947 | ||
948 | static ssize_t nfsd4_write_time(struct file *file, char *buf, size_t size, time_t *time) | 948 | static ssize_t nfsd4_write_time(struct file *file, char *buf, size_t size, time_t *time) |
949 | { | 949 | { |
950 | ssize_t rv; | 950 | ssize_t rv; |
951 | 951 | ||
952 | mutex_lock(&nfsd_mutex); | 952 | mutex_lock(&nfsd_mutex); |
953 | rv = __nfsd4_write_time(file, buf, size, time); | 953 | rv = __nfsd4_write_time(file, buf, size, time); |
954 | mutex_unlock(&nfsd_mutex); | 954 | mutex_unlock(&nfsd_mutex); |
955 | return rv; | 955 | return rv; |
956 | } | 956 | } |
957 | 957 | ||
958 | /** | 958 | /** |
959 | * write_leasetime - Set or report the current NFSv4 lease time | 959 | * write_leasetime - Set or report the current NFSv4 lease time |
960 | * | 960 | * |
961 | * Input: | 961 | * Input: |
962 | * buf: ignored | 962 | * buf: ignored |
963 | * size: zero | 963 | * size: zero |
964 | * | 964 | * |
965 | * OR | 965 | * OR |
966 | * | 966 | * |
967 | * Input: | 967 | * Input: |
968 | * buf: C string containing an unsigned | 968 | * buf: C string containing an unsigned |
969 | * integer value representing the new | 969 | * integer value representing the new |
970 | * NFSv4 lease expiry time | 970 | * NFSv4 lease expiry time |
971 | * size: non-zero length of C string in @buf | 971 | * size: non-zero length of C string in @buf |
972 | * Output: | 972 | * Output: |
973 | * On success: passed-in buffer filled with '\n'-terminated C | 973 | * On success: passed-in buffer filled with '\n'-terminated C |
974 | * string containing unsigned integer value of the | 974 | * string containing unsigned integer value of the |
975 | * current lease expiry time; | 975 | * current lease expiry time; |
976 | * return code is the size in bytes of the string | 976 | * return code is the size in bytes of the string |
977 | * On error: return code is zero or a negative errno value | 977 | * On error: return code is zero or a negative errno value |
978 | */ | 978 | */ |
979 | static ssize_t write_leasetime(struct file *file, char *buf, size_t size) | 979 | static ssize_t write_leasetime(struct file *file, char *buf, size_t size) |
980 | { | 980 | { |
981 | return nfsd4_write_time(file, buf, size, &nfsd4_lease); | 981 | return nfsd4_write_time(file, buf, size, &nfsd4_lease); |
982 | } | 982 | } |
983 | 983 | ||
984 | /** | 984 | /** |
985 | * write_gracetime - Set or report current NFSv4 grace period time | 985 | * write_gracetime - Set or report current NFSv4 grace period time |
986 | * | 986 | * |
987 | * As above, but sets the time of the NFSv4 grace period. | 987 | * As above, but sets the time of the NFSv4 grace period. |
988 | * | 988 | * |
989 | * Note this should never be set to less than the *previous* | 989 | * Note this should never be set to less than the *previous* |
990 | * lease-period time, but we don't try to enforce this. (In the common | 990 | * lease-period time, but we don't try to enforce this. (In the common |
991 | * case (a new boot), we don't know what the previous lease time was | 991 | * case (a new boot), we don't know what the previous lease time was |
992 | * anyway.) | 992 | * anyway.) |
993 | */ | 993 | */ |
994 | static ssize_t write_gracetime(struct file *file, char *buf, size_t size) | 994 | static ssize_t write_gracetime(struct file *file, char *buf, size_t size) |
995 | { | 995 | { |
996 | return nfsd4_write_time(file, buf, size, &nfsd4_grace); | 996 | return nfsd4_write_time(file, buf, size, &nfsd4_grace); |
997 | } | 997 | } |
998 | 998 | ||
999 | extern char *nfs4_recoverydir(void); | 999 | extern char *nfs4_recoverydir(void); |
1000 | 1000 | ||
1001 | static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size) | 1001 | static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size) |
1002 | { | 1002 | { |
1003 | char *mesg = buf; | 1003 | char *mesg = buf; |
1004 | char *recdir; | 1004 | char *recdir; |
1005 | int len, status; | 1005 | int len, status; |
1006 | 1006 | ||
1007 | if (size > 0) { | 1007 | if (size > 0) { |
1008 | if (nfsd_serv) | 1008 | if (nfsd_serv) |
1009 | return -EBUSY; | 1009 | return -EBUSY; |
1010 | if (size > PATH_MAX || buf[size-1] != '\n') | 1010 | if (size > PATH_MAX || buf[size-1] != '\n') |
1011 | return -EINVAL; | 1011 | return -EINVAL; |
1012 | buf[size-1] = 0; | 1012 | buf[size-1] = 0; |
1013 | 1013 | ||
1014 | recdir = mesg; | 1014 | recdir = mesg; |
1015 | len = qword_get(&mesg, recdir, size); | 1015 | len = qword_get(&mesg, recdir, size); |
1016 | if (len <= 0) | 1016 | if (len <= 0) |
1017 | return -EINVAL; | 1017 | return -EINVAL; |
1018 | 1018 | ||
1019 | status = nfs4_reset_recoverydir(recdir); | 1019 | status = nfs4_reset_recoverydir(recdir); |
1020 | if (status) | 1020 | if (status) |
1021 | return status; | 1021 | return status; |
1022 | } | 1022 | } |
1023 | 1023 | ||
1024 | return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%s\n", | 1024 | return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%s\n", |
1025 | nfs4_recoverydir()); | 1025 | nfs4_recoverydir()); |
1026 | } | 1026 | } |
1027 | 1027 | ||
1028 | /** | 1028 | /** |
1029 | * write_recoverydir - Set or report the pathname of the recovery directory | 1029 | * write_recoverydir - Set or report the pathname of the recovery directory |
1030 | * | 1030 | * |
1031 | * Input: | 1031 | * Input: |
1032 | * buf: ignored | 1032 | * buf: ignored |
1033 | * size: zero | 1033 | * size: zero |
1034 | * | 1034 | * |
1035 | * OR | 1035 | * OR |
1036 | * | 1036 | * |
1037 | * Input: | 1037 | * Input: |
1038 | * buf: C string containing the pathname | 1038 | * buf: C string containing the pathname |
1039 | * of the directory on a local file | 1039 | * of the directory on a local file |
1040 | * system containing permanent NFSv4 | 1040 | * system containing permanent NFSv4 |
1041 | * recovery data | 1041 | * recovery data |
1042 | * size: non-zero length of C string in @buf | 1042 | * size: non-zero length of C string in @buf |
1043 | * Output: | 1043 | * Output: |
1044 | * On success: passed-in buffer filled with '\n'-terminated C string | 1044 | * On success: passed-in buffer filled with '\n'-terminated C string |
1045 | * containing the current recovery pathname setting; | 1045 | * containing the current recovery pathname setting; |
1046 | * return code is the size in bytes of the string | 1046 | * return code is the size in bytes of the string |
1047 | * On error: return code is zero or a negative errno value | 1047 | * On error: return code is zero or a negative errno value |
1048 | */ | 1048 | */ |
1049 | static ssize_t write_recoverydir(struct file *file, char *buf, size_t size) | 1049 | static ssize_t write_recoverydir(struct file *file, char *buf, size_t size) |
1050 | { | 1050 | { |
1051 | ssize_t rv; | 1051 | ssize_t rv; |
1052 | 1052 | ||
1053 | mutex_lock(&nfsd_mutex); | 1053 | mutex_lock(&nfsd_mutex); |
1054 | rv = __write_recoverydir(file, buf, size); | 1054 | rv = __write_recoverydir(file, buf, size); |
1055 | mutex_unlock(&nfsd_mutex); | 1055 | mutex_unlock(&nfsd_mutex); |
1056 | return rv; | 1056 | return rv; |
1057 | } | 1057 | } |
1058 | 1058 | ||
1059 | #endif | 1059 | #endif |
1060 | 1060 | ||
1061 | /*----------------------------------------------------------------------------*/ | 1061 | /*----------------------------------------------------------------------------*/ |
1062 | /* | 1062 | /* |
1063 | * populating the filesystem. | 1063 | * populating the filesystem. |
1064 | */ | 1064 | */ |
1065 | 1065 | ||
1066 | static int nfsd_fill_super(struct super_block * sb, void * data, int silent) | 1066 | static int nfsd_fill_super(struct super_block * sb, void * data, int silent) |
1067 | { | 1067 | { |
1068 | static struct tree_descr nfsd_files[] = { | 1068 | static struct tree_descr nfsd_files[] = { |
1069 | [NFSD_List] = {"exports", &exports_operations, S_IRUGO}, | 1069 | [NFSD_List] = {"exports", &exports_operations, S_IRUGO}, |
1070 | [NFSD_Export_features] = {"export_features", | 1070 | [NFSD_Export_features] = {"export_features", |
1071 | &export_features_operations, S_IRUGO}, | 1071 | &export_features_operations, S_IRUGO}, |
1072 | [NFSD_FO_UnlockIP] = {"unlock_ip", | 1072 | [NFSD_FO_UnlockIP] = {"unlock_ip", |
1073 | &transaction_ops, S_IWUSR|S_IRUSR}, | 1073 | &transaction_ops, S_IWUSR|S_IRUSR}, |
1074 | [NFSD_FO_UnlockFS] = {"unlock_filesystem", | 1074 | [NFSD_FO_UnlockFS] = {"unlock_filesystem", |
1075 | &transaction_ops, S_IWUSR|S_IRUSR}, | 1075 | &transaction_ops, S_IWUSR|S_IRUSR}, |
1076 | [NFSD_Fh] = {"filehandle", &transaction_ops, S_IWUSR|S_IRUSR}, | 1076 | [NFSD_Fh] = {"filehandle", &transaction_ops, S_IWUSR|S_IRUSR}, |
1077 | [NFSD_Threads] = {"threads", &transaction_ops, S_IWUSR|S_IRUSR}, | 1077 | [NFSD_Threads] = {"threads", &transaction_ops, S_IWUSR|S_IRUSR}, |
1078 | [NFSD_Pool_Threads] = {"pool_threads", &transaction_ops, S_IWUSR|S_IRUSR}, | 1078 | [NFSD_Pool_Threads] = {"pool_threads", &transaction_ops, S_IWUSR|S_IRUSR}, |
1079 | [NFSD_Pool_Stats] = {"pool_stats", &pool_stats_operations, S_IRUGO}, | 1079 | [NFSD_Pool_Stats] = {"pool_stats", &pool_stats_operations, S_IRUGO}, |
1080 | [NFSD_Versions] = {"versions", &transaction_ops, S_IWUSR|S_IRUSR}, | 1080 | [NFSD_Versions] = {"versions", &transaction_ops, S_IWUSR|S_IRUSR}, |
1081 | [NFSD_Ports] = {"portlist", &transaction_ops, S_IWUSR|S_IRUGO}, | 1081 | [NFSD_Ports] = {"portlist", &transaction_ops, S_IWUSR|S_IRUGO}, |
1082 | [NFSD_MaxBlkSize] = {"max_block_size", &transaction_ops, S_IWUSR|S_IRUGO}, | 1082 | [NFSD_MaxBlkSize] = {"max_block_size", &transaction_ops, S_IWUSR|S_IRUGO}, |
1083 | #if defined(CONFIG_SUNRPC_GSS) || defined(CONFIG_SUNRPC_GSS_MODULE) | 1083 | #if defined(CONFIG_SUNRPC_GSS) || defined(CONFIG_SUNRPC_GSS_MODULE) |
1084 | [NFSD_SupportedEnctypes] = {"supported_krb5_enctypes", &supported_enctypes_ops, S_IRUGO}, | 1084 | [NFSD_SupportedEnctypes] = {"supported_krb5_enctypes", &supported_enctypes_ops, S_IRUGO}, |
1085 | #endif /* CONFIG_SUNRPC_GSS or CONFIG_SUNRPC_GSS_MODULE */ | 1085 | #endif /* CONFIG_SUNRPC_GSS or CONFIG_SUNRPC_GSS_MODULE */ |
1086 | #ifdef CONFIG_NFSD_V4 | 1086 | #ifdef CONFIG_NFSD_V4 |
1087 | [NFSD_Leasetime] = {"nfsv4leasetime", &transaction_ops, S_IWUSR|S_IRUSR}, | 1087 | [NFSD_Leasetime] = {"nfsv4leasetime", &transaction_ops, S_IWUSR|S_IRUSR}, |
1088 | [NFSD_Gracetime] = {"nfsv4gracetime", &transaction_ops, S_IWUSR|S_IRUSR}, | 1088 | [NFSD_Gracetime] = {"nfsv4gracetime", &transaction_ops, S_IWUSR|S_IRUSR}, |
1089 | [NFSD_RecoveryDir] = {"nfsv4recoverydir", &transaction_ops, S_IWUSR|S_IRUSR}, | 1089 | [NFSD_RecoveryDir] = {"nfsv4recoverydir", &transaction_ops, S_IWUSR|S_IRUSR}, |
1090 | #endif | 1090 | #endif |
1091 | /* last one */ {""} | 1091 | /* last one */ {""} |
1092 | }; | 1092 | }; |
1093 | return simple_fill_super(sb, 0x6e667364, nfsd_files); | 1093 | return simple_fill_super(sb, 0x6e667364, nfsd_files); |
1094 | } | 1094 | } |
1095 | 1095 | ||
1096 | static struct dentry *nfsd_mount(struct file_system_type *fs_type, | 1096 | static struct dentry *nfsd_mount(struct file_system_type *fs_type, |
1097 | int flags, const char *dev_name, void *data) | 1097 | int flags, const char *dev_name, void *data) |
1098 | { | 1098 | { |
1099 | return mount_single(fs_type, flags, data, nfsd_fill_super); | 1099 | return mount_single(fs_type, flags, data, nfsd_fill_super); |
1100 | } | 1100 | } |
1101 | 1101 | ||
1102 | static struct file_system_type nfsd_fs_type = { | 1102 | static struct file_system_type nfsd_fs_type = { |
1103 | .owner = THIS_MODULE, | 1103 | .owner = THIS_MODULE, |
1104 | .name = "nfsd", | 1104 | .name = "nfsd", |
1105 | .mount = nfsd_mount, | 1105 | .mount = nfsd_mount, |
1106 | .kill_sb = kill_litter_super, | 1106 | .kill_sb = kill_litter_super, |
1107 | }; | 1107 | }; |
1108 | 1108 | ||
1109 | #ifdef CONFIG_PROC_FS | 1109 | #ifdef CONFIG_PROC_FS |
1110 | static int create_proc_exports_entry(void) | 1110 | static int create_proc_exports_entry(void) |
1111 | { | 1111 | { |
1112 | struct proc_dir_entry *entry; | 1112 | struct proc_dir_entry *entry; |
1113 | 1113 | ||
1114 | entry = proc_mkdir("fs/nfs", NULL); | 1114 | entry = proc_mkdir("fs/nfs", NULL); |
1115 | if (!entry) | 1115 | if (!entry) |
1116 | return -ENOMEM; | 1116 | return -ENOMEM; |
1117 | entry = proc_create("exports", 0, entry, &exports_operations); | 1117 | entry = proc_create("exports", 0, entry, &exports_operations); |
1118 | if (!entry) | 1118 | if (!entry) |
1119 | return -ENOMEM; | 1119 | return -ENOMEM; |
1120 | return 0; | 1120 | return 0; |
1121 | } | 1121 | } |
1122 | #else /* CONFIG_PROC_FS */ | 1122 | #else /* CONFIG_PROC_FS */ |
1123 | static int create_proc_exports_entry(void) | 1123 | static int create_proc_exports_entry(void) |
1124 | { | 1124 | { |
1125 | return 0; | 1125 | return 0; |
1126 | } | 1126 | } |
1127 | #endif | 1127 | #endif |
1128 | 1128 | ||
1129 | int nfsd_net_id; | 1129 | int nfsd_net_id; |
1130 | static struct pernet_operations nfsd_net_ops = { | 1130 | static struct pernet_operations nfsd_net_ops = { |
1131 | .id = &nfsd_net_id, | 1131 | .id = &nfsd_net_id, |
1132 | .size = sizeof(struct nfsd_net), | 1132 | .size = sizeof(struct nfsd_net), |
1133 | }; | 1133 | }; |
1134 | 1134 | ||
1135 | static int __init init_nfsd(void) | 1135 | static int __init init_nfsd(void) |
1136 | { | 1136 | { |
1137 | int retval; | 1137 | int retval; |
1138 | printk(KERN_INFO "Installing knfsd (copyright (C) 1996 okir@monad.swb.de).\n"); | 1138 | printk(KERN_INFO "Installing knfsd (copyright (C) 1996 okir@monad.swb.de).\n"); |
1139 | 1139 | ||
1140 | retval = rpc_pipefs_notifier_register(&nfsd4_cld_block); | 1140 | retval = register_cld_notifier(); |
1141 | if (retval) | 1141 | if (retval) |
1142 | return retval; | 1142 | return retval; |
1143 | retval = register_pernet_subsys(&nfsd_net_ops); | 1143 | retval = register_pernet_subsys(&nfsd_net_ops); |
1144 | if (retval < 0) | 1144 | if (retval < 0) |
1145 | goto out_unregister_notifier; | 1145 | goto out_unregister_notifier; |
1146 | retval = nfsd4_init_slabs(); | 1146 | retval = nfsd4_init_slabs(); |
1147 | if (retval) | 1147 | if (retval) |
1148 | goto out_unregister_pernet; | 1148 | goto out_unregister_pernet; |
1149 | nfs4_state_init(); | 1149 | nfs4_state_init(); |
1150 | retval = nfsd_fault_inject_init(); /* nfsd fault injection controls */ | 1150 | retval = nfsd_fault_inject_init(); /* nfsd fault injection controls */ |
1151 | if (retval) | 1151 | if (retval) |
1152 | goto out_free_slabs; | 1152 | goto out_free_slabs; |
1153 | nfsd_stat_init(); /* Statistics */ | 1153 | nfsd_stat_init(); /* Statistics */ |
1154 | retval = nfsd_reply_cache_init(); | 1154 | retval = nfsd_reply_cache_init(); |
1155 | if (retval) | 1155 | if (retval) |
1156 | goto out_free_stat; | 1156 | goto out_free_stat; |
1157 | retval = nfsd_export_init(); | 1157 | retval = nfsd_export_init(); |
1158 | if (retval) | 1158 | if (retval) |
1159 | goto out_free_cache; | 1159 | goto out_free_cache; |
1160 | nfsd_lockd_init(); /* lockd->nfsd callbacks */ | 1160 | nfsd_lockd_init(); /* lockd->nfsd callbacks */ |
1161 | retval = nfsd_idmap_init(); | 1161 | retval = nfsd_idmap_init(); |
1162 | if (retval) | 1162 | if (retval) |
1163 | goto out_free_lockd; | 1163 | goto out_free_lockd; |
1164 | retval = create_proc_exports_entry(); | 1164 | retval = create_proc_exports_entry(); |
1165 | if (retval) | 1165 | if (retval) |
1166 | goto out_free_idmap; | 1166 | goto out_free_idmap; |
1167 | retval = register_filesystem(&nfsd_fs_type); | 1167 | retval = register_filesystem(&nfsd_fs_type); |
1168 | if (retval) | 1168 | if (retval) |
1169 | goto out_free_all; | 1169 | goto out_free_all; |
1170 | return 0; | 1170 | return 0; |
1171 | out_free_all: | 1171 | out_free_all: |
1172 | remove_proc_entry("fs/nfs/exports", NULL); | 1172 | remove_proc_entry("fs/nfs/exports", NULL); |
1173 | remove_proc_entry("fs/nfs", NULL); | 1173 | remove_proc_entry("fs/nfs", NULL); |
1174 | out_free_idmap: | 1174 | out_free_idmap: |
1175 | nfsd_idmap_shutdown(); | 1175 | nfsd_idmap_shutdown(); |
1176 | out_free_lockd: | 1176 | out_free_lockd: |
1177 | nfsd_lockd_shutdown(); | 1177 | nfsd_lockd_shutdown(); |
1178 | nfsd_export_shutdown(); | 1178 | nfsd_export_shutdown(); |
1179 | out_free_cache: | 1179 | out_free_cache: |
1180 | nfsd_reply_cache_shutdown(); | 1180 | nfsd_reply_cache_shutdown(); |
1181 | out_free_stat: | 1181 | out_free_stat: |
1182 | nfsd_stat_shutdown(); | 1182 | nfsd_stat_shutdown(); |
1183 | nfsd_fault_inject_cleanup(); | 1183 | nfsd_fault_inject_cleanup(); |
1184 | out_free_slabs: | 1184 | out_free_slabs: |
1185 | nfsd4_free_slabs(); | 1185 | nfsd4_free_slabs(); |
1186 | out_unregister_pernet: | 1186 | out_unregister_pernet: |
1187 | unregister_pernet_subsys(&nfsd_net_ops); | 1187 | unregister_pernet_subsys(&nfsd_net_ops); |
1188 | out_unregister_notifier: | 1188 | out_unregister_notifier: |
1189 | rpc_pipefs_notifier_unregister(&nfsd4_cld_block); | 1189 | unregister_cld_notifier(); |
1190 | return retval; | 1190 | return retval; |
1191 | } | 1191 | } |
1192 | 1192 | ||
1193 | static void __exit exit_nfsd(void) | 1193 | static void __exit exit_nfsd(void) |
1194 | { | 1194 | { |
1195 | nfsd_export_shutdown(); | 1195 | nfsd_export_shutdown(); |
1196 | nfsd_reply_cache_shutdown(); | 1196 | nfsd_reply_cache_shutdown(); |
1197 | remove_proc_entry("fs/nfs/exports", NULL); | 1197 | remove_proc_entry("fs/nfs/exports", NULL); |
1198 | remove_proc_entry("fs/nfs", NULL); | 1198 | remove_proc_entry("fs/nfs", NULL); |
1199 | nfsd_stat_shutdown(); | 1199 | nfsd_stat_shutdown(); |
1200 | nfsd_lockd_shutdown(); | 1200 | nfsd_lockd_shutdown(); |
1201 | nfsd_idmap_shutdown(); | 1201 | nfsd_idmap_shutdown(); |
1202 | nfsd4_free_slabs(); | 1202 | nfsd4_free_slabs(); |
1203 | nfsd_fault_inject_cleanup(); | 1203 | nfsd_fault_inject_cleanup(); |
1204 | unregister_filesystem(&nfsd_fs_type); | 1204 | unregister_filesystem(&nfsd_fs_type); |
1205 | unregister_pernet_subsys(&nfsd_net_ops); | 1205 | unregister_pernet_subsys(&nfsd_net_ops); |
1206 | rpc_pipefs_notifier_unregister(&nfsd4_cld_block); | 1206 | unregister_cld_notifier(); |
1207 | } | 1207 | } |
1208 | 1208 | ||
1209 | MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>"); | 1209 | MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>"); |
1210 | MODULE_LICENSE("GPL"); | 1210 | MODULE_LICENSE("GPL"); |
1211 | module_init(init_nfsd) | 1211 | module_init(init_nfsd) |
1212 | module_exit(exit_nfsd) | 1212 | module_exit(exit_nfsd) |
1213 | 1213 |
fs/nfsd/nfsd.h
1 | /* | 1 | /* |
2 | * Hodge-podge collection of knfsd-related stuff. | 2 | * Hodge-podge collection of knfsd-related stuff. |
3 | * I will sort this out later. | 3 | * I will sort this out later. |
4 | * | 4 | * |
5 | * Copyright (C) 1995-1997 Olaf Kirch <okir@monad.swb.de> | 5 | * Copyright (C) 1995-1997 Olaf Kirch <okir@monad.swb.de> |
6 | */ | 6 | */ |
7 | 7 | ||
8 | #ifndef LINUX_NFSD_NFSD_H | 8 | #ifndef LINUX_NFSD_NFSD_H |
9 | #define LINUX_NFSD_NFSD_H | 9 | #define LINUX_NFSD_NFSD_H |
10 | 10 | ||
11 | #include <linux/types.h> | 11 | #include <linux/types.h> |
12 | #include <linux/mount.h> | 12 | #include <linux/mount.h> |
13 | 13 | ||
14 | #include <linux/nfs.h> | 14 | #include <linux/nfs.h> |
15 | #include <linux/nfs2.h> | 15 | #include <linux/nfs2.h> |
16 | #include <linux/nfs3.h> | 16 | #include <linux/nfs3.h> |
17 | #include <linux/nfs4.h> | 17 | #include <linux/nfs4.h> |
18 | #include <linux/sunrpc/msg_prot.h> | 18 | #include <linux/sunrpc/msg_prot.h> |
19 | 19 | ||
20 | #include <linux/nfsd/debug.h> | 20 | #include <linux/nfsd/debug.h> |
21 | #include <linux/nfsd/export.h> | 21 | #include <linux/nfsd/export.h> |
22 | #include <linux/nfsd/stats.h> | 22 | #include <linux/nfsd/stats.h> |
23 | 23 | ||
24 | /* | 24 | /* |
25 | * nfsd version | 25 | * nfsd version |
26 | */ | 26 | */ |
27 | #define NFSD_SUPPORTED_MINOR_VERSION 1 | 27 | #define NFSD_SUPPORTED_MINOR_VERSION 1 |
28 | /* | 28 | /* |
29 | * Maximum blocksizes supported by daemon under various circumstances. | 29 | * Maximum blocksizes supported by daemon under various circumstances. |
30 | */ | 30 | */ |
31 | #define NFSSVC_MAXBLKSIZE RPCSVC_MAXPAYLOAD | 31 | #define NFSSVC_MAXBLKSIZE RPCSVC_MAXPAYLOAD |
32 | /* NFSv2 is limited by the protocol specification, see RFC 1094 */ | 32 | /* NFSv2 is limited by the protocol specification, see RFC 1094 */ |
33 | #define NFSSVC_MAXBLKSIZE_V2 (8*1024) | 33 | #define NFSSVC_MAXBLKSIZE_V2 (8*1024) |
34 | 34 | ||
35 | 35 | ||
36 | /* | 36 | /* |
37 | * Largest number of bytes we need to allocate for an NFS | 37 | * Largest number of bytes we need to allocate for an NFS |
38 | * call or reply. Used to control buffer sizes. We use | 38 | * call or reply. Used to control buffer sizes. We use |
39 | * the length of v3 WRITE, READDIR and READDIR replies | 39 | * the length of v3 WRITE, READDIR and READDIR replies |
40 | * which are an RPC header, up to 26 XDR units of reply | 40 | * which are an RPC header, up to 26 XDR units of reply |
41 | * data, and some page data. | 41 | * data, and some page data. |
42 | * | 42 | * |
43 | * Note that accuracy here doesn't matter too much as the | 43 | * Note that accuracy here doesn't matter too much as the |
44 | * size is rounded up to a page size when allocating space. | 44 | * size is rounded up to a page size when allocating space. |
45 | */ | 45 | */ |
46 | #define NFSD_BUFSIZE ((RPC_MAX_HEADER_WITH_AUTH+26)*XDR_UNIT + NFSSVC_MAXBLKSIZE) | 46 | #define NFSD_BUFSIZE ((RPC_MAX_HEADER_WITH_AUTH+26)*XDR_UNIT + NFSSVC_MAXBLKSIZE) |
47 | 47 | ||
48 | struct readdir_cd { | 48 | struct readdir_cd { |
49 | __be32 err; /* 0, nfserr, or nfserr_eof */ | 49 | __be32 err; /* 0, nfserr, or nfserr_eof */ |
50 | }; | 50 | }; |
51 | 51 | ||
52 | 52 | ||
53 | extern struct svc_program nfsd_program; | 53 | extern struct svc_program nfsd_program; |
54 | extern struct svc_version nfsd_version2, nfsd_version3, | 54 | 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; | 58 | extern struct svc_serv *nfsd_serv; |
59 | extern spinlock_t nfsd_drc_lock; | 59 | extern spinlock_t nfsd_drc_lock; |
60 | extern unsigned int nfsd_drc_max_mem; | 60 | extern unsigned int nfsd_drc_max_mem; |
61 | extern unsigned int nfsd_drc_mem_used; | 61 | extern unsigned int nfsd_drc_mem_used; |
62 | 62 | ||
63 | extern const struct seq_operations nfs_exports_op; | 63 | extern const struct seq_operations nfs_exports_op; |
64 | 64 | ||
65 | /* | 65 | /* |
66 | * Function prototypes. | 66 | * Function prototypes. |
67 | */ | 67 | */ |
68 | int nfsd_svc(unsigned short port, int nrservs); | 68 | int nfsd_svc(unsigned short port, int nrservs); |
69 | int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp); | 69 | int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp); |
70 | 70 | ||
71 | int nfsd_nrthreads(void); | 71 | int nfsd_nrthreads(void); |
72 | int nfsd_nrpools(void); | 72 | int nfsd_nrpools(void); |
73 | int nfsd_get_nrthreads(int n, int *); | 73 | int nfsd_get_nrthreads(int n, int *); |
74 | int nfsd_set_nrthreads(int n, int *); | 74 | int nfsd_set_nrthreads(int n, int *); |
75 | 75 | ||
76 | #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) | 76 | #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) |
77 | #ifdef CONFIG_NFSD_V2_ACL | 77 | #ifdef CONFIG_NFSD_V2_ACL |
78 | extern struct svc_version nfsd_acl_version2; | 78 | extern struct svc_version nfsd_acl_version2; |
79 | #else | 79 | #else |
80 | #define nfsd_acl_version2 NULL | 80 | #define nfsd_acl_version2 NULL |
81 | #endif | 81 | #endif |
82 | #ifdef CONFIG_NFSD_V3_ACL | 82 | #ifdef CONFIG_NFSD_V3_ACL |
83 | extern struct svc_version nfsd_acl_version3; | 83 | extern struct svc_version nfsd_acl_version3; |
84 | #else | 84 | #else |
85 | #define nfsd_acl_version3 NULL | 85 | #define nfsd_acl_version3 NULL |
86 | #endif | 86 | #endif |
87 | #endif | 87 | #endif |
88 | 88 | ||
89 | enum vers_op {NFSD_SET, NFSD_CLEAR, NFSD_TEST, NFSD_AVAIL }; | 89 | enum vers_op {NFSD_SET, NFSD_CLEAR, NFSD_TEST, NFSD_AVAIL }; |
90 | int nfsd_vers(int vers, enum vers_op change); | 90 | int nfsd_vers(int vers, enum vers_op change); |
91 | int nfsd_minorversion(u32 minorversion, enum vers_op change); | 91 | int nfsd_minorversion(u32 minorversion, enum vers_op change); |
92 | void nfsd_reset_versions(void); | 92 | void nfsd_reset_versions(void); |
93 | int nfsd_create_serv(void); | 93 | int nfsd_create_serv(void); |
94 | 94 | ||
95 | extern int nfsd_max_blksize; | 95 | extern int nfsd_max_blksize; |
96 | 96 | ||
97 | static inline int nfsd_v4client(struct svc_rqst *rq) | 97 | static inline int nfsd_v4client(struct svc_rqst *rq) |
98 | { | 98 | { |
99 | return rq->rq_prog == NFS_PROGRAM && rq->rq_vers == 4; | 99 | return rq->rq_prog == NFS_PROGRAM && rq->rq_vers == 4; |
100 | } | 100 | } |
101 | 101 | ||
102 | /* | 102 | /* |
103 | * NFSv4 State | 103 | * NFSv4 State |
104 | */ | 104 | */ |
105 | #ifdef CONFIG_NFSD_V4 | 105 | #ifdef CONFIG_NFSD_V4 |
106 | extern unsigned int max_delegations; | 106 | extern unsigned int max_delegations; |
107 | void nfs4_state_init(void); | 107 | void nfs4_state_init(void); |
108 | int nfsd4_init_slabs(void); | 108 | int nfsd4_init_slabs(void); |
109 | void nfsd4_free_slabs(void); | 109 | void nfsd4_free_slabs(void); |
110 | int nfs4_state_start(void); | 110 | int nfs4_state_start(void); |
111 | void nfs4_state_shutdown(void); | 111 | void nfs4_state_shutdown(void); |
112 | void nfs4_reset_lease(time_t leasetime); | 112 | void nfs4_reset_lease(time_t leasetime); |
113 | int nfs4_reset_recoverydir(char *recdir); | 113 | int nfs4_reset_recoverydir(char *recdir); |
114 | #else | 114 | #else |
115 | static inline void nfs4_state_init(void) { } | 115 | static inline void nfs4_state_init(void) { } |
116 | static inline int nfsd4_init_slabs(void) { return 0; } | 116 | static inline int nfsd4_init_slabs(void) { return 0; } |
117 | static inline void nfsd4_free_slabs(void) { } | 117 | static inline void nfsd4_free_slabs(void) { } |
118 | static inline int nfs4_state_start(void) { return 0; } | 118 | static inline int nfs4_state_start(void) { return 0; } |
119 | static inline void nfs4_state_shutdown(void) { } | 119 | static inline void nfs4_state_shutdown(void) { } |
120 | static inline void nfs4_reset_lease(time_t leasetime) { } | 120 | static inline void nfs4_reset_lease(time_t leasetime) { } |
121 | static inline int nfs4_reset_recoverydir(char *recdir) { return 0; } | 121 | static inline int nfs4_reset_recoverydir(char *recdir) { return 0; } |
122 | #endif | 122 | #endif |
123 | 123 | ||
124 | /* | 124 | /* |
125 | * lockd binding | 125 | * lockd binding |
126 | */ | 126 | */ |
127 | void nfsd_lockd_init(void); | 127 | void nfsd_lockd_init(void); |
128 | void nfsd_lockd_shutdown(void); | 128 | void nfsd_lockd_shutdown(void); |
129 | 129 | ||
130 | 130 | ||
131 | /* | 131 | /* |
132 | * These macros provide pre-xdr'ed values for faster operation. | 132 | * These macros provide pre-xdr'ed values for faster operation. |
133 | */ | 133 | */ |
134 | #define nfs_ok cpu_to_be32(NFS_OK) | 134 | #define nfs_ok cpu_to_be32(NFS_OK) |
135 | #define nfserr_perm cpu_to_be32(NFSERR_PERM) | 135 | #define nfserr_perm cpu_to_be32(NFSERR_PERM) |
136 | #define nfserr_noent cpu_to_be32(NFSERR_NOENT) | 136 | #define nfserr_noent cpu_to_be32(NFSERR_NOENT) |
137 | #define nfserr_io cpu_to_be32(NFSERR_IO) | 137 | #define nfserr_io cpu_to_be32(NFSERR_IO) |
138 | #define nfserr_nxio cpu_to_be32(NFSERR_NXIO) | 138 | #define nfserr_nxio cpu_to_be32(NFSERR_NXIO) |
139 | #define nfserr_eagain cpu_to_be32(NFSERR_EAGAIN) | 139 | #define nfserr_eagain cpu_to_be32(NFSERR_EAGAIN) |
140 | #define nfserr_acces cpu_to_be32(NFSERR_ACCES) | 140 | #define nfserr_acces cpu_to_be32(NFSERR_ACCES) |
141 | #define nfserr_exist cpu_to_be32(NFSERR_EXIST) | 141 | #define nfserr_exist cpu_to_be32(NFSERR_EXIST) |
142 | #define nfserr_xdev cpu_to_be32(NFSERR_XDEV) | 142 | #define nfserr_xdev cpu_to_be32(NFSERR_XDEV) |
143 | #define nfserr_nodev cpu_to_be32(NFSERR_NODEV) | 143 | #define nfserr_nodev cpu_to_be32(NFSERR_NODEV) |
144 | #define nfserr_notdir cpu_to_be32(NFSERR_NOTDIR) | 144 | #define nfserr_notdir cpu_to_be32(NFSERR_NOTDIR) |
145 | #define nfserr_isdir cpu_to_be32(NFSERR_ISDIR) | 145 | #define nfserr_isdir cpu_to_be32(NFSERR_ISDIR) |
146 | #define nfserr_inval cpu_to_be32(NFSERR_INVAL) | 146 | #define nfserr_inval cpu_to_be32(NFSERR_INVAL) |
147 | #define nfserr_fbig cpu_to_be32(NFSERR_FBIG) | 147 | #define nfserr_fbig cpu_to_be32(NFSERR_FBIG) |
148 | #define nfserr_nospc cpu_to_be32(NFSERR_NOSPC) | 148 | #define nfserr_nospc cpu_to_be32(NFSERR_NOSPC) |
149 | #define nfserr_rofs cpu_to_be32(NFSERR_ROFS) | 149 | #define nfserr_rofs cpu_to_be32(NFSERR_ROFS) |
150 | #define nfserr_mlink cpu_to_be32(NFSERR_MLINK) | 150 | #define nfserr_mlink cpu_to_be32(NFSERR_MLINK) |
151 | #define nfserr_opnotsupp cpu_to_be32(NFSERR_OPNOTSUPP) | 151 | #define nfserr_opnotsupp cpu_to_be32(NFSERR_OPNOTSUPP) |
152 | #define nfserr_nametoolong cpu_to_be32(NFSERR_NAMETOOLONG) | 152 | #define nfserr_nametoolong cpu_to_be32(NFSERR_NAMETOOLONG) |
153 | #define nfserr_notempty cpu_to_be32(NFSERR_NOTEMPTY) | 153 | #define nfserr_notempty cpu_to_be32(NFSERR_NOTEMPTY) |
154 | #define nfserr_dquot cpu_to_be32(NFSERR_DQUOT) | 154 | #define nfserr_dquot cpu_to_be32(NFSERR_DQUOT) |
155 | #define nfserr_stale cpu_to_be32(NFSERR_STALE) | 155 | #define nfserr_stale cpu_to_be32(NFSERR_STALE) |
156 | #define nfserr_remote cpu_to_be32(NFSERR_REMOTE) | 156 | #define nfserr_remote cpu_to_be32(NFSERR_REMOTE) |
157 | #define nfserr_wflush cpu_to_be32(NFSERR_WFLUSH) | 157 | #define nfserr_wflush cpu_to_be32(NFSERR_WFLUSH) |
158 | #define nfserr_badhandle cpu_to_be32(NFSERR_BADHANDLE) | 158 | #define nfserr_badhandle cpu_to_be32(NFSERR_BADHANDLE) |
159 | #define nfserr_notsync cpu_to_be32(NFSERR_NOT_SYNC) | 159 | #define nfserr_notsync cpu_to_be32(NFSERR_NOT_SYNC) |
160 | #define nfserr_badcookie cpu_to_be32(NFSERR_BAD_COOKIE) | 160 | #define nfserr_badcookie cpu_to_be32(NFSERR_BAD_COOKIE) |
161 | #define nfserr_notsupp cpu_to_be32(NFSERR_NOTSUPP) | 161 | #define nfserr_notsupp cpu_to_be32(NFSERR_NOTSUPP) |
162 | #define nfserr_toosmall cpu_to_be32(NFSERR_TOOSMALL) | 162 | #define nfserr_toosmall cpu_to_be32(NFSERR_TOOSMALL) |
163 | #define nfserr_serverfault cpu_to_be32(NFSERR_SERVERFAULT) | 163 | #define nfserr_serverfault cpu_to_be32(NFSERR_SERVERFAULT) |
164 | #define nfserr_badtype cpu_to_be32(NFSERR_BADTYPE) | 164 | #define nfserr_badtype cpu_to_be32(NFSERR_BADTYPE) |
165 | #define nfserr_jukebox cpu_to_be32(NFSERR_JUKEBOX) | 165 | #define nfserr_jukebox cpu_to_be32(NFSERR_JUKEBOX) |
166 | #define nfserr_denied cpu_to_be32(NFSERR_DENIED) | 166 | #define nfserr_denied cpu_to_be32(NFSERR_DENIED) |
167 | #define nfserr_deadlock cpu_to_be32(NFSERR_DEADLOCK) | 167 | #define nfserr_deadlock cpu_to_be32(NFSERR_DEADLOCK) |
168 | #define nfserr_expired cpu_to_be32(NFSERR_EXPIRED) | 168 | #define nfserr_expired cpu_to_be32(NFSERR_EXPIRED) |
169 | #define nfserr_bad_cookie cpu_to_be32(NFSERR_BAD_COOKIE) | 169 | #define nfserr_bad_cookie cpu_to_be32(NFSERR_BAD_COOKIE) |
170 | #define nfserr_same cpu_to_be32(NFSERR_SAME) | 170 | #define nfserr_same cpu_to_be32(NFSERR_SAME) |
171 | #define nfserr_clid_inuse cpu_to_be32(NFSERR_CLID_INUSE) | 171 | #define nfserr_clid_inuse cpu_to_be32(NFSERR_CLID_INUSE) |
172 | #define nfserr_stale_clientid cpu_to_be32(NFSERR_STALE_CLIENTID) | 172 | #define nfserr_stale_clientid cpu_to_be32(NFSERR_STALE_CLIENTID) |
173 | #define nfserr_resource cpu_to_be32(NFSERR_RESOURCE) | 173 | #define nfserr_resource cpu_to_be32(NFSERR_RESOURCE) |
174 | #define nfserr_moved cpu_to_be32(NFSERR_MOVED) | 174 | #define nfserr_moved cpu_to_be32(NFSERR_MOVED) |
175 | #define nfserr_nofilehandle cpu_to_be32(NFSERR_NOFILEHANDLE) | 175 | #define nfserr_nofilehandle cpu_to_be32(NFSERR_NOFILEHANDLE) |
176 | #define nfserr_minor_vers_mismatch cpu_to_be32(NFSERR_MINOR_VERS_MISMATCH) | 176 | #define nfserr_minor_vers_mismatch cpu_to_be32(NFSERR_MINOR_VERS_MISMATCH) |
177 | #define nfserr_share_denied cpu_to_be32(NFSERR_SHARE_DENIED) | 177 | #define nfserr_share_denied cpu_to_be32(NFSERR_SHARE_DENIED) |
178 | #define nfserr_stale_stateid cpu_to_be32(NFSERR_STALE_STATEID) | 178 | #define nfserr_stale_stateid cpu_to_be32(NFSERR_STALE_STATEID) |
179 | #define nfserr_old_stateid cpu_to_be32(NFSERR_OLD_STATEID) | 179 | #define nfserr_old_stateid cpu_to_be32(NFSERR_OLD_STATEID) |
180 | #define nfserr_bad_stateid cpu_to_be32(NFSERR_BAD_STATEID) | 180 | #define nfserr_bad_stateid cpu_to_be32(NFSERR_BAD_STATEID) |
181 | #define nfserr_bad_seqid cpu_to_be32(NFSERR_BAD_SEQID) | 181 | #define nfserr_bad_seqid cpu_to_be32(NFSERR_BAD_SEQID) |
182 | #define nfserr_symlink cpu_to_be32(NFSERR_SYMLINK) | 182 | #define nfserr_symlink cpu_to_be32(NFSERR_SYMLINK) |
183 | #define nfserr_not_same cpu_to_be32(NFSERR_NOT_SAME) | 183 | #define nfserr_not_same cpu_to_be32(NFSERR_NOT_SAME) |
184 | #define nfserr_lock_range cpu_to_be32(NFSERR_LOCK_RANGE) | 184 | #define nfserr_lock_range cpu_to_be32(NFSERR_LOCK_RANGE) |
185 | #define nfserr_restorefh cpu_to_be32(NFSERR_RESTOREFH) | 185 | #define nfserr_restorefh cpu_to_be32(NFSERR_RESTOREFH) |
186 | #define nfserr_attrnotsupp cpu_to_be32(NFSERR_ATTRNOTSUPP) | 186 | #define nfserr_attrnotsupp cpu_to_be32(NFSERR_ATTRNOTSUPP) |
187 | #define nfserr_bad_xdr cpu_to_be32(NFSERR_BAD_XDR) | 187 | #define nfserr_bad_xdr cpu_to_be32(NFSERR_BAD_XDR) |
188 | #define nfserr_openmode cpu_to_be32(NFSERR_OPENMODE) | 188 | #define nfserr_openmode cpu_to_be32(NFSERR_OPENMODE) |
189 | #define nfserr_badowner cpu_to_be32(NFSERR_BADOWNER) | 189 | #define nfserr_badowner cpu_to_be32(NFSERR_BADOWNER) |
190 | #define nfserr_locks_held cpu_to_be32(NFSERR_LOCKS_HELD) | 190 | #define nfserr_locks_held cpu_to_be32(NFSERR_LOCKS_HELD) |
191 | #define nfserr_op_illegal cpu_to_be32(NFSERR_OP_ILLEGAL) | 191 | #define nfserr_op_illegal cpu_to_be32(NFSERR_OP_ILLEGAL) |
192 | #define nfserr_grace cpu_to_be32(NFSERR_GRACE) | 192 | #define nfserr_grace cpu_to_be32(NFSERR_GRACE) |
193 | #define nfserr_no_grace cpu_to_be32(NFSERR_NO_GRACE) | 193 | #define nfserr_no_grace cpu_to_be32(NFSERR_NO_GRACE) |
194 | #define nfserr_reclaim_bad cpu_to_be32(NFSERR_RECLAIM_BAD) | 194 | #define nfserr_reclaim_bad cpu_to_be32(NFSERR_RECLAIM_BAD) |
195 | #define nfserr_badname cpu_to_be32(NFSERR_BADNAME) | 195 | #define nfserr_badname cpu_to_be32(NFSERR_BADNAME) |
196 | #define nfserr_cb_path_down cpu_to_be32(NFSERR_CB_PATH_DOWN) | 196 | #define nfserr_cb_path_down cpu_to_be32(NFSERR_CB_PATH_DOWN) |
197 | #define nfserr_locked cpu_to_be32(NFSERR_LOCKED) | 197 | #define nfserr_locked cpu_to_be32(NFSERR_LOCKED) |
198 | #define nfserr_wrongsec cpu_to_be32(NFSERR_WRONGSEC) | 198 | #define nfserr_wrongsec cpu_to_be32(NFSERR_WRONGSEC) |
199 | #define nfserr_badiomode cpu_to_be32(NFS4ERR_BADIOMODE) | 199 | #define nfserr_badiomode cpu_to_be32(NFS4ERR_BADIOMODE) |
200 | #define nfserr_badlayout cpu_to_be32(NFS4ERR_BADLAYOUT) | 200 | #define nfserr_badlayout cpu_to_be32(NFS4ERR_BADLAYOUT) |
201 | #define nfserr_bad_session_digest cpu_to_be32(NFS4ERR_BAD_SESSION_DIGEST) | 201 | #define nfserr_bad_session_digest cpu_to_be32(NFS4ERR_BAD_SESSION_DIGEST) |
202 | #define nfserr_badsession cpu_to_be32(NFS4ERR_BADSESSION) | 202 | #define nfserr_badsession cpu_to_be32(NFS4ERR_BADSESSION) |
203 | #define nfserr_badslot cpu_to_be32(NFS4ERR_BADSLOT) | 203 | #define nfserr_badslot cpu_to_be32(NFS4ERR_BADSLOT) |
204 | #define nfserr_complete_already cpu_to_be32(NFS4ERR_COMPLETE_ALREADY) | 204 | #define nfserr_complete_already cpu_to_be32(NFS4ERR_COMPLETE_ALREADY) |
205 | #define nfserr_conn_not_bound_to_session cpu_to_be32(NFS4ERR_CONN_NOT_BOUND_TO_SESSION) | 205 | #define nfserr_conn_not_bound_to_session cpu_to_be32(NFS4ERR_CONN_NOT_BOUND_TO_SESSION) |
206 | #define nfserr_deleg_already_wanted cpu_to_be32(NFS4ERR_DELEG_ALREADY_WANTED) | 206 | #define nfserr_deleg_already_wanted cpu_to_be32(NFS4ERR_DELEG_ALREADY_WANTED) |
207 | #define nfserr_back_chan_busy cpu_to_be32(NFS4ERR_BACK_CHAN_BUSY) | 207 | #define nfserr_back_chan_busy cpu_to_be32(NFS4ERR_BACK_CHAN_BUSY) |
208 | #define nfserr_layouttrylater cpu_to_be32(NFS4ERR_LAYOUTTRYLATER) | 208 | #define nfserr_layouttrylater cpu_to_be32(NFS4ERR_LAYOUTTRYLATER) |
209 | #define nfserr_layoutunavailable cpu_to_be32(NFS4ERR_LAYOUTUNAVAILABLE) | 209 | #define nfserr_layoutunavailable cpu_to_be32(NFS4ERR_LAYOUTUNAVAILABLE) |
210 | #define nfserr_nomatching_layout cpu_to_be32(NFS4ERR_NOMATCHING_LAYOUT) | 210 | #define nfserr_nomatching_layout cpu_to_be32(NFS4ERR_NOMATCHING_LAYOUT) |
211 | #define nfserr_recallconflict cpu_to_be32(NFS4ERR_RECALLCONFLICT) | 211 | #define nfserr_recallconflict cpu_to_be32(NFS4ERR_RECALLCONFLICT) |
212 | #define nfserr_unknown_layouttype cpu_to_be32(NFS4ERR_UNKNOWN_LAYOUTTYPE) | 212 | #define nfserr_unknown_layouttype cpu_to_be32(NFS4ERR_UNKNOWN_LAYOUTTYPE) |
213 | #define nfserr_seq_misordered cpu_to_be32(NFS4ERR_SEQ_MISORDERED) | 213 | #define nfserr_seq_misordered cpu_to_be32(NFS4ERR_SEQ_MISORDERED) |
214 | #define nfserr_sequence_pos cpu_to_be32(NFS4ERR_SEQUENCE_POS) | 214 | #define nfserr_sequence_pos cpu_to_be32(NFS4ERR_SEQUENCE_POS) |
215 | #define nfserr_req_too_big cpu_to_be32(NFS4ERR_REQ_TOO_BIG) | 215 | #define nfserr_req_too_big cpu_to_be32(NFS4ERR_REQ_TOO_BIG) |
216 | #define nfserr_rep_too_big cpu_to_be32(NFS4ERR_REP_TOO_BIG) | 216 | #define nfserr_rep_too_big cpu_to_be32(NFS4ERR_REP_TOO_BIG) |
217 | #define nfserr_rep_too_big_to_cache cpu_to_be32(NFS4ERR_REP_TOO_BIG_TO_CACHE) | 217 | #define nfserr_rep_too_big_to_cache cpu_to_be32(NFS4ERR_REP_TOO_BIG_TO_CACHE) |
218 | #define nfserr_retry_uncached_rep cpu_to_be32(NFS4ERR_RETRY_UNCACHED_REP) | 218 | #define nfserr_retry_uncached_rep cpu_to_be32(NFS4ERR_RETRY_UNCACHED_REP) |
219 | #define nfserr_unsafe_compound cpu_to_be32(NFS4ERR_UNSAFE_COMPOUND) | 219 | #define nfserr_unsafe_compound cpu_to_be32(NFS4ERR_UNSAFE_COMPOUND) |
220 | #define nfserr_too_many_ops cpu_to_be32(NFS4ERR_TOO_MANY_OPS) | 220 | #define nfserr_too_many_ops cpu_to_be32(NFS4ERR_TOO_MANY_OPS) |
221 | #define nfserr_op_not_in_session cpu_to_be32(NFS4ERR_OP_NOT_IN_SESSION) | 221 | #define nfserr_op_not_in_session cpu_to_be32(NFS4ERR_OP_NOT_IN_SESSION) |
222 | #define nfserr_hash_alg_unsupp cpu_to_be32(NFS4ERR_HASH_ALG_UNSUPP) | 222 | #define nfserr_hash_alg_unsupp cpu_to_be32(NFS4ERR_HASH_ALG_UNSUPP) |
223 | #define nfserr_clientid_busy cpu_to_be32(NFS4ERR_CLIENTID_BUSY) | 223 | #define nfserr_clientid_busy cpu_to_be32(NFS4ERR_CLIENTID_BUSY) |
224 | #define nfserr_pnfs_io_hole cpu_to_be32(NFS4ERR_PNFS_IO_HOLE) | 224 | #define nfserr_pnfs_io_hole cpu_to_be32(NFS4ERR_PNFS_IO_HOLE) |
225 | #define nfserr_seq_false_retry cpu_to_be32(NFS4ERR_SEQ_FALSE_RETRY) | 225 | #define nfserr_seq_false_retry cpu_to_be32(NFS4ERR_SEQ_FALSE_RETRY) |
226 | #define nfserr_bad_high_slot cpu_to_be32(NFS4ERR_BAD_HIGH_SLOT) | 226 | #define nfserr_bad_high_slot cpu_to_be32(NFS4ERR_BAD_HIGH_SLOT) |
227 | #define nfserr_deadsession cpu_to_be32(NFS4ERR_DEADSESSION) | 227 | #define nfserr_deadsession cpu_to_be32(NFS4ERR_DEADSESSION) |
228 | #define nfserr_encr_alg_unsupp cpu_to_be32(NFS4ERR_ENCR_ALG_UNSUPP) | 228 | #define nfserr_encr_alg_unsupp cpu_to_be32(NFS4ERR_ENCR_ALG_UNSUPP) |
229 | #define nfserr_pnfs_no_layout cpu_to_be32(NFS4ERR_PNFS_NO_LAYOUT) | 229 | #define nfserr_pnfs_no_layout cpu_to_be32(NFS4ERR_PNFS_NO_LAYOUT) |
230 | #define nfserr_not_only_op cpu_to_be32(NFS4ERR_NOT_ONLY_OP) | 230 | #define nfserr_not_only_op cpu_to_be32(NFS4ERR_NOT_ONLY_OP) |
231 | #define nfserr_wrong_cred cpu_to_be32(NFS4ERR_WRONG_CRED) | 231 | #define nfserr_wrong_cred cpu_to_be32(NFS4ERR_WRONG_CRED) |
232 | #define nfserr_wrong_type cpu_to_be32(NFS4ERR_WRONG_TYPE) | 232 | #define nfserr_wrong_type cpu_to_be32(NFS4ERR_WRONG_TYPE) |
233 | #define nfserr_dirdeleg_unavail cpu_to_be32(NFS4ERR_DIRDELEG_UNAVAIL) | 233 | #define nfserr_dirdeleg_unavail cpu_to_be32(NFS4ERR_DIRDELEG_UNAVAIL) |
234 | #define nfserr_reject_deleg cpu_to_be32(NFS4ERR_REJECT_DELEG) | 234 | #define nfserr_reject_deleg cpu_to_be32(NFS4ERR_REJECT_DELEG) |
235 | #define nfserr_returnconflict cpu_to_be32(NFS4ERR_RETURNCONFLICT) | 235 | #define nfserr_returnconflict cpu_to_be32(NFS4ERR_RETURNCONFLICT) |
236 | #define nfserr_deleg_revoked cpu_to_be32(NFS4ERR_DELEG_REVOKED) | 236 | #define nfserr_deleg_revoked cpu_to_be32(NFS4ERR_DELEG_REVOKED) |
237 | 237 | ||
238 | /* error codes for internal use */ | 238 | /* error codes for internal use */ |
239 | /* if a request fails due to kmalloc failure, it gets dropped. | 239 | /* if a request fails due to kmalloc failure, it gets dropped. |
240 | * Client should resend eventually | 240 | * Client should resend eventually |
241 | */ | 241 | */ |
242 | #define nfserr_dropit cpu_to_be32(30000) | 242 | #define nfserr_dropit cpu_to_be32(30000) |
243 | /* end-of-file indicator in readdir */ | 243 | /* end-of-file indicator in readdir */ |
244 | #define nfserr_eof cpu_to_be32(30001) | 244 | #define nfserr_eof cpu_to_be32(30001) |
245 | /* replay detected */ | 245 | /* replay detected */ |
246 | #define nfserr_replay_me cpu_to_be32(11001) | 246 | #define nfserr_replay_me cpu_to_be32(11001) |
247 | /* nfs41 replay detected */ | 247 | /* nfs41 replay detected */ |
248 | #define nfserr_replay_cache cpu_to_be32(11002) | 248 | #define nfserr_replay_cache cpu_to_be32(11002) |
249 | 249 | ||
250 | /* Check for dir entries '.' and '..' */ | 250 | /* Check for dir entries '.' and '..' */ |
251 | #define isdotent(n, l) (l < 3 && n[0] == '.' && (l == 1 || n[1] == '.')) | 251 | #define isdotent(n, l) (l < 3 && n[0] == '.' && (l == 1 || n[1] == '.')) |
252 | 252 | ||
253 | /* | 253 | /* |
254 | * Time of server startup | 254 | * Time of server startup |
255 | */ | 255 | */ |
256 | extern struct timeval nfssvc_boot; | 256 | extern struct timeval nfssvc_boot; |
257 | 257 | ||
258 | #ifdef CONFIG_NFSD_V4 | 258 | #ifdef CONFIG_NFSD_V4 |
259 | 259 | ||
260 | extern time_t nfsd4_lease; | 260 | extern time_t nfsd4_lease; |
261 | extern time_t nfsd4_grace; | 261 | extern time_t nfsd4_grace; |
262 | 262 | ||
263 | /* before processing a COMPOUND operation, we have to check that there | 263 | /* before processing a COMPOUND operation, we have to check that there |
264 | * is enough space in the buffer for XDR encode to succeed. otherwise, | 264 | * is enough space in the buffer for XDR encode to succeed. otherwise, |
265 | * we might process an operation with side effects, and be unable to | 265 | * we might process an operation with side effects, and be unable to |
266 | * tell the client that the operation succeeded. | 266 | * tell the client that the operation succeeded. |
267 | * | 267 | * |
268 | * COMPOUND_SLACK_SPACE - this is the minimum bytes of buffer space | 268 | * COMPOUND_SLACK_SPACE - this is the minimum bytes of buffer space |
269 | * needed to encode an "ordinary" _successful_ operation. (GETATTR, | 269 | * needed to encode an "ordinary" _successful_ operation. (GETATTR, |
270 | * READ, READDIR, and READLINK have their own buffer checks.) if we | 270 | * READ, READDIR, and READLINK have their own buffer checks.) if we |
271 | * fall below this level, we fail the next operation with NFS4ERR_RESOURCE. | 271 | * fall below this level, we fail the next operation with NFS4ERR_RESOURCE. |
272 | * | 272 | * |
273 | * COMPOUND_ERR_SLACK_SPACE - this is the minimum bytes of buffer space | 273 | * COMPOUND_ERR_SLACK_SPACE - this is the minimum bytes of buffer space |
274 | * needed to encode an operation which has failed with NFS4ERR_RESOURCE. | 274 | * needed to encode an operation which has failed with NFS4ERR_RESOURCE. |
275 | * care is taken to ensure that we never fall below this level for any | 275 | * care is taken to ensure that we never fall below this level for any |
276 | * reason. | 276 | * reason. |
277 | */ | 277 | */ |
278 | #define COMPOUND_SLACK_SPACE 140 /* OP_GETFH */ | 278 | #define COMPOUND_SLACK_SPACE 140 /* OP_GETFH */ |
279 | #define COMPOUND_ERR_SLACK_SPACE 12 /* OP_SETATTR */ | 279 | #define COMPOUND_ERR_SLACK_SPACE 12 /* OP_SETATTR */ |
280 | 280 | ||
281 | #define NFSD_LAUNDROMAT_MINTIMEOUT 1 /* seconds */ | 281 | #define NFSD_LAUNDROMAT_MINTIMEOUT 1 /* seconds */ |
282 | 282 | ||
283 | /* | 283 | /* |
284 | * The following attributes are currently not supported by the NFSv4 server: | 284 | * The following attributes are currently not supported by the NFSv4 server: |
285 | * ARCHIVE (deprecated anyway) | 285 | * ARCHIVE (deprecated anyway) |
286 | * HIDDEN (unlikely to be supported any time soon) | 286 | * HIDDEN (unlikely to be supported any time soon) |
287 | * MIMETYPE (unlikely to be supported any time soon) | 287 | * MIMETYPE (unlikely to be supported any time soon) |
288 | * QUOTA_* (will be supported in a forthcoming patch) | 288 | * QUOTA_* (will be supported in a forthcoming patch) |
289 | * SYSTEM (unlikely to be supported any time soon) | 289 | * SYSTEM (unlikely to be supported any time soon) |
290 | * TIME_BACKUP (unlikely to be supported any time soon) | 290 | * TIME_BACKUP (unlikely to be supported any time soon) |
291 | * TIME_CREATE (unlikely to be supported any time soon) | 291 | * TIME_CREATE (unlikely to be supported any time soon) |
292 | */ | 292 | */ |
293 | #define NFSD4_SUPPORTED_ATTRS_WORD0 \ | 293 | #define NFSD4_SUPPORTED_ATTRS_WORD0 \ |
294 | (FATTR4_WORD0_SUPPORTED_ATTRS | FATTR4_WORD0_TYPE | FATTR4_WORD0_FH_EXPIRE_TYPE \ | 294 | (FATTR4_WORD0_SUPPORTED_ATTRS | FATTR4_WORD0_TYPE | FATTR4_WORD0_FH_EXPIRE_TYPE \ |
295 | | FATTR4_WORD0_CHANGE | FATTR4_WORD0_SIZE | FATTR4_WORD0_LINK_SUPPORT \ | 295 | | FATTR4_WORD0_CHANGE | FATTR4_WORD0_SIZE | FATTR4_WORD0_LINK_SUPPORT \ |
296 | | FATTR4_WORD0_SYMLINK_SUPPORT | FATTR4_WORD0_NAMED_ATTR | FATTR4_WORD0_FSID \ | 296 | | FATTR4_WORD0_SYMLINK_SUPPORT | FATTR4_WORD0_NAMED_ATTR | FATTR4_WORD0_FSID \ |
297 | | FATTR4_WORD0_UNIQUE_HANDLES | FATTR4_WORD0_LEASE_TIME | FATTR4_WORD0_RDATTR_ERROR \ | 297 | | FATTR4_WORD0_UNIQUE_HANDLES | FATTR4_WORD0_LEASE_TIME | FATTR4_WORD0_RDATTR_ERROR \ |
298 | | FATTR4_WORD0_ACLSUPPORT | FATTR4_WORD0_CANSETTIME | FATTR4_WORD0_CASE_INSENSITIVE \ | 298 | | FATTR4_WORD0_ACLSUPPORT | FATTR4_WORD0_CANSETTIME | FATTR4_WORD0_CASE_INSENSITIVE \ |
299 | | FATTR4_WORD0_CASE_PRESERVING | FATTR4_WORD0_CHOWN_RESTRICTED \ | 299 | | FATTR4_WORD0_CASE_PRESERVING | FATTR4_WORD0_CHOWN_RESTRICTED \ |
300 | | FATTR4_WORD0_FILEHANDLE | FATTR4_WORD0_FILEID | FATTR4_WORD0_FILES_AVAIL \ | 300 | | FATTR4_WORD0_FILEHANDLE | FATTR4_WORD0_FILEID | FATTR4_WORD0_FILES_AVAIL \ |
301 | | FATTR4_WORD0_FILES_FREE | FATTR4_WORD0_FILES_TOTAL | FATTR4_WORD0_FS_LOCATIONS | FATTR4_WORD0_HOMOGENEOUS \ | 301 | | FATTR4_WORD0_FILES_FREE | FATTR4_WORD0_FILES_TOTAL | FATTR4_WORD0_FS_LOCATIONS | FATTR4_WORD0_HOMOGENEOUS \ |
302 | | FATTR4_WORD0_MAXFILESIZE | FATTR4_WORD0_MAXLINK | FATTR4_WORD0_MAXNAME \ | 302 | | FATTR4_WORD0_MAXFILESIZE | FATTR4_WORD0_MAXLINK | FATTR4_WORD0_MAXNAME \ |
303 | | FATTR4_WORD0_MAXREAD | FATTR4_WORD0_MAXWRITE | FATTR4_WORD0_ACL) | 303 | | FATTR4_WORD0_MAXREAD | FATTR4_WORD0_MAXWRITE | FATTR4_WORD0_ACL) |
304 | 304 | ||
305 | #define NFSD4_SUPPORTED_ATTRS_WORD1 \ | 305 | #define NFSD4_SUPPORTED_ATTRS_WORD1 \ |
306 | (FATTR4_WORD1_MODE | FATTR4_WORD1_NO_TRUNC | FATTR4_WORD1_NUMLINKS \ | 306 | (FATTR4_WORD1_MODE | FATTR4_WORD1_NO_TRUNC | FATTR4_WORD1_NUMLINKS \ |
307 | | FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP | FATTR4_WORD1_RAWDEV \ | 307 | | FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP | FATTR4_WORD1_RAWDEV \ |
308 | | FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE | FATTR4_WORD1_SPACE_TOTAL \ | 308 | | FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE | FATTR4_WORD1_SPACE_TOTAL \ |
309 | | FATTR4_WORD1_SPACE_USED | FATTR4_WORD1_TIME_ACCESS | FATTR4_WORD1_TIME_ACCESS_SET \ | 309 | | FATTR4_WORD1_SPACE_USED | FATTR4_WORD1_TIME_ACCESS | FATTR4_WORD1_TIME_ACCESS_SET \ |
310 | | FATTR4_WORD1_TIME_DELTA | FATTR4_WORD1_TIME_METADATA \ | 310 | | FATTR4_WORD1_TIME_DELTA | FATTR4_WORD1_TIME_METADATA \ |
311 | | FATTR4_WORD1_TIME_MODIFY | FATTR4_WORD1_TIME_MODIFY_SET | FATTR4_WORD1_MOUNTED_ON_FILEID) | 311 | | FATTR4_WORD1_TIME_MODIFY | FATTR4_WORD1_TIME_MODIFY_SET | FATTR4_WORD1_MOUNTED_ON_FILEID) |
312 | 312 | ||
313 | #define NFSD4_SUPPORTED_ATTRS_WORD2 0 | 313 | #define NFSD4_SUPPORTED_ATTRS_WORD2 0 |
314 | 314 | ||
315 | #define NFSD4_1_SUPPORTED_ATTRS_WORD0 \ | 315 | #define NFSD4_1_SUPPORTED_ATTRS_WORD0 \ |
316 | NFSD4_SUPPORTED_ATTRS_WORD0 | 316 | NFSD4_SUPPORTED_ATTRS_WORD0 |
317 | 317 | ||
318 | #define NFSD4_1_SUPPORTED_ATTRS_WORD1 \ | 318 | #define NFSD4_1_SUPPORTED_ATTRS_WORD1 \ |
319 | NFSD4_SUPPORTED_ATTRS_WORD1 | 319 | NFSD4_SUPPORTED_ATTRS_WORD1 |
320 | 320 | ||
321 | #define NFSD4_1_SUPPORTED_ATTRS_WORD2 \ | 321 | #define NFSD4_1_SUPPORTED_ATTRS_WORD2 \ |
322 | (NFSD4_SUPPORTED_ATTRS_WORD2 | FATTR4_WORD2_SUPPATTR_EXCLCREAT) | 322 | (NFSD4_SUPPORTED_ATTRS_WORD2 | FATTR4_WORD2_SUPPATTR_EXCLCREAT) |
323 | 323 | ||
324 | static inline u32 nfsd_suppattrs0(u32 minorversion) | 324 | static inline u32 nfsd_suppattrs0(u32 minorversion) |
325 | { | 325 | { |
326 | return minorversion ? NFSD4_1_SUPPORTED_ATTRS_WORD0 | 326 | return minorversion ? NFSD4_1_SUPPORTED_ATTRS_WORD0 |
327 | : NFSD4_SUPPORTED_ATTRS_WORD0; | 327 | : NFSD4_SUPPORTED_ATTRS_WORD0; |
328 | } | 328 | } |
329 | 329 | ||
330 | static inline u32 nfsd_suppattrs1(u32 minorversion) | 330 | static inline u32 nfsd_suppattrs1(u32 minorversion) |
331 | { | 331 | { |
332 | return minorversion ? NFSD4_1_SUPPORTED_ATTRS_WORD1 | 332 | return minorversion ? NFSD4_1_SUPPORTED_ATTRS_WORD1 |
333 | : NFSD4_SUPPORTED_ATTRS_WORD1; | 333 | : NFSD4_SUPPORTED_ATTRS_WORD1; |
334 | } | 334 | } |
335 | 335 | ||
336 | static inline u32 nfsd_suppattrs2(u32 minorversion) | 336 | static inline u32 nfsd_suppattrs2(u32 minorversion) |
337 | { | 337 | { |
338 | return minorversion ? NFSD4_1_SUPPORTED_ATTRS_WORD2 | 338 | return minorversion ? NFSD4_1_SUPPORTED_ATTRS_WORD2 |
339 | : NFSD4_SUPPORTED_ATTRS_WORD2; | 339 | : NFSD4_SUPPORTED_ATTRS_WORD2; |
340 | } | 340 | } |
341 | 341 | ||
342 | /* These will return ERR_INVAL if specified in GETATTR or READDIR. */ | 342 | /* These will return ERR_INVAL if specified in GETATTR or READDIR. */ |
343 | #define NFSD_WRITEONLY_ATTRS_WORD1 \ | 343 | #define NFSD_WRITEONLY_ATTRS_WORD1 \ |
344 | (FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET) | 344 | (FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET) |
345 | 345 | ||
346 | /* These are the only attrs allowed in CREATE/OPEN/SETATTR. */ | 346 | /* These are the only attrs allowed in CREATE/OPEN/SETATTR. */ |
347 | #define NFSD_WRITEABLE_ATTRS_WORD0 \ | 347 | #define NFSD_WRITEABLE_ATTRS_WORD0 \ |
348 | (FATTR4_WORD0_SIZE | FATTR4_WORD0_ACL) | 348 | (FATTR4_WORD0_SIZE | FATTR4_WORD0_ACL) |
349 | #define NFSD_WRITEABLE_ATTRS_WORD1 \ | 349 | #define NFSD_WRITEABLE_ATTRS_WORD1 \ |
350 | (FATTR4_WORD1_MODE | FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP \ | 350 | (FATTR4_WORD1_MODE | FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP \ |
351 | | FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET) | 351 | | FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET) |
352 | #define NFSD_WRITEABLE_ATTRS_WORD2 0 | 352 | #define NFSD_WRITEABLE_ATTRS_WORD2 0 |
353 | 353 | ||
354 | #define NFSD_SUPPATTR_EXCLCREAT_WORD0 \ | 354 | #define NFSD_SUPPATTR_EXCLCREAT_WORD0 \ |
355 | NFSD_WRITEABLE_ATTRS_WORD0 | 355 | NFSD_WRITEABLE_ATTRS_WORD0 |
356 | /* | 356 | /* |
357 | * we currently store the exclusive create verifier in the v_{a,m}time | 357 | * we currently store the exclusive create verifier in the v_{a,m}time |
358 | * attributes so the client can't set these at create time using EXCLUSIVE4_1 | 358 | * attributes so the client can't set these at create time using EXCLUSIVE4_1 |
359 | */ | 359 | */ |
360 | #define NFSD_SUPPATTR_EXCLCREAT_WORD1 \ | 360 | #define NFSD_SUPPATTR_EXCLCREAT_WORD1 \ |
361 | (NFSD_WRITEABLE_ATTRS_WORD1 & \ | 361 | (NFSD_WRITEABLE_ATTRS_WORD1 & \ |
362 | ~(FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET)) | 362 | ~(FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET)) |
363 | #define NFSD_SUPPATTR_EXCLCREAT_WORD2 \ | 363 | #define NFSD_SUPPATTR_EXCLCREAT_WORD2 \ |
364 | NFSD_WRITEABLE_ATTRS_WORD2 | 364 | NFSD_WRITEABLE_ATTRS_WORD2 |
365 | 365 | ||
366 | extern int nfsd4_is_junction(struct dentry *dentry); | 366 | extern int nfsd4_is_junction(struct dentry *dentry); |
367 | #else | 367 | extern int register_cld_notifier(void); |
368 | extern void unregister_cld_notifier(void); | ||
369 | #else /* CONFIG_NFSD_V4 */ | ||
368 | static inline int nfsd4_is_junction(struct dentry *dentry) | 370 | static inline int nfsd4_is_junction(struct dentry *dentry) |
369 | { | 371 | { |
370 | return 0; | 372 | return 0; |
371 | } | 373 | } |
374 | |||
375 | #define register_cld_notifier() 0 | ||
376 | #define unregister_cld_notifier() do { } while(0) | ||
372 | 377 | ||
373 | #endif /* CONFIG_NFSD_V4 */ | 378 | #endif /* CONFIG_NFSD_V4 */ |
374 | 379 | ||
375 | #endif /* LINUX_NFSD_NFSD_H */ | 380 | #endif /* LINUX_NFSD_NFSD_H */ |
376 | 381 |