diff options
Diffstat (limited to 'fs/nfsd/nfs4recover.c')
-rw-r--r-- | fs/nfsd/nfs4recover.c | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index 2dc9851a1d37..2805c5245eac 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c | |||
@@ -120,6 +120,70 @@ out: | |||
120 | return status; | 120 | return status; |
121 | } | 121 | } |
122 | 122 | ||
123 | static int | ||
124 | nfsd4_rec_fsync(struct dentry *dentry) | ||
125 | { | ||
126 | struct file *filp; | ||
127 | int status = nfs_ok; | ||
128 | |||
129 | dprintk("NFSD: nfs4_fsync_rec_dir\n"); | ||
130 | filp = dentry_open(dget(dentry), mntget(rec_dir.mnt), O_RDWR); | ||
131 | if (IS_ERR(filp)) { | ||
132 | status = PTR_ERR(filp); | ||
133 | goto out; | ||
134 | } | ||
135 | if (filp->f_op && filp->f_op->fsync) | ||
136 | status = filp->f_op->fsync(filp, filp->f_dentry, 0); | ||
137 | fput(filp); | ||
138 | out: | ||
139 | if (status) | ||
140 | printk("nfsd4: unable to sync recovery directory\n"); | ||
141 | return status; | ||
142 | } | ||
143 | |||
144 | int | ||
145 | nfsd4_create_clid_dir(struct nfs4_client *clp) | ||
146 | { | ||
147 | char *dname = clp->cl_recdir; | ||
148 | struct dentry *dentry; | ||
149 | uid_t uid; | ||
150 | gid_t gid; | ||
151 | int status; | ||
152 | |||
153 | dprintk("NFSD: nfsd4_create_clid_dir for \"%s\"\n", dname); | ||
154 | |||
155 | if (!rec_dir_init || clp->cl_firststate) | ||
156 | return 0; | ||
157 | |||
158 | nfs4_save_user(&uid, &gid); | ||
159 | |||
160 | /* lock the parent */ | ||
161 | down(&rec_dir.dentry->d_inode->i_sem); | ||
162 | |||
163 | dentry = lookup_one_len(dname, rec_dir.dentry, HEXDIR_LEN-1); | ||
164 | if (IS_ERR(dentry)) { | ||
165 | status = PTR_ERR(dentry); | ||
166 | goto out_unlock; | ||
167 | } | ||
168 | status = -EEXIST; | ||
169 | if (dentry->d_inode) { | ||
170 | dprintk("NFSD: nfsd4_create_clid_dir: DIRECTORY EXISTS\n"); | ||
171 | goto out_put; | ||
172 | } | ||
173 | status = vfs_mkdir(rec_dir.dentry->d_inode, dentry, S_IRWXU); | ||
174 | out_put: | ||
175 | dput(dentry); | ||
176 | out_unlock: | ||
177 | up(&rec_dir.dentry->d_inode->i_sem); | ||
178 | if (status == 0) { | ||
179 | clp->cl_firststate = 1; | ||
180 | status = nfsd4_rec_fsync(rec_dir.dentry); | ||
181 | } | ||
182 | nfs4_reset_user(uid, gid); | ||
183 | dprintk("NFSD: nfsd4_create_clid_dir returns %d\n", status); | ||
184 | return status; | ||
185 | } | ||
186 | |||
123 | typedef int (recdir_func)(struct dentry *, struct dentry *); | 187 | typedef int (recdir_func)(struct dentry *, struct dentry *); |
124 | 188 | ||
125 | struct dentry_list { | 189 | struct dentry_list { |
@@ -202,6 +266,111 @@ out: | |||
202 | } | 266 | } |
203 | 267 | ||
204 | static int | 268 | static int |
269 | nfsd4_remove_clid_file(struct dentry *dir, struct dentry *dentry) | ||
270 | { | ||
271 | int status; | ||
272 | |||
273 | if (!S_ISREG(dir->d_inode->i_mode)) { | ||
274 | printk("nfsd4: non-file found in client recovery directory\n"); | ||
275 | return -EINVAL; | ||
276 | } | ||
277 | down(&dir->d_inode->i_sem); | ||
278 | status = vfs_unlink(dir->d_inode, dentry); | ||
279 | up(&dir->d_inode->i_sem); | ||
280 | return status; | ||
281 | } | ||
282 | |||
283 | static int | ||
284 | nfsd4_clear_clid_dir(struct dentry *dir, struct dentry *dentry) | ||
285 | { | ||
286 | int status; | ||
287 | |||
288 | /* For now this directory should already be empty, but we empty it of | ||
289 | * any regular files anyway, just in case the directory was created by | ||
290 | * a kernel from the future.... */ | ||
291 | nfsd4_list_rec_dir(dentry, nfsd4_remove_clid_file); | ||
292 | down(&dir->d_inode->i_sem); | ||
293 | status = vfs_rmdir(dir->d_inode, dentry); | ||
294 | up(&dir->d_inode->i_sem); | ||
295 | return status; | ||
296 | } | ||
297 | |||
298 | static int | ||
299 | nfsd4_unlink_clid_dir(char *name, int namlen) | ||
300 | { | ||
301 | struct dentry *dentry; | ||
302 | int status; | ||
303 | |||
304 | dprintk("NFSD: nfsd4_unlink_clid_dir. name %.*s\n", namlen, name); | ||
305 | |||
306 | dentry = lookup_one_len(name, rec_dir.dentry, namlen); | ||
307 | if (IS_ERR(dentry)) { | ||
308 | status = PTR_ERR(dentry); | ||
309 | return status; | ||
310 | } | ||
311 | status = -ENOENT; | ||
312 | if (!dentry->d_inode) | ||
313 | goto out; | ||
314 | |||
315 | status = nfsd4_clear_clid_dir(rec_dir.dentry, dentry); | ||
316 | out: | ||
317 | dput(dentry); | ||
318 | return status; | ||
319 | } | ||
320 | |||
321 | void | ||
322 | nfsd4_remove_clid_dir(struct nfs4_client *clp) | ||
323 | { | ||
324 | uid_t uid; | ||
325 | gid_t gid; | ||
326 | int status; | ||
327 | |||
328 | if (!rec_dir_init || !clp->cl_firststate) | ||
329 | return; | ||
330 | |||
331 | nfs4_save_user(&uid, &gid); | ||
332 | status = nfsd4_unlink_clid_dir(clp->cl_recdir, HEXDIR_LEN-1); | ||
333 | nfs4_reset_user(uid, gid); | ||
334 | if (status == 0) | ||
335 | status = nfsd4_rec_fsync(rec_dir.dentry); | ||
336 | if (status) | ||
337 | printk("NFSD: Failed to remove expired client state directory" | ||
338 | " %.*s\n", HEXDIR_LEN, clp->cl_recdir); | ||
339 | return; | ||
340 | } | ||
341 | |||
342 | static int | ||
343 | purge_old(struct dentry *parent, struct dentry *child) | ||
344 | { | ||
345 | int status; | ||
346 | |||
347 | if (nfs4_has_reclaimed_state(child->d_name.name)) | ||
348 | return nfs_ok; | ||
349 | |||
350 | status = nfsd4_clear_clid_dir(parent, child); | ||
351 | if (status) | ||
352 | printk("failed to remove client recovery directory %s\n", | ||
353 | child->d_name.name); | ||
354 | /* Keep trying, success or failure: */ | ||
355 | return nfs_ok; | ||
356 | } | ||
357 | |||
358 | void | ||
359 | nfsd4_recdir_purge_old(void) { | ||
360 | int status; | ||
361 | |||
362 | if (!rec_dir_init) | ||
363 | return; | ||
364 | status = nfsd4_list_rec_dir(rec_dir.dentry, purge_old); | ||
365 | if (status == 0) | ||
366 | status = nfsd4_rec_fsync(rec_dir.dentry); | ||
367 | if (status) | ||
368 | printk("nfsd4: failed to purge old clients from recovery" | ||
369 | " directory %s\n", rec_dir.dentry->d_name.name); | ||
370 | return; | ||
371 | } | ||
372 | |||
373 | static int | ||
205 | load_recdir(struct dentry *parent, struct dentry *child) | 374 | load_recdir(struct dentry *parent, struct dentry *child) |
206 | { | 375 | { |
207 | if (child->d_name.len != HEXDIR_LEN - 1) { | 376 | if (child->d_name.len != HEXDIR_LEN - 1) { |