Blame view
fs/nfsd/nfs4recover.c
9.56 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 |
|
c7b9a4592 [PATCH] knfsd: nf... |
116 117 118 |
int nfsd4_create_clid_dir(struct nfs4_client *clp) { |
d84f4f992 CRED: Inaugurate ... |
119 |
const struct cred *original_cred; |
c7b9a4592 [PATCH] knfsd: nf... |
120 |
char *dname = clp->cl_recdir; |
e970a573c nfsd: open a file... |
121 |
struct dentry *dir, *dentry; |
c7b9a4592 [PATCH] knfsd: nf... |
122 123 124 125 |
int status; dprintk("NFSD: nfsd4_create_clid_dir for \"%s\" ", dname); |
e970a573c nfsd: open a file... |
126 |
if (!rec_file || clp->cl_firststate) |
c7b9a4592 [PATCH] knfsd: nf... |
127 |
return 0; |
6577aac01 nfsd4: fix failur... |
128 |
clp->cl_firststate = 1; |
d84f4f992 CRED: Inaugurate ... |
129 130 131 |
status = nfs4_save_creds(&original_cred); if (status < 0) return status; |
c7b9a4592 [PATCH] knfsd: nf... |
132 |
|
e970a573c nfsd: open a file... |
133 |
dir = rec_file->f_path.dentry; |
c7b9a4592 [PATCH] knfsd: nf... |
134 |
/* lock the parent */ |
e970a573c nfsd: open a file... |
135 |
mutex_lock(&dir->d_inode->i_mutex); |
c7b9a4592 [PATCH] knfsd: nf... |
136 |
|
e970a573c nfsd: open a file... |
137 |
dentry = lookup_one_len(dname, dir, HEXDIR_LEN-1); |
c7b9a4592 [PATCH] knfsd: nf... |
138 139 140 141 142 |
if (IS_ERR(dentry)) { status = PTR_ERR(dentry); goto out_unlock; } status = -EEXIST; |
6577aac01 nfsd4: fix failur... |
143 |
if (dentry->d_inode) |
c7b9a4592 [PATCH] knfsd: nf... |
144 |
goto out_put; |
e970a573c nfsd: open a file... |
145 |
status = mnt_want_write(rec_file->f_path.mnt); |
463c31972 [PATCH] r/o bind ... |
146 147 |
if (status) goto out_put; |
e970a573c nfsd: open a file... |
148 149 |
status = vfs_mkdir(dir->d_inode, dentry, S_IRWXU); mnt_drop_write(rec_file->f_path.mnt); |
c7b9a4592 [PATCH] knfsd: nf... |
150 151 152 |
out_put: dput(dentry); out_unlock: |
e970a573c nfsd: open a file... |
153 |
mutex_unlock(&dir->d_inode->i_mutex); |
6577aac01 nfsd4: fix failur... |
154 |
if (status == 0) |
8018ab057 sanitize vfs_fsyn... |
155 |
vfs_fsync(rec_file, 0); |
6577aac01 nfsd4: fix failur... |
156 157 158 159 160 |
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 ... |
161 |
nfs4_reset_creds(original_cred); |
c7b9a4592 [PATCH] knfsd: nf... |
162 163 |
return status; } |
190e4fbf9 [PATCH] knfsd: nf... |
164 |
typedef int (recdir_func)(struct dentry *, struct dentry *); |
05f4f678b nfsd4: don't do l... |
165 166 |
struct name_list { char name[HEXDIR_LEN]; |
190e4fbf9 [PATCH] knfsd: nf... |
167 168 |
struct list_head list; }; |
190e4fbf9 [PATCH] knfsd: nf... |
169 |
static int |
05f4f678b nfsd4: don't do l... |
170 |
nfsd4_build_namelist(void *arg, const char *name, int namlen, |
afefdbb28 [PATCH] VFS: Make... |
171 |
loff_t offset, u64 ino, unsigned int d_type) |
190e4fbf9 [PATCH] knfsd: nf... |
172 |
{ |
05f4f678b nfsd4: don't do l... |
173 174 |
struct list_head *names = arg; struct name_list *entry; |
190e4fbf9 [PATCH] knfsd: nf... |
175 |
|
05f4f678b nfsd4: don't do l... |
176 |
if (namlen != HEXDIR_LEN - 1) |
b37ad28bc [PATCH] nfsd: nfs... |
177 |
return 0; |
05f4f678b nfsd4: don't do l... |
178 179 |
entry = kmalloc(sizeof(struct name_list), GFP_KERNEL); if (entry == NULL) |
190e4fbf9 [PATCH] knfsd: nf... |
180 |
return -ENOMEM; |
05f4f678b nfsd4: don't do l... |
181 182 183 |
memcpy(entry->name, name, HEXDIR_LEN - 1); entry->name[HEXDIR_LEN - 1] = '\0'; list_add(&entry->list, names); |
190e4fbf9 [PATCH] knfsd: nf... |
184 185 186 187 |
return 0; } static int |
5b4b299cc nfsd4_list_rec_di... |
188 |
nfsd4_list_rec_dir(recdir_func *f) |
190e4fbf9 [PATCH] knfsd: nf... |
189 |
{ |
d84f4f992 CRED: Inaugurate ... |
190 |
const struct cred *original_cred; |
5b4b299cc nfsd4_list_rec_di... |
191 |
struct dentry *dir = rec_file->f_path.dentry; |
05f4f678b nfsd4: don't do l... |
192 |
LIST_HEAD(names); |
190e4fbf9 [PATCH] knfsd: nf... |
193 |
int status; |
d84f4f992 CRED: Inaugurate ... |
194 195 196 |
status = nfs4_save_creds(&original_cred); if (status < 0) return status; |
190e4fbf9 [PATCH] knfsd: nf... |
197 |
|
5b4b299cc nfsd4_list_rec_di... |
198 199 200 201 202 203 204 |
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... |
205 |
mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT); |
05f4f678b nfsd4: don't do l... |
206 |
while (!list_empty(&names)) { |
5b4b299cc nfsd4_list_rec_di... |
207 |
struct name_list *entry; |
05f4f678b nfsd4: don't do l... |
208 |
entry = list_entry(names.next, struct name_list, list); |
5b4b299cc nfsd4_list_rec_di... |
209 210 211 212 213 214 215 216 217 |
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... |
218 |
} |
05f4f678b nfsd4: don't do l... |
219 220 |
list_del(&entry->list); kfree(entry); |
190e4fbf9 [PATCH] knfsd: nf... |
221 |
} |
2f9092e10 Fix i_mutex vs. r... |
222 |
mutex_unlock(&dir->d_inode->i_mutex); |
d84f4f992 CRED: Inaugurate ... |
223 |
nfs4_reset_creds(original_cred); |
190e4fbf9 [PATCH] knfsd: nf... |
224 225 226 227 |
return status; } static int |
c7b9a4592 [PATCH] knfsd: nf... |
228 229 |
nfsd4_unlink_clid_dir(char *name, int namlen) { |
e970a573c nfsd: open a file... |
230 |
struct dentry *dir, *dentry; |
c7b9a4592 [PATCH] knfsd: nf... |
231 232 233 234 |
int status; dprintk("NFSD: nfsd4_unlink_clid_dir. name %.*s ", namlen, name); |
e970a573c nfsd: open a file... |
235 236 237 |
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... |
238 239 |
if (IS_ERR(dentry)) { status = PTR_ERR(dentry); |
2f9092e10 Fix i_mutex vs. r... |
240 |
goto out_unlock; |
c7b9a4592 [PATCH] knfsd: nf... |
241 242 243 244 |
} status = -ENOENT; if (!dentry->d_inode) goto out; |
e970a573c nfsd: open a file... |
245 |
status = vfs_rmdir(dir->d_inode, dentry); |
c7b9a4592 [PATCH] knfsd: nf... |
246 247 |
out: dput(dentry); |
2f9092e10 Fix i_mutex vs. r... |
248 |
out_unlock: |
e970a573c nfsd: open a file... |
249 |
mutex_unlock(&dir->d_inode->i_mutex); |
c7b9a4592 [PATCH] knfsd: nf... |
250 251 252 253 254 255 |
return status; } void nfsd4_remove_clid_dir(struct nfs4_client *clp) { |
d84f4f992 CRED: Inaugurate ... |
256 |
const struct cred *original_cred; |
c7b9a4592 [PATCH] knfsd: nf... |
257 |
int status; |
e970a573c nfsd: open a file... |
258 |
if (!rec_file || !clp->cl_firststate) |
c7b9a4592 [PATCH] knfsd: nf... |
259 |
return; |
e970a573c nfsd: open a file... |
260 |
status = mnt_want_write(rec_file->f_path.mnt); |
0622753b8 [PATCH] r/o bind ... |
261 262 |
if (status) goto out; |
67be43135 [PATCH] nfsd4: pr... |
263 |
clp->cl_firststate = 0; |
d84f4f992 CRED: Inaugurate ... |
264 265 266 267 |
status = nfs4_save_creds(&original_cred); if (status < 0) goto out; |
c7b9a4592 [PATCH] knfsd: nf... |
268 |
status = nfsd4_unlink_clid_dir(clp->cl_recdir, HEXDIR_LEN-1); |
d84f4f992 CRED: Inaugurate ... |
269 |
nfs4_reset_creds(original_cred); |
c7b9a4592 [PATCH] knfsd: nf... |
270 |
if (status == 0) |
8018ab057 sanitize vfs_fsyn... |
271 |
vfs_fsync(rec_file, 0); |
e970a573c nfsd: open a file... |
272 |
mnt_drop_write(rec_file->f_path.mnt); |
0622753b8 [PATCH] r/o bind ... |
273 |
out: |
c7b9a4592 [PATCH] knfsd: nf... |
274 275 276 277 278 279 280 281 282 283 284 |
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... |
285 |
if (nfs4_has_reclaimed_state(child->d_name.name, false)) |
b37ad28bc [PATCH] nfsd: nfs... |
286 |
return 0; |
c7b9a4592 [PATCH] knfsd: nf... |
287 |
|
2f9092e10 Fix i_mutex vs. r... |
288 |
status = vfs_rmdir(parent->d_inode, child); |
c7b9a4592 [PATCH] knfsd: nf... |
289 290 291 292 293 |
if (status) printk("failed to remove client recovery directory %s ", child->d_name.name); /* Keep trying, success or failure: */ |
b37ad28bc [PATCH] nfsd: nfs... |
294 |
return 0; |
c7b9a4592 [PATCH] knfsd: nf... |
295 296 297 298 299 |
} void nfsd4_recdir_purge_old(void) { int status; |
e970a573c nfsd: open a file... |
300 |
if (!rec_file) |
c7b9a4592 [PATCH] knfsd: nf... |
301 |
return; |
e970a573c nfsd: open a file... |
302 |
status = mnt_want_write(rec_file->f_path.mnt); |
0622753b8 [PATCH] r/o bind ... |
303 304 |
if (status) goto out; |
5b4b299cc nfsd4_list_rec_di... |
305 |
status = nfsd4_list_rec_dir(purge_old); |
c7b9a4592 [PATCH] knfsd: nf... |
306 |
if (status == 0) |
8018ab057 sanitize vfs_fsyn... |
307 |
vfs_fsync(rec_file, 0); |
e970a573c nfsd: open a file... |
308 |
mnt_drop_write(rec_file->f_path.mnt); |
0622753b8 [PATCH] r/o bind ... |
309 |
out: |
c7b9a4592 [PATCH] knfsd: nf... |
310 311 |
if (status) printk("nfsd4: failed to purge old clients from recovery" |
e970a573c nfsd: open a file... |
312 313 |
" directory %s ", rec_file->f_path.dentry->d_name.name); |
c7b9a4592 [PATCH] knfsd: nf... |
314 315 316 |
} static int |
190e4fbf9 [PATCH] knfsd: nf... |
317 318 319 320 321 322 323 |
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... |
324 |
return 0; |
190e4fbf9 [PATCH] knfsd: nf... |
325 326 |
} nfs4_client_to_reclaim(child->d_name.name); |
b37ad28bc [PATCH] nfsd: nfs... |
327 |
return 0; |
190e4fbf9 [PATCH] knfsd: nf... |
328 329 330 331 332 |
} int nfsd4_recdir_load(void) { int status; |
e970a573c nfsd: open a file... |
333 334 |
if (!rec_file) return 0; |
5b4b299cc nfsd4_list_rec_di... |
335 |
status = nfsd4_list_rec_dir(load_recdir); |
190e4fbf9 [PATCH] knfsd: nf... |
336 337 |
if (status) printk("nfsd4: failed loading clients from recovery" |
e970a573c nfsd: open a file... |
338 339 |
" directory %s ", rec_file->f_path.dentry->d_name.name); |
190e4fbf9 [PATCH] knfsd: nf... |
340 341 342 343 344 345 346 347 |
return status; } /* * Hold reference to the recovery directory. */ void |
48483bf23 nfsd4: simplify r... |
348 |
nfsd4_init_recdir() |
190e4fbf9 [PATCH] knfsd: nf... |
349 |
{ |
d84f4f992 CRED: Inaugurate ... |
350 351 |
const struct cred *original_cred; int status; |
190e4fbf9 [PATCH] knfsd: nf... |
352 353 354 |
printk("NFSD: Using %s as the NFSv4 state recovery directory ", |
48483bf23 nfsd4: simplify r... |
355 |
user_recovery_dirname); |
190e4fbf9 [PATCH] knfsd: nf... |
356 |
|
e970a573c nfsd: open a file... |
357 |
BUG_ON(rec_file); |
190e4fbf9 [PATCH] knfsd: nf... |
358 |
|
d84f4f992 CRED: Inaugurate ... |
359 360 361 362 363 364 365 366 |
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... |
367 |
|
48483bf23 nfsd4: simplify r... |
368 |
rec_file = filp_open(user_recovery_dirname, O_RDONLY | O_DIRECTORY, 0); |
e970a573c nfsd: open a file... |
369 |
if (IS_ERR(rec_file)) { |
c2642ab05 [PATCH] nfsd4: re... |
370 371 |
printk("NFSD: unable to find recovery directory %s ", |
48483bf23 nfsd4: simplify r... |
372 |
user_recovery_dirname); |
e970a573c nfsd: open a file... |
373 374 |
rec_file = NULL; } |
190e4fbf9 [PATCH] knfsd: nf... |
375 |
|
d84f4f992 CRED: Inaugurate ... |
376 |
nfs4_reset_creds(original_cred); |
190e4fbf9 [PATCH] knfsd: nf... |
377 378 379 380 381 |
} void nfsd4_shutdown_recdir(void) { |
e970a573c nfsd: open a file... |
382 |
if (!rec_file) |
190e4fbf9 [PATCH] knfsd: nf... |
383 |
return; |
e970a573c nfsd: open a file... |
384 385 |
fput(rec_file); rec_file = NULL; |
190e4fbf9 [PATCH] knfsd: nf... |
386 |
} |
48483bf23 nfsd4: simplify r... |
387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 |
/* * 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; } |