Blame view
fs/nfsd/nfs4recover.c
9.76 KB
a55370a3c [PATCH] knfsd: nf... |
1 |
/* |
a55370a3c [PATCH] knfsd: nf... |
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
* Copyright (c) 2004 The Regents of the University of Michigan. * All rights reserved. * * Andy Adamson <andros@citi.umich.edu> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ |
190e4fbf9 [PATCH] knfsd: nf... |
33 |
#include <linux/file.h> |
5a0e3ad6a include cleanup: ... |
34 |
#include <linux/slab.h> |
190e4fbf9 [PATCH] knfsd: nf... |
35 |
#include <linux/namei.h> |
a55370a3c [PATCH] knfsd: nf... |
36 |
#include <linux/crypto.h> |
e8edc6e03 Detach sched.h fr... |
37 |
#include <linux/sched.h> |
9a74af213 nfsd: Move privat... |
38 39 40 |
#include "nfsd.h" #include "state.h" |
0a3adadee nfsd: make fs/nfs... |
41 |
#include "vfs.h" |
a55370a3c [PATCH] knfsd: nf... |
42 43 |
#define NFSDDBG_FACILITY NFSDDBG_PROC |
190e4fbf9 [PATCH] knfsd: nf... |
44 |
/* Globals */ |
e970a573c nfsd: open a file... |
45 |
static struct file *rec_file; |
48483bf23 nfsd4: simplify r... |
46 |
static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery"; |
190e4fbf9 [PATCH] knfsd: nf... |
47 |
|
d84f4f992 CRED: Inaugurate ... |
48 49 |
static int nfs4_save_creds(const struct cred **original_creds) |
190e4fbf9 [PATCH] knfsd: nf... |
50 |
{ |
d84f4f992 CRED: Inaugurate ... |
51 52 53 54 55 56 57 58 59 60 61 |
struct cred *new; new = prepare_creds(); if (!new) return -ENOMEM; new->fsuid = 0; new->fsgid = 0; *original_creds = override_creds(new); put_cred(new); return 0; |
190e4fbf9 [PATCH] knfsd: nf... |
62 63 64 |
} static void |
d84f4f992 CRED: Inaugurate ... |
65 |
nfs4_reset_creds(const struct cred *original) |
190e4fbf9 [PATCH] knfsd: nf... |
66 |
{ |
d84f4f992 CRED: Inaugurate ... |
67 |
revert_creds(original); |
190e4fbf9 [PATCH] knfsd: nf... |
68 |
} |
a55370a3c [PATCH] knfsd: nf... |
69 70 71 72 73 74 75 76 77 78 79 80 81 |
static void md5_to_hex(char *out, char *md5) { int i; for (i=0; i<16; i++) { unsigned char c = md5[i]; *out++ = '0' + ((c&0xf0)>>4) + (c>=0xa0)*('a'-'9'-1); *out++ = '0' + (c&0x0f) + ((c&0x0f)>=0x0a)*('a'-'9'-1); } *out = '\0'; } |
b37ad28bc [PATCH] nfsd: nfs... |
82 |
__be32 |
a55370a3c [PATCH] knfsd: nf... |
83 84 85 |
nfs4_make_rec_clidname(char *dname, struct xdr_netobj *clname) { struct xdr_netobj cksum; |
350586879 [CRYPTO] users: U... |
86 |
struct hash_desc desc; |
60c74f819 Update fs/ to use... |
87 |
struct scatterlist sg; |
3e7724639 nfsd4: stop using... |
88 |
__be32 status = nfserr_jukebox; |
a55370a3c [PATCH] knfsd: nf... |
89 90 91 92 |
dprintk("NFSD: nfs4_make_rec_clidname for %.*s ", clname->len, clname->data); |
350586879 [CRYPTO] users: U... |
93 94 95 96 97 |
desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP; desc.tfm = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC); if (IS_ERR(desc.tfm)) goto out_no_tfm; cksum.len = crypto_hash_digestsize(desc.tfm); |
a55370a3c [PATCH] knfsd: nf... |
98 99 100 |
cksum.data = kmalloc(cksum.len, GFP_KERNEL); if (cksum.data == NULL) goto out; |
a55370a3c [PATCH] knfsd: nf... |
101 |
|
60c74f819 Update fs/ to use... |
102 |
sg_init_one(&sg, clname->data, clname->len); |
a55370a3c [PATCH] knfsd: nf... |
103 |
|
60c74f819 Update fs/ to use... |
104 |
if (crypto_hash_digest(&desc, &sg, sg.length, cksum.data)) |
350586879 [CRYPTO] users: U... |
105 |
goto out; |
a55370a3c [PATCH] knfsd: nf... |
106 107 |
md5_to_hex(dname, cksum.data); |
a55370a3c [PATCH] knfsd: nf... |
108 109 |
status = nfs_ok; out: |
2bd9e7b62 nfsd: Fix leaked ... |
110 |
kfree(cksum.data); |
350586879 [CRYPTO] users: U... |
111 112 |
crypto_free_hash(desc.tfm); out_no_tfm: |
a55370a3c [PATCH] knfsd: nf... |
113 114 |
return status; } |
190e4fbf9 [PATCH] knfsd: nf... |
115 |
|
7a6ef8c72 nfsd4: nfsd4_crea... |
116 |
void nfsd4_create_clid_dir(struct nfs4_client *clp) |
c7b9a4592 [PATCH] knfsd: nf... |
117 |
{ |
d84f4f992 CRED: Inaugurate ... |
118 |
const struct cred *original_cred; |
c7b9a4592 [PATCH] knfsd: nf... |
119 |
char *dname = clp->cl_recdir; |
e970a573c nfsd: open a file... |
120 |
struct dentry *dir, *dentry; |
c7b9a4592 [PATCH] knfsd: nf... |
121 122 123 124 |
int status; dprintk("NFSD: nfsd4_create_clid_dir for \"%s\" ", dname); |
b8548894b nfsd4: be forgivi... |
125 |
if (clp->cl_firststate) |
7a6ef8c72 nfsd4: nfsd4_crea... |
126 |
return; |
6577aac01 nfsd4: fix failur... |
127 |
clp->cl_firststate = 1; |
b8548894b nfsd4: be forgivi... |
128 |
if (!rec_file) |
7a6ef8c72 nfsd4: nfsd4_crea... |
129 |
return; |
d84f4f992 CRED: Inaugurate ... |
130 131 |
status = nfs4_save_creds(&original_cred); if (status < 0) |
7a6ef8c72 nfsd4: nfsd4_crea... |
132 |
return; |
c7b9a4592 [PATCH] knfsd: nf... |
133 |
|
e970a573c nfsd: open a file... |
134 |
dir = rec_file->f_path.dentry; |
c7b9a4592 [PATCH] knfsd: nf... |
135 |
/* lock the parent */ |
e970a573c nfsd: open a file... |
136 |
mutex_lock(&dir->d_inode->i_mutex); |
c7b9a4592 [PATCH] knfsd: nf... |
137 |
|
e970a573c nfsd: open a file... |
138 |
dentry = lookup_one_len(dname, dir, HEXDIR_LEN-1); |
c7b9a4592 [PATCH] knfsd: nf... |
139 140 141 142 |
if (IS_ERR(dentry)) { status = PTR_ERR(dentry); goto out_unlock; } |
6577aac01 nfsd4: fix failur... |
143 |
if (dentry->d_inode) |
aec39680b nfsd4: fix spurio... |
144 145 146 147 148 149 150 151 |
/* * In the 4.1 case, where we're called from * reclaim_complete(), records from the previous reboot * may still be left, so this is OK. * * In the 4.0 case, we should never get here; but we may * as well be forgiving and just succeed silently. */ |
c7b9a4592 [PATCH] knfsd: nf... |
152 |
goto out_put; |
a561be710 switch a bunch of... |
153 |
status = mnt_want_write_file(rec_file); |
463c31972 [PATCH] r/o bind ... |
154 155 |
if (status) goto out_put; |
e970a573c nfsd: open a file... |
156 |
status = vfs_mkdir(dir->d_inode, dentry, S_IRWXU); |
2a79f17e4 vfs: mnt_drop_wri... |
157 |
mnt_drop_write_file(rec_file); |
c7b9a4592 [PATCH] knfsd: nf... |
158 159 160 |
out_put: dput(dentry); out_unlock: |
e970a573c nfsd: open a file... |
161 |
mutex_unlock(&dir->d_inode->i_mutex); |
6577aac01 nfsd4: fix failur... |
162 |
if (status == 0) |
8018ab057 sanitize vfs_fsyn... |
163 |
vfs_fsync(rec_file, 0); |
6577aac01 nfsd4: fix failur... |
164 165 166 167 168 |
else printk(KERN_ERR "NFSD: failed to write recovery record" " (err %d); please check that %s exists" " and is writeable", status, user_recovery_dirname); |
d84f4f992 CRED: Inaugurate ... |
169 |
nfs4_reset_creds(original_cred); |
c7b9a4592 [PATCH] knfsd: nf... |
170 |
} |
190e4fbf9 [PATCH] knfsd: nf... |
171 |
typedef int (recdir_func)(struct dentry *, struct dentry *); |
05f4f678b nfsd4: don't do l... |
172 173 |
struct name_list { char name[HEXDIR_LEN]; |
190e4fbf9 [PATCH] knfsd: nf... |
174 175 |
struct list_head list; }; |
190e4fbf9 [PATCH] knfsd: nf... |
176 |
static int |
05f4f678b nfsd4: don't do l... |
177 |
nfsd4_build_namelist(void *arg, const char *name, int namlen, |
afefdbb28 [PATCH] VFS: Make... |
178 |
loff_t offset, u64 ino, unsigned int d_type) |
190e4fbf9 [PATCH] knfsd: nf... |
179 |
{ |
05f4f678b nfsd4: don't do l... |
180 181 |
struct list_head *names = arg; struct name_list *entry; |
190e4fbf9 [PATCH] knfsd: nf... |
182 |
|
05f4f678b nfsd4: don't do l... |
183 |
if (namlen != HEXDIR_LEN - 1) |
b37ad28bc [PATCH] nfsd: nfs... |
184 |
return 0; |
05f4f678b nfsd4: don't do l... |
185 186 |
entry = kmalloc(sizeof(struct name_list), GFP_KERNEL); if (entry == NULL) |
190e4fbf9 [PATCH] knfsd: nf... |
187 |
return -ENOMEM; |
05f4f678b nfsd4: don't do l... |
188 189 190 |
memcpy(entry->name, name, HEXDIR_LEN - 1); entry->name[HEXDIR_LEN - 1] = '\0'; list_add(&entry->list, names); |
190e4fbf9 [PATCH] knfsd: nf... |
191 192 193 194 |
return 0; } static int |
5b4b299cc nfsd4_list_rec_di... |
195 |
nfsd4_list_rec_dir(recdir_func *f) |
190e4fbf9 [PATCH] knfsd: nf... |
196 |
{ |
d84f4f992 CRED: Inaugurate ... |
197 |
const struct cred *original_cred; |
5b4b299cc nfsd4_list_rec_di... |
198 |
struct dentry *dir = rec_file->f_path.dentry; |
05f4f678b nfsd4: don't do l... |
199 |
LIST_HEAD(names); |
190e4fbf9 [PATCH] knfsd: nf... |
200 |
int status; |
d84f4f992 CRED: Inaugurate ... |
201 202 203 |
status = nfs4_save_creds(&original_cred); if (status < 0) return status; |
190e4fbf9 [PATCH] knfsd: nf... |
204 |
|
5b4b299cc nfsd4_list_rec_di... |
205 206 207 208 209 210 211 |
status = vfs_llseek(rec_file, 0, SEEK_SET); if (status < 0) { nfs4_reset_creds(original_cred); return status; } status = vfs_readdir(rec_file, nfsd4_build_namelist, &names); |
8daed1e54 nfsd: silence loc... |
212 |
mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT); |
05f4f678b nfsd4: don't do l... |
213 |
while (!list_empty(&names)) { |
5b4b299cc nfsd4_list_rec_di... |
214 |
struct name_list *entry; |
05f4f678b nfsd4: don't do l... |
215 |
entry = list_entry(names.next, struct name_list, list); |
5b4b299cc nfsd4_list_rec_di... |
216 217 218 219 220 221 222 223 224 |
if (!status) { struct dentry *dentry; dentry = lookup_one_len(entry->name, dir, HEXDIR_LEN-1); if (IS_ERR(dentry)) { status = PTR_ERR(dentry); break; } status = f(dir, dentry); dput(dentry); |
05f4f678b nfsd4: don't do l... |
225 |
} |
05f4f678b nfsd4: don't do l... |
226 227 |
list_del(&entry->list); kfree(entry); |
190e4fbf9 [PATCH] knfsd: nf... |
228 |
} |
2f9092e10 Fix i_mutex vs. r... |
229 |
mutex_unlock(&dir->d_inode->i_mutex); |
d84f4f992 CRED: Inaugurate ... |
230 |
nfs4_reset_creds(original_cred); |
190e4fbf9 [PATCH] knfsd: nf... |
231 232 233 234 |
return status; } static int |
c7b9a4592 [PATCH] knfsd: nf... |
235 236 |
nfsd4_unlink_clid_dir(char *name, int namlen) { |
e970a573c nfsd: open a file... |
237 |
struct dentry *dir, *dentry; |
c7b9a4592 [PATCH] knfsd: nf... |
238 239 240 241 |
int status; dprintk("NFSD: nfsd4_unlink_clid_dir. name %.*s ", namlen, name); |
e970a573c nfsd: open a file... |
242 243 244 |
dir = rec_file->f_path.dentry; mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT); dentry = lookup_one_len(name, dir, namlen); |
c7b9a4592 [PATCH] knfsd: nf... |
245 246 |
if (IS_ERR(dentry)) { status = PTR_ERR(dentry); |
2f9092e10 Fix i_mutex vs. r... |
247 |
goto out_unlock; |
c7b9a4592 [PATCH] knfsd: nf... |
248 249 250 251 |
} status = -ENOENT; if (!dentry->d_inode) goto out; |
e970a573c nfsd: open a file... |
252 |
status = vfs_rmdir(dir->d_inode, dentry); |
c7b9a4592 [PATCH] knfsd: nf... |
253 254 |
out: dput(dentry); |
2f9092e10 Fix i_mutex vs. r... |
255 |
out_unlock: |
e970a573c nfsd: open a file... |
256 |
mutex_unlock(&dir->d_inode->i_mutex); |
c7b9a4592 [PATCH] knfsd: nf... |
257 258 259 260 261 262 |
return status; } void nfsd4_remove_clid_dir(struct nfs4_client *clp) { |
d84f4f992 CRED: Inaugurate ... |
263 |
const struct cred *original_cred; |
c7b9a4592 [PATCH] knfsd: nf... |
264 |
int status; |
e970a573c nfsd: open a file... |
265 |
if (!rec_file || !clp->cl_firststate) |
c7b9a4592 [PATCH] knfsd: nf... |
266 |
return; |
a561be710 switch a bunch of... |
267 |
status = mnt_want_write_file(rec_file); |
0622753b8 [PATCH] r/o bind ... |
268 269 |
if (status) goto out; |
67be43135 [PATCH] nfsd4: pr... |
270 |
clp->cl_firststate = 0; |
d84f4f992 CRED: Inaugurate ... |
271 272 273 274 |
status = nfs4_save_creds(&original_cred); if (status < 0) goto out; |
c7b9a4592 [PATCH] knfsd: nf... |
275 |
status = nfsd4_unlink_clid_dir(clp->cl_recdir, HEXDIR_LEN-1); |
d84f4f992 CRED: Inaugurate ... |
276 |
nfs4_reset_creds(original_cred); |
c7b9a4592 [PATCH] knfsd: nf... |
277 |
if (status == 0) |
8018ab057 sanitize vfs_fsyn... |
278 |
vfs_fsync(rec_file, 0); |
2a79f17e4 vfs: mnt_drop_wri... |
279 |
mnt_drop_write_file(rec_file); |
0622753b8 [PATCH] r/o bind ... |
280 |
out: |
c7b9a4592 [PATCH] knfsd: nf... |
281 282 283 284 285 286 287 288 289 290 291 |
if (status) printk("NFSD: Failed to remove expired client state directory" " %.*s ", HEXDIR_LEN, clp->cl_recdir); return; } static int purge_old(struct dentry *parent, struct dentry *child) { int status; |
a1bcecd29 nfsd41: match cli... |
292 |
if (nfs4_has_reclaimed_state(child->d_name.name, false)) |
b37ad28bc [PATCH] nfsd: nfs... |
293 |
return 0; |
c7b9a4592 [PATCH] knfsd: nf... |
294 |
|
2f9092e10 Fix i_mutex vs. r... |
295 |
status = vfs_rmdir(parent->d_inode, child); |
c7b9a4592 [PATCH] knfsd: nf... |
296 297 298 299 300 |
if (status) printk("failed to remove client recovery directory %s ", child->d_name.name); /* Keep trying, success or failure: */ |
b37ad28bc [PATCH] nfsd: nfs... |
301 |
return 0; |
c7b9a4592 [PATCH] knfsd: nf... |
302 303 304 305 306 |
} void nfsd4_recdir_purge_old(void) { int status; |
e970a573c nfsd: open a file... |
307 |
if (!rec_file) |
c7b9a4592 [PATCH] knfsd: nf... |
308 |
return; |
a561be710 switch a bunch of... |
309 |
status = mnt_want_write_file(rec_file); |
0622753b8 [PATCH] r/o bind ... |
310 311 |
if (status) goto out; |
5b4b299cc nfsd4_list_rec_di... |
312 |
status = nfsd4_list_rec_dir(purge_old); |
c7b9a4592 [PATCH] knfsd: nf... |
313 |
if (status == 0) |
8018ab057 sanitize vfs_fsyn... |
314 |
vfs_fsync(rec_file, 0); |
2a79f17e4 vfs: mnt_drop_wri... |
315 |
mnt_drop_write_file(rec_file); |
0622753b8 [PATCH] r/o bind ... |
316 |
out: |
c7b9a4592 [PATCH] knfsd: nf... |
317 318 |
if (status) printk("nfsd4: failed to purge old clients from recovery" |
e970a573c nfsd: open a file... |
319 320 |
" directory %s ", rec_file->f_path.dentry->d_name.name); |
c7b9a4592 [PATCH] knfsd: nf... |
321 322 323 |
} static int |
190e4fbf9 [PATCH] knfsd: nf... |
324 325 326 327 328 329 330 |
load_recdir(struct dentry *parent, struct dentry *child) { if (child->d_name.len != HEXDIR_LEN - 1) { printk("nfsd4: illegal name %s in recovery directory ", child->d_name.name); /* Keep trying; maybe the others are OK: */ |
b37ad28bc [PATCH] nfsd: nfs... |
331 |
return 0; |
190e4fbf9 [PATCH] knfsd: nf... |
332 333 |
} nfs4_client_to_reclaim(child->d_name.name); |
b37ad28bc [PATCH] nfsd: nfs... |
334 |
return 0; |
190e4fbf9 [PATCH] knfsd: nf... |
335 336 337 338 339 |
} int nfsd4_recdir_load(void) { int status; |
e970a573c nfsd: open a file... |
340 341 |
if (!rec_file) return 0; |
5b4b299cc nfsd4_list_rec_di... |
342 |
status = nfsd4_list_rec_dir(load_recdir); |
190e4fbf9 [PATCH] knfsd: nf... |
343 344 |
if (status) printk("nfsd4: failed loading clients from recovery" |
e970a573c nfsd: open a file... |
345 346 |
" directory %s ", rec_file->f_path.dentry->d_name.name); |
190e4fbf9 [PATCH] knfsd: nf... |
347 348 349 350 351 352 353 354 |
return status; } /* * Hold reference to the recovery directory. */ void |
48483bf23 nfsd4: simplify r... |
355 |
nfsd4_init_recdir() |
190e4fbf9 [PATCH] knfsd: nf... |
356 |
{ |
d84f4f992 CRED: Inaugurate ... |
357 358 |
const struct cred *original_cred; int status; |
190e4fbf9 [PATCH] knfsd: nf... |
359 360 361 |
printk("NFSD: Using %s as the NFSv4 state recovery directory ", |
48483bf23 nfsd4: simplify r... |
362 |
user_recovery_dirname); |
190e4fbf9 [PATCH] knfsd: nf... |
363 |
|
e970a573c nfsd: open a file... |
364 |
BUG_ON(rec_file); |
190e4fbf9 [PATCH] knfsd: nf... |
365 |
|
d84f4f992 CRED: Inaugurate ... |
366 367 368 369 370 371 372 373 |
status = nfs4_save_creds(&original_cred); if (status < 0) { printk("NFSD: Unable to change credentials to find recovery" " directory: error %d ", status); return; } |
190e4fbf9 [PATCH] knfsd: nf... |
374 |
|
48483bf23 nfsd4: simplify r... |
375 |
rec_file = filp_open(user_recovery_dirname, O_RDONLY | O_DIRECTORY, 0); |
e970a573c nfsd: open a file... |
376 |
if (IS_ERR(rec_file)) { |
c2642ab05 [PATCH] nfsd4: re... |
377 378 |
printk("NFSD: unable to find recovery directory %s ", |
48483bf23 nfsd4: simplify r... |
379 |
user_recovery_dirname); |
e970a573c nfsd: open a file... |
380 381 |
rec_file = NULL; } |
190e4fbf9 [PATCH] knfsd: nf... |
382 |
|
d84f4f992 CRED: Inaugurate ... |
383 |
nfs4_reset_creds(original_cred); |
190e4fbf9 [PATCH] knfsd: nf... |
384 385 386 387 388 |
} void nfsd4_shutdown_recdir(void) { |
e970a573c nfsd: open a file... |
389 |
if (!rec_file) |
190e4fbf9 [PATCH] knfsd: nf... |
390 |
return; |
e970a573c nfsd: open a file... |
391 392 |
fput(rec_file); rec_file = NULL; |
190e4fbf9 [PATCH] knfsd: nf... |
393 |
} |
48483bf23 nfsd4: simplify r... |
394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 |
/* * Change the NFSv4 recovery directory to recdir. */ int nfs4_reset_recoverydir(char *recdir) { int status; struct path path; status = kern_path(recdir, LOOKUP_FOLLOW, &path); if (status) return status; status = -ENOTDIR; if (S_ISDIR(path.dentry->d_inode->i_mode)) { strcpy(user_recovery_dirname, recdir); status = 0; } path_put(&path); return status; } char * nfs4_recoverydir(void) { return user_recovery_dirname; } |