nfsd: don't search for client by hash on legacy reboot recovery gracedone
[platform/adaptation/renesas_rcar/renesas_kernel.git] / fs / nfsd / nfs4recover.c
1 /*
2 *  Copyright (c) 2004 The Regents of the University of Michigan.
3 *  Copyright (c) 2012 Jeff Layton <jlayton@redhat.com>
4 *  All rights reserved.
5 *
6 *  Andy Adamson <andros@citi.umich.edu>
7 *
8 *  Redistribution and use in source and binary forms, with or without
9 *  modification, are permitted provided that the following conditions
10 *  are met:
11 *
12 *  1. Redistributions of source code must retain the above copyright
13 *     notice, this list of conditions and the following disclaimer.
14 *  2. Redistributions in binary form must reproduce the above copyright
15 *     notice, this list of conditions and the following disclaimer in the
16 *     documentation and/or other materials provided with the distribution.
17 *  3. Neither the name of the University nor the names of its
18 *     contributors may be used to endorse or promote products derived
19 *     from this software without specific prior written permission.
20 *
21 *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
22 *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23 *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28 *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29 *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
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.
32 *
33 */
34
35 #include <linux/file.h>
36 #include <linux/slab.h>
37 #include <linux/namei.h>
38 #include <linux/crypto.h>
39 #include <linux/sched.h>
40 #include <linux/fs.h>
41 #include <linux/module.h>
42 #include <net/net_namespace.h>
43 #include <linux/sunrpc/rpc_pipe_fs.h>
44 #include <linux/sunrpc/clnt.h>
45 #include <linux/nfsd/cld.h>
46
47 #include "nfsd.h"
48 #include "state.h"
49 #include "vfs.h"
50 #include "netns.h"
51
52 #define NFSDDBG_FACILITY                NFSDDBG_PROC
53
54 /* Declarations */
55 struct nfsd4_client_tracking_ops {
56         int (*init)(struct net *);
57         void (*exit)(struct net *);
58         void (*create)(struct nfs4_client *);
59         void (*remove)(struct nfs4_client *);
60         int (*check)(struct nfs4_client *);
61         void (*grace_done)(struct net *, time_t);
62 };
63
64 /* Globals */
65 static struct file *rec_file;
66 static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery";
67 static struct nfsd4_client_tracking_ops *client_tracking_ops;
68 static bool in_grace;
69
70 static int
71 nfs4_save_creds(const struct cred **original_creds)
72 {
73         struct cred *new;
74
75         new = prepare_creds();
76         if (!new)
77                 return -ENOMEM;
78
79         new->fsuid = 0;
80         new->fsgid = 0;
81         *original_creds = override_creds(new);
82         put_cred(new);
83         return 0;
84 }
85
86 static void
87 nfs4_reset_creds(const struct cred *original)
88 {
89         revert_creds(original);
90 }
91
92 static void
93 md5_to_hex(char *out, char *md5)
94 {
95         int i;
96
97         for (i=0; i<16; i++) {
98                 unsigned char c = md5[i];
99
100                 *out++ = '0' + ((c&0xf0)>>4) + (c>=0xa0)*('a'-'9'-1);
101                 *out++ = '0' + (c&0x0f) + ((c&0x0f)>=0x0a)*('a'-'9'-1);
102         }
103         *out = '\0';
104 }
105
106 __be32
107 nfs4_make_rec_clidname(char *dname, struct xdr_netobj *clname)
108 {
109         struct xdr_netobj cksum;
110         struct hash_desc desc;
111         struct scatterlist sg;
112         __be32 status = nfserr_jukebox;
113
114         dprintk("NFSD: nfs4_make_rec_clidname for %.*s\n",
115                         clname->len, clname->data);
116         desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
117         desc.tfm = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC);
118         if (IS_ERR(desc.tfm))
119                 goto out_no_tfm;
120         cksum.len = crypto_hash_digestsize(desc.tfm);
121         cksum.data = kmalloc(cksum.len, GFP_KERNEL);
122         if (cksum.data == NULL)
123                 goto out;
124
125         sg_init_one(&sg, clname->data, clname->len);
126
127         if (crypto_hash_digest(&desc, &sg, sg.length, cksum.data))
128                 goto out;
129
130         md5_to_hex(dname, cksum.data);
131
132         status = nfs_ok;
133 out:
134         kfree(cksum.data);
135         crypto_free_hash(desc.tfm);
136 out_no_tfm:
137         return status;
138 }
139
140 static void
141 nfsd4_create_clid_dir(struct nfs4_client *clp)
142 {
143         const struct cred *original_cred;
144         char *dname = clp->cl_recdir;
145         struct dentry *dir, *dentry;
146         struct nfs4_client_reclaim *crp;
147         int status;
148
149         dprintk("NFSD: nfsd4_create_clid_dir for \"%s\"\n", dname);
150
151         if (test_and_set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
152                 return;
153         if (!rec_file)
154                 return;
155         status = nfs4_save_creds(&original_cred);
156         if (status < 0)
157                 return;
158
159         status = mnt_want_write_file(rec_file);
160         if (status)
161                 return;
162
163         dir = rec_file->f_path.dentry;
164         /* lock the parent */
165         mutex_lock(&dir->d_inode->i_mutex);
166
167         dentry = lookup_one_len(dname, dir, HEXDIR_LEN-1);
168         if (IS_ERR(dentry)) {
169                 status = PTR_ERR(dentry);
170                 goto out_unlock;
171         }
172         if (dentry->d_inode)
173                 /*
174                  * In the 4.1 case, where we're called from
175                  * reclaim_complete(), records from the previous reboot
176                  * may still be left, so this is OK.
177                  *
178                  * In the 4.0 case, we should never get here; but we may
179                  * as well be forgiving and just succeed silently.
180                  */
181                 goto out_put;
182         status = vfs_mkdir(dir->d_inode, dentry, S_IRWXU);
183 out_put:
184         dput(dentry);
185 out_unlock:
186         mutex_unlock(&dir->d_inode->i_mutex);
187         if (status == 0) {
188                 if (in_grace) {
189                         crp = nfs4_client_to_reclaim(clp->cl_recdir);
190                         if (crp)
191                                 crp->cr_clp = clp;
192                 }
193                 vfs_fsync(rec_file, 0);
194         } else {
195                 printk(KERN_ERR "NFSD: failed to write recovery record"
196                                 " (err %d); please check that %s exists"
197                                 " and is writeable", status,
198                                 user_recovery_dirname);
199         }
200         mnt_drop_write_file(rec_file);
201         nfs4_reset_creds(original_cred);
202 }
203
204 typedef int (recdir_func)(struct dentry *, struct dentry *);
205
206 struct name_list {
207         char name[HEXDIR_LEN];
208         struct list_head list;
209 };
210
211 static int
212 nfsd4_build_namelist(void *arg, const char *name, int namlen,
213                 loff_t offset, u64 ino, unsigned int d_type)
214 {
215         struct list_head *names = arg;
216         struct name_list *entry;
217
218         if (namlen != HEXDIR_LEN - 1)
219                 return 0;
220         entry = kmalloc(sizeof(struct name_list), GFP_KERNEL);
221         if (entry == NULL)
222                 return -ENOMEM;
223         memcpy(entry->name, name, HEXDIR_LEN - 1);
224         entry->name[HEXDIR_LEN - 1] = '\0';
225         list_add(&entry->list, names);
226         return 0;
227 }
228
229 static int
230 nfsd4_list_rec_dir(recdir_func *f)
231 {
232         const struct cred *original_cred;
233         struct dentry *dir = rec_file->f_path.dentry;
234         LIST_HEAD(names);
235         int status;
236
237         status = nfs4_save_creds(&original_cred);
238         if (status < 0)
239                 return status;
240
241         status = vfs_llseek(rec_file, 0, SEEK_SET);
242         if (status < 0) {
243                 nfs4_reset_creds(original_cred);
244                 return status;
245         }
246
247         status = vfs_readdir(rec_file, nfsd4_build_namelist, &names);
248         mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT);
249         while (!list_empty(&names)) {
250                 struct name_list *entry;
251                 entry = list_entry(names.next, struct name_list, list);
252                 if (!status) {
253                         struct dentry *dentry;
254                         dentry = lookup_one_len(entry->name, dir, HEXDIR_LEN-1);
255                         if (IS_ERR(dentry)) {
256                                 status = PTR_ERR(dentry);
257                                 break;
258                         }
259                         status = f(dir, dentry);
260                         dput(dentry);
261                 }
262                 list_del(&entry->list);
263                 kfree(entry);
264         }
265         mutex_unlock(&dir->d_inode->i_mutex);
266         nfs4_reset_creds(original_cred);
267         return status;
268 }
269
270 static int
271 nfsd4_unlink_clid_dir(char *name, int namlen)
272 {
273         struct dentry *dir, *dentry;
274         int status;
275
276         dprintk("NFSD: nfsd4_unlink_clid_dir. name %.*s\n", namlen, name);
277
278         dir = rec_file->f_path.dentry;
279         mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT);
280         dentry = lookup_one_len(name, dir, namlen);
281         if (IS_ERR(dentry)) {
282                 status = PTR_ERR(dentry);
283                 goto out_unlock;
284         }
285         status = -ENOENT;
286         if (!dentry->d_inode)
287                 goto out;
288         status = vfs_rmdir(dir->d_inode, dentry);
289 out:
290         dput(dentry);
291 out_unlock:
292         mutex_unlock(&dir->d_inode->i_mutex);
293         return status;
294 }
295
296 static void
297 nfsd4_remove_clid_dir(struct nfs4_client *clp)
298 {
299         const struct cred *original_cred;
300         struct nfs4_client_reclaim *crp;
301         int status;
302
303         if (!rec_file || !test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
304                 return;
305
306         status = mnt_want_write_file(rec_file);
307         if (status)
308                 goto out;
309         clear_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
310
311         status = nfs4_save_creds(&original_cred);
312         if (status < 0)
313                 goto out_drop_write;
314
315         status = nfsd4_unlink_clid_dir(clp->cl_recdir, HEXDIR_LEN-1);
316         nfs4_reset_creds(original_cred);
317         if (status == 0) {
318                 vfs_fsync(rec_file, 0);
319                 if (in_grace) {
320                         /* remove reclaim record */
321                         crp = nfsd4_find_reclaim_client(clp->cl_recdir);
322                         if (crp)
323                                 nfs4_remove_reclaim_record(crp);
324                 }
325         }
326 out_drop_write:
327         mnt_drop_write_file(rec_file);
328 out:
329         if (status)
330                 printk("NFSD: Failed to remove expired client state directory"
331                                 " %.*s\n", HEXDIR_LEN, clp->cl_recdir);
332 }
333
334 static int
335 purge_old(struct dentry *parent, struct dentry *child)
336 {
337         int status;
338
339         if (nfs4_has_reclaimed_state(child->d_name.name))
340                 return 0;
341
342         status = vfs_rmdir(parent->d_inode, child);
343         if (status)
344                 printk("failed to remove client recovery directory %s\n",
345                                 child->d_name.name);
346         /* Keep trying, success or failure: */
347         return 0;
348 }
349
350 static void
351 nfsd4_recdir_purge_old(struct net *net, time_t boot_time)
352 {
353         int status;
354
355         in_grace = false;
356         if (!rec_file)
357                 return;
358         status = mnt_want_write_file(rec_file);
359         if (status)
360                 goto out;
361         status = nfsd4_list_rec_dir(purge_old);
362         if (status == 0)
363                 vfs_fsync(rec_file, 0);
364         mnt_drop_write_file(rec_file);
365 out:
366         if (status)
367                 printk("nfsd4: failed to purge old clients from recovery"
368                         " directory %s\n", rec_file->f_path.dentry->d_name.name);
369 }
370
371 static int
372 load_recdir(struct dentry *parent, struct dentry *child)
373 {
374         if (child->d_name.len != HEXDIR_LEN - 1) {
375                 printk("nfsd4: illegal name %s in recovery directory\n",
376                                 child->d_name.name);
377                 /* Keep trying; maybe the others are OK: */
378                 return 0;
379         }
380         nfs4_client_to_reclaim(child->d_name.name);
381         return 0;
382 }
383
384 static int
385 nfsd4_recdir_load(void) {
386         int status;
387
388         if (!rec_file)
389                 return 0;
390
391         status = nfsd4_list_rec_dir(load_recdir);
392         if (status)
393                 printk("nfsd4: failed loading clients from recovery"
394                         " directory %s\n", rec_file->f_path.dentry->d_name.name);
395         return status;
396 }
397
398 /*
399  * Hold reference to the recovery directory.
400  */
401
402 static int
403 nfsd4_init_recdir(void)
404 {
405         const struct cred *original_cred;
406         int status;
407
408         printk("NFSD: Using %s as the NFSv4 state recovery directory\n",
409                         user_recovery_dirname);
410
411         BUG_ON(rec_file);
412
413         status = nfs4_save_creds(&original_cred);
414         if (status < 0) {
415                 printk("NFSD: Unable to change credentials to find recovery"
416                        " directory: error %d\n",
417                        status);
418                 return status;
419         }
420
421         rec_file = filp_open(user_recovery_dirname, O_RDONLY | O_DIRECTORY, 0);
422         if (IS_ERR(rec_file)) {
423                 printk("NFSD: unable to find recovery directory %s\n",
424                                 user_recovery_dirname);
425                 status = PTR_ERR(rec_file);
426                 rec_file = NULL;
427         }
428
429         nfs4_reset_creds(original_cred);
430         if (!status)
431                 in_grace = true;
432         return status;
433 }
434
435 static int
436 nfsd4_load_reboot_recovery_data(struct net *net)
437 {
438         int status;
439
440         /* XXX: The legacy code won't work in a container */
441         if (net != &init_net) {
442                 WARN(1, KERN_ERR "NFSD: attempt to initialize legacy client "
443                         "tracking in a container!\n");
444                 return -EINVAL;
445         }
446
447         nfs4_lock_state();
448         status = nfsd4_init_recdir();
449         if (!status)
450                 status = nfsd4_recdir_load();
451         nfs4_unlock_state();
452         if (status)
453                 printk(KERN_ERR "NFSD: Failure reading reboot recovery data\n");
454         return status;
455 }
456
457 static void
458 nfsd4_shutdown_recdir(void)
459 {
460         if (!rec_file)
461                 return;
462         fput(rec_file);
463         rec_file = NULL;
464 }
465
466 static void
467 nfsd4_legacy_tracking_exit(struct net *net)
468 {
469         nfs4_release_reclaim();
470         nfsd4_shutdown_recdir();
471 }
472
473 /*
474  * Change the NFSv4 recovery directory to recdir.
475  */
476 int
477 nfs4_reset_recoverydir(char *recdir)
478 {
479         int status;
480         struct path path;
481
482         status = kern_path(recdir, LOOKUP_FOLLOW, &path);
483         if (status)
484                 return status;
485         status = -ENOTDIR;
486         if (S_ISDIR(path.dentry->d_inode->i_mode)) {
487                 strcpy(user_recovery_dirname, recdir);
488                 status = 0;
489         }
490         path_put(&path);
491         return status;
492 }
493
494 char *
495 nfs4_recoverydir(void)
496 {
497         return user_recovery_dirname;
498 }
499
500 static int
501 nfsd4_check_legacy_client(struct nfs4_client *clp)
502 {
503         struct nfs4_client_reclaim *crp;
504
505         /* did we already find that this client is stable? */
506         if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
507                 return 0;
508
509         /* look for it in the reclaim hashtable otherwise */
510         crp = nfsd4_find_reclaim_client(clp->cl_recdir);
511         if (crp) {
512                 set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
513                 crp->cr_clp = clp;
514                 return 0;
515         }
516
517         return -ENOENT;
518 }
519
520 static struct nfsd4_client_tracking_ops nfsd4_legacy_tracking_ops = {
521         .init           = nfsd4_load_reboot_recovery_data,
522         .exit           = nfsd4_legacy_tracking_exit,
523         .create         = nfsd4_create_clid_dir,
524         .remove         = nfsd4_remove_clid_dir,
525         .check          = nfsd4_check_legacy_client,
526         .grace_done     = nfsd4_recdir_purge_old,
527 };
528
529 /* Globals */
530 #define NFSD_PIPE_DIR           "nfsd"
531 #define NFSD_CLD_PIPE           "cld"
532
533 /* per-net-ns structure for holding cld upcall info */
534 struct cld_net {
535         struct rpc_pipe         *cn_pipe;
536         spinlock_t               cn_lock;
537         struct list_head         cn_list;
538         unsigned int             cn_xid;
539 };
540
541 struct cld_upcall {
542         struct list_head         cu_list;
543         struct cld_net          *cu_net;
544         struct task_struct      *cu_task;
545         struct cld_msg           cu_msg;
546 };
547
548 static int
549 __cld_pipe_upcall(struct rpc_pipe *pipe, struct cld_msg *cmsg)
550 {
551         int ret;
552         struct rpc_pipe_msg msg;
553
554         memset(&msg, 0, sizeof(msg));
555         msg.data = cmsg;
556         msg.len = sizeof(*cmsg);
557
558         /*
559          * Set task state before we queue the upcall. That prevents
560          * wake_up_process in the downcall from racing with schedule.
561          */
562         set_current_state(TASK_UNINTERRUPTIBLE);
563         ret = rpc_queue_upcall(pipe, &msg);
564         if (ret < 0) {
565                 set_current_state(TASK_RUNNING);
566                 goto out;
567         }
568
569         schedule();
570         set_current_state(TASK_RUNNING);
571
572         if (msg.errno < 0)
573                 ret = msg.errno;
574 out:
575         return ret;
576 }
577
578 static int
579 cld_pipe_upcall(struct rpc_pipe *pipe, struct cld_msg *cmsg)
580 {
581         int ret;
582
583         /*
584          * -EAGAIN occurs when pipe is closed and reopened while there are
585          *  upcalls queued.
586          */
587         do {
588                 ret = __cld_pipe_upcall(pipe, cmsg);
589         } while (ret == -EAGAIN);
590
591         return ret;
592 }
593
594 static ssize_t
595 cld_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
596 {
597         struct cld_upcall *tmp, *cup;
598         struct cld_msg __user *cmsg = (struct cld_msg __user *)src;
599         uint32_t xid;
600         struct nfsd_net *nn = net_generic(filp->f_dentry->d_sb->s_fs_info,
601                                                 nfsd_net_id);
602         struct cld_net *cn = nn->cld_net;
603
604         if (mlen != sizeof(*cmsg)) {
605                 dprintk("%s: got %zu bytes, expected %zu\n", __func__, mlen,
606                         sizeof(*cmsg));
607                 return -EINVAL;
608         }
609
610         /* copy just the xid so we can try to find that */
611         if (copy_from_user(&xid, &cmsg->cm_xid, sizeof(xid)) != 0) {
612                 dprintk("%s: error when copying xid from userspace", __func__);
613                 return -EFAULT;
614         }
615
616         /* walk the list and find corresponding xid */
617         cup = NULL;
618         spin_lock(&cn->cn_lock);
619         list_for_each_entry(tmp, &cn->cn_list, cu_list) {
620                 if (get_unaligned(&tmp->cu_msg.cm_xid) == xid) {
621                         cup = tmp;
622                         list_del_init(&cup->cu_list);
623                         break;
624                 }
625         }
626         spin_unlock(&cn->cn_lock);
627
628         /* couldn't find upcall? */
629         if (!cup) {
630                 dprintk("%s: couldn't find upcall -- xid=%u\n", __func__, xid);
631                 return -EINVAL;
632         }
633
634         if (copy_from_user(&cup->cu_msg, src, mlen) != 0)
635                 return -EFAULT;
636
637         wake_up_process(cup->cu_task);
638         return mlen;
639 }
640
641 static void
642 cld_pipe_destroy_msg(struct rpc_pipe_msg *msg)
643 {
644         struct cld_msg *cmsg = msg->data;
645         struct cld_upcall *cup = container_of(cmsg, struct cld_upcall,
646                                                  cu_msg);
647
648         /* errno >= 0 means we got a downcall */
649         if (msg->errno >= 0)
650                 return;
651
652         wake_up_process(cup->cu_task);
653 }
654
655 static const struct rpc_pipe_ops cld_upcall_ops = {
656         .upcall         = rpc_pipe_generic_upcall,
657         .downcall       = cld_pipe_downcall,
658         .destroy_msg    = cld_pipe_destroy_msg,
659 };
660
661 static struct dentry *
662 nfsd4_cld_register_sb(struct super_block *sb, struct rpc_pipe *pipe)
663 {
664         struct dentry *dir, *dentry;
665
666         dir = rpc_d_lookup_sb(sb, NFSD_PIPE_DIR);
667         if (dir == NULL)
668                 return ERR_PTR(-ENOENT);
669         dentry = rpc_mkpipe_dentry(dir, NFSD_CLD_PIPE, NULL, pipe);
670         dput(dir);
671         return dentry;
672 }
673
674 static void
675 nfsd4_cld_unregister_sb(struct rpc_pipe *pipe)
676 {
677         if (pipe->dentry)
678                 rpc_unlink(pipe->dentry);
679 }
680
681 static struct dentry *
682 nfsd4_cld_register_net(struct net *net, struct rpc_pipe *pipe)
683 {
684         struct super_block *sb;
685         struct dentry *dentry;
686
687         sb = rpc_get_sb_net(net);
688         if (!sb)
689                 return NULL;
690         dentry = nfsd4_cld_register_sb(sb, pipe);
691         rpc_put_sb_net(net);
692         return dentry;
693 }
694
695 static void
696 nfsd4_cld_unregister_net(struct net *net, struct rpc_pipe *pipe)
697 {
698         struct super_block *sb;
699
700         sb = rpc_get_sb_net(net);
701         if (sb) {
702                 nfsd4_cld_unregister_sb(pipe);
703                 rpc_put_sb_net(net);
704         }
705 }
706
707 /* Initialize rpc_pipefs pipe for communication with client tracking daemon */
708 static int
709 nfsd4_init_cld_pipe(struct net *net)
710 {
711         int ret;
712         struct dentry *dentry;
713         struct nfsd_net *nn = net_generic(net, nfsd_net_id);
714         struct cld_net *cn;
715
716         if (nn->cld_net)
717                 return 0;
718
719         cn = kzalloc(sizeof(*cn), GFP_KERNEL);
720         if (!cn) {
721                 ret = -ENOMEM;
722                 goto err;
723         }
724
725         cn->cn_pipe = rpc_mkpipe_data(&cld_upcall_ops, RPC_PIPE_WAIT_FOR_OPEN);
726         if (IS_ERR(cn->cn_pipe)) {
727                 ret = PTR_ERR(cn->cn_pipe);
728                 goto err;
729         }
730         spin_lock_init(&cn->cn_lock);
731         INIT_LIST_HEAD(&cn->cn_list);
732
733         dentry = nfsd4_cld_register_net(net, cn->cn_pipe);
734         if (IS_ERR(dentry)) {
735                 ret = PTR_ERR(dentry);
736                 goto err_destroy_data;
737         }
738
739         cn->cn_pipe->dentry = dentry;
740         nn->cld_net = cn;
741         return 0;
742
743 err_destroy_data:
744         rpc_destroy_pipe_data(cn->cn_pipe);
745 err:
746         kfree(cn);
747         printk(KERN_ERR "NFSD: unable to create nfsdcld upcall pipe (%d)\n",
748                         ret);
749         return ret;
750 }
751
752 static void
753 nfsd4_remove_cld_pipe(struct net *net)
754 {
755         struct nfsd_net *nn = net_generic(net, nfsd_net_id);
756         struct cld_net *cn = nn->cld_net;
757
758         nfsd4_cld_unregister_net(net, cn->cn_pipe);
759         rpc_destroy_pipe_data(cn->cn_pipe);
760         kfree(nn->cld_net);
761         nn->cld_net = NULL;
762 }
763
764 static struct cld_upcall *
765 alloc_cld_upcall(struct cld_net *cn)
766 {
767         struct cld_upcall *new, *tmp;
768
769         new = kzalloc(sizeof(*new), GFP_KERNEL);
770         if (!new)
771                 return new;
772
773         /* FIXME: hard cap on number in flight? */
774 restart_search:
775         spin_lock(&cn->cn_lock);
776         list_for_each_entry(tmp, &cn->cn_list, cu_list) {
777                 if (tmp->cu_msg.cm_xid == cn->cn_xid) {
778                         cn->cn_xid++;
779                         spin_unlock(&cn->cn_lock);
780                         goto restart_search;
781                 }
782         }
783         new->cu_task = current;
784         new->cu_msg.cm_vers = CLD_UPCALL_VERSION;
785         put_unaligned(cn->cn_xid++, &new->cu_msg.cm_xid);
786         new->cu_net = cn;
787         list_add(&new->cu_list, &cn->cn_list);
788         spin_unlock(&cn->cn_lock);
789
790         dprintk("%s: allocated xid %u\n", __func__, new->cu_msg.cm_xid);
791
792         return new;
793 }
794
795 static void
796 free_cld_upcall(struct cld_upcall *victim)
797 {
798         struct cld_net *cn = victim->cu_net;
799
800         spin_lock(&cn->cn_lock);
801         list_del(&victim->cu_list);
802         spin_unlock(&cn->cn_lock);
803         kfree(victim);
804 }
805
806 /* Ask daemon to create a new record */
807 static void
808 nfsd4_cld_create(struct nfs4_client *clp)
809 {
810         int ret;
811         struct cld_upcall *cup;
812         /* FIXME: determine net from clp */
813         struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id);
814         struct cld_net *cn = nn->cld_net;
815
816         /* Don't upcall if it's already stored */
817         if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
818                 return;
819
820         cup = alloc_cld_upcall(cn);
821         if (!cup) {
822                 ret = -ENOMEM;
823                 goto out_err;
824         }
825
826         cup->cu_msg.cm_cmd = Cld_Create;
827         cup->cu_msg.cm_u.cm_name.cn_len = clp->cl_name.len;
828         memcpy(cup->cu_msg.cm_u.cm_name.cn_id, clp->cl_name.data,
829                         clp->cl_name.len);
830
831         ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg);
832         if (!ret) {
833                 ret = cup->cu_msg.cm_status;
834                 set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
835         }
836
837         free_cld_upcall(cup);
838 out_err:
839         if (ret)
840                 printk(KERN_ERR "NFSD: Unable to create client "
841                                 "record on stable storage: %d\n", ret);
842 }
843
844 /* Ask daemon to create a new record */
845 static void
846 nfsd4_cld_remove(struct nfs4_client *clp)
847 {
848         int ret;
849         struct cld_upcall *cup;
850         /* FIXME: determine net from clp */
851         struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id);
852         struct cld_net *cn = nn->cld_net;
853
854         /* Don't upcall if it's already removed */
855         if (!test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
856                 return;
857
858         cup = alloc_cld_upcall(cn);
859         if (!cup) {
860                 ret = -ENOMEM;
861                 goto out_err;
862         }
863
864         cup->cu_msg.cm_cmd = Cld_Remove;
865         cup->cu_msg.cm_u.cm_name.cn_len = clp->cl_name.len;
866         memcpy(cup->cu_msg.cm_u.cm_name.cn_id, clp->cl_name.data,
867                         clp->cl_name.len);
868
869         ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg);
870         if (!ret) {
871                 ret = cup->cu_msg.cm_status;
872                 clear_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
873         }
874
875         free_cld_upcall(cup);
876 out_err:
877         if (ret)
878                 printk(KERN_ERR "NFSD: Unable to remove client "
879                                 "record from stable storage: %d\n", ret);
880 }
881
882 /* Check for presence of a record, and update its timestamp */
883 static int
884 nfsd4_cld_check(struct nfs4_client *clp)
885 {
886         int ret;
887         struct cld_upcall *cup;
888         /* FIXME: determine net from clp */
889         struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id);
890         struct cld_net *cn = nn->cld_net;
891
892         /* Don't upcall if one was already stored during this grace pd */
893         if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
894                 return 0;
895
896         cup = alloc_cld_upcall(cn);
897         if (!cup) {
898                 printk(KERN_ERR "NFSD: Unable to check client record on "
899                                 "stable storage: %d\n", -ENOMEM);
900                 return -ENOMEM;
901         }
902
903         cup->cu_msg.cm_cmd = Cld_Check;
904         cup->cu_msg.cm_u.cm_name.cn_len = clp->cl_name.len;
905         memcpy(cup->cu_msg.cm_u.cm_name.cn_id, clp->cl_name.data,
906                         clp->cl_name.len);
907
908         ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg);
909         if (!ret) {
910                 ret = cup->cu_msg.cm_status;
911                 set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
912         }
913
914         free_cld_upcall(cup);
915         return ret;
916 }
917
918 static void
919 nfsd4_cld_grace_done(struct net *net, time_t boot_time)
920 {
921         int ret;
922         struct cld_upcall *cup;
923         struct nfsd_net *nn = net_generic(net, nfsd_net_id);
924         struct cld_net *cn = nn->cld_net;
925
926         cup = alloc_cld_upcall(cn);
927         if (!cup) {
928                 ret = -ENOMEM;
929                 goto out_err;
930         }
931
932         cup->cu_msg.cm_cmd = Cld_GraceDone;
933         cup->cu_msg.cm_u.cm_gracetime = (int64_t)boot_time;
934         ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg);
935         if (!ret)
936                 ret = cup->cu_msg.cm_status;
937
938         free_cld_upcall(cup);
939 out_err:
940         if (ret)
941                 printk(KERN_ERR "NFSD: Unable to end grace period: %d\n", ret);
942 }
943
944 static struct nfsd4_client_tracking_ops nfsd4_cld_tracking_ops = {
945         .init           = nfsd4_init_cld_pipe,
946         .exit           = nfsd4_remove_cld_pipe,
947         .create         = nfsd4_cld_create,
948         .remove         = nfsd4_cld_remove,
949         .check          = nfsd4_cld_check,
950         .grace_done     = nfsd4_cld_grace_done,
951 };
952
953 /* upcall via usermodehelper */
954 static char cltrack_prog[PATH_MAX] = "/sbin/nfsdcltrack";
955 module_param_string(cltrack_prog, cltrack_prog, sizeof(cltrack_prog),
956                         S_IRUGO|S_IWUSR);
957 MODULE_PARM_DESC(cltrack_prog, "Path to the nfsdcltrack upcall program");
958
959 static bool cltrack_legacy_disable;
960 module_param(cltrack_legacy_disable, bool, S_IRUGO|S_IWUSR);
961 MODULE_PARM_DESC(cltrack_legacy_disable,
962                 "Disable legacy recoverydir conversion. Default: false");
963
964 #define LEGACY_TOPDIR_ENV_PREFIX "NFSDCLTRACK_LEGACY_TOPDIR="
965 #define LEGACY_RECDIR_ENV_PREFIX "NFSDCLTRACK_LEGACY_RECDIR="
966
967 static char *
968 nfsd4_cltrack_legacy_topdir(void)
969 {
970         int copied;
971         size_t len;
972         char *result;
973
974         if (cltrack_legacy_disable)
975                 return NULL;
976
977         len = strlen(LEGACY_TOPDIR_ENV_PREFIX) +
978                 strlen(nfs4_recoverydir()) + 1;
979
980         result = kmalloc(len, GFP_KERNEL);
981         if (!result)
982                 return result;
983
984         copied = snprintf(result, len, LEGACY_TOPDIR_ENV_PREFIX "%s",
985                                 nfs4_recoverydir());
986         if (copied >= len) {
987                 /* just return nothing if output was truncated */
988                 kfree(result);
989                 return NULL;
990         }
991
992         return result;
993 }
994
995 static char *
996 nfsd4_cltrack_legacy_recdir(const char *recdir)
997 {
998         int copied;
999         size_t len;
1000         char *result;
1001
1002         if (cltrack_legacy_disable)
1003                 return NULL;
1004
1005         /* +1 is for '/' between "topdir" and "recdir" */
1006         len = strlen(LEGACY_RECDIR_ENV_PREFIX) +
1007                 strlen(nfs4_recoverydir()) + 1 + HEXDIR_LEN;
1008
1009         result = kmalloc(len, GFP_KERNEL);
1010         if (!result)
1011                 return result;
1012
1013         copied = snprintf(result, len, LEGACY_RECDIR_ENV_PREFIX "%s/%s",
1014                                 nfs4_recoverydir(), recdir);
1015         if (copied >= len) {
1016                 /* just return nothing if output was truncated */
1017                 kfree(result);
1018                 return NULL;
1019         }
1020
1021         return result;
1022 }
1023
1024 static int
1025 nfsd4_umh_cltrack_upcall(char *cmd, char *arg, char *legacy)
1026 {
1027         char *envp[2];
1028         char *argv[4];
1029         int ret;
1030
1031         if (unlikely(!cltrack_prog[0])) {
1032                 dprintk("%s: cltrack_prog is disabled\n", __func__);
1033                 return -EACCES;
1034         }
1035
1036         dprintk("%s: cmd: %s\n", __func__, cmd);
1037         dprintk("%s: arg: %s\n", __func__, arg ? arg : "(null)");
1038         dprintk("%s: legacy: %s\n", __func__, legacy ? legacy : "(null)");
1039
1040         envp[0] = legacy;
1041         envp[1] = NULL;
1042
1043         argv[0] = (char *)cltrack_prog;
1044         argv[1] = cmd;
1045         argv[2] = arg;
1046         argv[3] = NULL;
1047
1048         ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
1049         /*
1050          * Disable the upcall mechanism if we're getting an ENOENT or EACCES
1051          * error. The admin can re-enable it on the fly by using sysfs
1052          * once the problem has been fixed.
1053          */
1054         if (ret == -ENOENT || ret == -EACCES) {
1055                 dprintk("NFSD: %s was not found or isn't executable (%d). "
1056                         "Setting cltrack_prog to blank string!",
1057                         cltrack_prog, ret);
1058                 cltrack_prog[0] = '\0';
1059         }
1060         dprintk("%s: %s return value: %d\n", __func__, cltrack_prog, ret);
1061
1062         return ret;
1063 }
1064
1065 static char *
1066 bin_to_hex_dup(const unsigned char *src, int srclen)
1067 {
1068         int i;
1069         char *buf, *hex;
1070
1071         /* +1 for terminating NULL */
1072         buf = kmalloc((srclen * 2) + 1, GFP_KERNEL);
1073         if (!buf)
1074                 return buf;
1075
1076         hex = buf;
1077         for (i = 0; i < srclen; i++) {
1078                 sprintf(hex, "%2.2x", *src++);
1079                 hex += 2;
1080         }
1081         return buf;
1082 }
1083
1084 static int
1085 nfsd4_umh_cltrack_init(struct net __attribute__((unused)) *net)
1086 {
1087         return nfsd4_umh_cltrack_upcall("init", NULL, NULL);
1088 }
1089
1090 static void
1091 nfsd4_umh_cltrack_create(struct nfs4_client *clp)
1092 {
1093         char *hexid;
1094
1095         hexid = bin_to_hex_dup(clp->cl_name.data, clp->cl_name.len);
1096         if (!hexid) {
1097                 dprintk("%s: can't allocate memory for upcall!\n", __func__);
1098                 return;
1099         }
1100         nfsd4_umh_cltrack_upcall("create", hexid, NULL);
1101         kfree(hexid);
1102 }
1103
1104 static void
1105 nfsd4_umh_cltrack_remove(struct nfs4_client *clp)
1106 {
1107         char *hexid;
1108
1109         hexid = bin_to_hex_dup(clp->cl_name.data, clp->cl_name.len);
1110         if (!hexid) {
1111                 dprintk("%s: can't allocate memory for upcall!\n", __func__);
1112                 return;
1113         }
1114         nfsd4_umh_cltrack_upcall("remove", hexid, NULL);
1115         kfree(hexid);
1116 }
1117
1118 static int
1119 nfsd4_umh_cltrack_check(struct nfs4_client *clp)
1120 {
1121         int ret;
1122         char *hexid, *legacy;
1123
1124         hexid = bin_to_hex_dup(clp->cl_name.data, clp->cl_name.len);
1125         if (!hexid) {
1126                 dprintk("%s: can't allocate memory for upcall!\n", __func__);
1127                 return -ENOMEM;
1128         }
1129         legacy = nfsd4_cltrack_legacy_recdir(clp->cl_recdir);
1130         ret = nfsd4_umh_cltrack_upcall("check", hexid, legacy);
1131         kfree(legacy);
1132         kfree(hexid);
1133         return ret;
1134 }
1135
1136 static void
1137 nfsd4_umh_cltrack_grace_done(struct net __attribute__((unused)) *net,
1138                                 time_t boot_time)
1139 {
1140         char *legacy;
1141         char timestr[22]; /* FIXME: better way to determine max size? */
1142
1143         sprintf(timestr, "%ld", boot_time);
1144         legacy = nfsd4_cltrack_legacy_topdir();
1145         nfsd4_umh_cltrack_upcall("gracedone", timestr, legacy);
1146         kfree(legacy);
1147 }
1148
1149 static struct nfsd4_client_tracking_ops nfsd4_umh_tracking_ops = {
1150         .init           = nfsd4_umh_cltrack_init,
1151         .exit           = NULL,
1152         .create         = nfsd4_umh_cltrack_create,
1153         .remove         = nfsd4_umh_cltrack_remove,
1154         .check          = nfsd4_umh_cltrack_check,
1155         .grace_done     = nfsd4_umh_cltrack_grace_done,
1156 };
1157
1158 int
1159 nfsd4_client_tracking_init(struct net *net)
1160 {
1161         int status;
1162         struct path path;
1163
1164         /* just run the init if it the method is already decided */
1165         if (client_tracking_ops)
1166                 goto do_init;
1167
1168         /*
1169          * First, try a UMH upcall. It should succeed or fail quickly, so
1170          * there's little harm in trying that first.
1171          */
1172         client_tracking_ops = &nfsd4_umh_tracking_ops;
1173         status = client_tracking_ops->init(net);
1174         if (!status)
1175                 return status;
1176
1177         /*
1178          * See if the recoverydir exists and is a directory. If it is,
1179          * then use the legacy ops.
1180          */
1181         client_tracking_ops = &nfsd4_legacy_tracking_ops;
1182         status = kern_path(nfs4_recoverydir(), LOOKUP_FOLLOW, &path);
1183         if (!status) {
1184                 status = S_ISDIR(path.dentry->d_inode->i_mode);
1185                 path_put(&path);
1186                 if (status)
1187                         goto do_init;
1188         }
1189
1190         /* Finally, try to use nfsdcld */
1191         client_tracking_ops = &nfsd4_cld_tracking_ops;
1192         printk(KERN_WARNING "NFSD: the nfsdcld client tracking upcall will be "
1193                         "removed in 3.10. Please transition to using "
1194                         "nfsdcltrack.\n");
1195 do_init:
1196         status = client_tracking_ops->init(net);
1197         if (status) {
1198                 printk(KERN_WARNING "NFSD: Unable to initialize client "
1199                                     "recovery tracking! (%d)\n", status);
1200                 client_tracking_ops = NULL;
1201         }
1202         return status;
1203 }
1204
1205 void
1206 nfsd4_client_tracking_exit(struct net *net)
1207 {
1208         if (client_tracking_ops) {
1209                 if (client_tracking_ops->exit)
1210                         client_tracking_ops->exit(net);
1211                 client_tracking_ops = NULL;
1212         }
1213 }
1214
1215 void
1216 nfsd4_client_record_create(struct nfs4_client *clp)
1217 {
1218         if (client_tracking_ops)
1219                 client_tracking_ops->create(clp);
1220 }
1221
1222 void
1223 nfsd4_client_record_remove(struct nfs4_client *clp)
1224 {
1225         if (client_tracking_ops)
1226                 client_tracking_ops->remove(clp);
1227 }
1228
1229 int
1230 nfsd4_client_record_check(struct nfs4_client *clp)
1231 {
1232         if (client_tracking_ops)
1233                 return client_tracking_ops->check(clp);
1234
1235         return -EOPNOTSUPP;
1236 }
1237
1238 void
1239 nfsd4_record_grace_done(struct net *net, time_t boot_time)
1240 {
1241         if (client_tracking_ops)
1242                 client_tracking_ops->grace_done(net, boot_time);
1243 }
1244
1245 static int
1246 rpc_pipefs_event(struct notifier_block *nb, unsigned long event, void *ptr)
1247 {
1248         struct super_block *sb = ptr;
1249         struct net *net = sb->s_fs_info;
1250         struct nfsd_net *nn = net_generic(net, nfsd_net_id);
1251         struct cld_net *cn = nn->cld_net;
1252         struct dentry *dentry;
1253         int ret = 0;
1254
1255         if (!try_module_get(THIS_MODULE))
1256                 return 0;
1257
1258         if (!cn) {
1259                 module_put(THIS_MODULE);
1260                 return 0;
1261         }
1262
1263         switch (event) {
1264         case RPC_PIPEFS_MOUNT:
1265                 dentry = nfsd4_cld_register_sb(sb, cn->cn_pipe);
1266                 if (IS_ERR(dentry)) {
1267                         ret = PTR_ERR(dentry);
1268                         break;
1269                 }
1270                 cn->cn_pipe->dentry = dentry;
1271                 break;
1272         case RPC_PIPEFS_UMOUNT:
1273                 if (cn->cn_pipe->dentry)
1274                         nfsd4_cld_unregister_sb(cn->cn_pipe);
1275                 break;
1276         default:
1277                 ret = -ENOTSUPP;
1278                 break;
1279         }
1280         module_put(THIS_MODULE);
1281         return ret;
1282 }
1283
1284 static struct notifier_block nfsd4_cld_block = {
1285         .notifier_call = rpc_pipefs_event,
1286 };
1287
1288 int
1289 register_cld_notifier(void)
1290 {
1291         return rpc_pipefs_notifier_register(&nfsd4_cld_block);
1292 }
1293
1294 void
1295 unregister_cld_notifier(void)
1296 {
1297         rpc_pipefs_notifier_unregister(&nfsd4_cld_block);
1298 }