~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/nfsd/nfs4recover.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 <crypto/hash.h>
 36 #include <linux/file.h>
 37 #include <linux/slab.h>
 38 #include <linux/namei.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 nfsd_net *);
 62         uint8_t version;
 63         size_t msglen;
 64 };
 65 
 66 static const struct nfsd4_client_tracking_ops nfsd4_cld_tracking_ops;
 67 static const struct nfsd4_client_tracking_ops nfsd4_cld_tracking_ops_v2;
 68 
 69 #ifdef CONFIG_NFSD_LEGACY_CLIENT_TRACKING
 70 /* Globals */
 71 static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery";
 72 
 73 static int
 74 nfs4_save_creds(const struct cred **original_creds)
 75 {
 76         struct cred *new;
 77 
 78         new = prepare_creds();
 79         if (!new)
 80                 return -ENOMEM;
 81 
 82         new->fsuid = GLOBAL_ROOT_UID;
 83         new->fsgid = GLOBAL_ROOT_GID;
 84         *original_creds = override_creds(new);
 85         put_cred(new);
 86         return 0;
 87 }
 88 
 89 static void
 90 nfs4_reset_creds(const struct cred *original)
 91 {
 92         revert_creds(original);
 93 }
 94 
 95 static void
 96 md5_to_hex(char *out, char *md5)
 97 {
 98         int i;
 99 
100         for (i=0; i<16; i++) {
101                 unsigned char c = md5[i];
102 
103                 *out++ = '' + ((c&0xf0)>>4) + (c>=0xa0)*('a'-'9'-1);
104                 *out++ = '' + (c&0x0f) + ((c&0x0f)>=0x0a)*('a'-'9'-1);
105         }
106         *out = '\0';
107 }
108 
109 static int
110 nfs4_make_rec_clidname(char *dname, const struct xdr_netobj *clname)
111 {
112         struct xdr_netobj cksum;
113         struct crypto_shash *tfm;
114         int status;
115 
116         dprintk("NFSD: nfs4_make_rec_clidname for %.*s\n",
117                         clname->len, clname->data);
118         tfm = crypto_alloc_shash("md5", 0, 0);
119         if (IS_ERR(tfm)) {
120                 status = PTR_ERR(tfm);
121                 goto out_no_tfm;
122         }
123 
124         cksum.len = crypto_shash_digestsize(tfm);
125         cksum.data = kmalloc(cksum.len, GFP_KERNEL);
126         if (cksum.data == NULL) {
127                 status = -ENOMEM;
128                 goto out;
129         }
130 
131         status = crypto_shash_tfm_digest(tfm, clname->data, clname->len,
132                                          cksum.data);
133         if (status)
134                 goto out;
135 
136         md5_to_hex(dname, cksum.data);
137 
138         status = 0;
139 out:
140         kfree(cksum.data);
141         crypto_free_shash(tfm);
142 out_no_tfm:
143         return status;
144 }
145 
146 /*
147  * If we had an error generating the recdir name for the legacy tracker
148  * then warn the admin. If the error doesn't appear to be transient,
149  * then disable recovery tracking.
150  */
151 static void
152 legacy_recdir_name_error(struct nfs4_client *clp, int error)
153 {
154         printk(KERN_ERR "NFSD: unable to generate recoverydir "
155                         "name (%d).\n", error);
156 
157         /*
158          * if the algorithm just doesn't exist, then disable the recovery
159          * tracker altogether. The crypto libs will generally return this if
160          * FIPS is enabled as well.
161          */
162         if (error == -ENOENT) {
163                 printk(KERN_ERR "NFSD: disabling legacy clientid tracking. "
164                         "Reboot recovery will not function correctly!\n");
165                 nfsd4_client_tracking_exit(clp->net);
166         }
167 }
168 
169 static void
170 __nfsd4_create_reclaim_record_grace(struct nfs4_client *clp,
171                 const char *dname, int len, struct nfsd_net *nn)
172 {
173         struct xdr_netobj name;
174         struct xdr_netobj princhash = { .len = 0, .data = NULL };
175         struct nfs4_client_reclaim *crp;
176 
177         name.data = kmemdup(dname, len, GFP_KERNEL);
178         if (!name.data) {
179                 dprintk("%s: failed to allocate memory for name.data!\n",
180                         __func__);
181                 return;
182         }
183         name.len = len;
184         crp = nfs4_client_to_reclaim(name, princhash, nn);
185         if (!crp) {
186                 kfree(name.data);
187                 return;
188         }
189         crp->cr_clp = clp;
190 }
191 
192 static void
193 nfsd4_create_clid_dir(struct nfs4_client *clp)
194 {
195         const struct cred *original_cred;
196         char dname[HEXDIR_LEN];
197         struct dentry *dir, *dentry;
198         int status;
199         struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
200 
201         if (test_and_set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
202                 return;
203         if (!nn->rec_file)
204                 return;
205 
206         status = nfs4_make_rec_clidname(dname, &clp->cl_name);
207         if (status)
208                 return legacy_recdir_name_error(clp, status);
209 
210         status = nfs4_save_creds(&original_cred);
211         if (status < 0)
212                 return;
213 
214         status = mnt_want_write_file(nn->rec_file);
215         if (status)
216                 goto out_creds;
217 
218         dir = nn->rec_file->f_path.dentry;
219         /* lock the parent */
220         inode_lock(d_inode(dir));
221 
222         dentry = lookup_one_len(dname, dir, HEXDIR_LEN-1);
223         if (IS_ERR(dentry)) {
224                 status = PTR_ERR(dentry);
225                 goto out_unlock;
226         }
227         if (d_really_is_positive(dentry))
228                 /*
229                  * In the 4.1 case, where we're called from
230                  * reclaim_complete(), records from the previous reboot
231                  * may still be left, so this is OK.
232                  *
233                  * In the 4.0 case, we should never get here; but we may
234                  * as well be forgiving and just succeed silently.
235                  */
236                 goto out_put;
237         status = vfs_mkdir(&nop_mnt_idmap, d_inode(dir), dentry, S_IRWXU);
238 out_put:
239         dput(dentry);
240 out_unlock:
241         inode_unlock(d_inode(dir));
242         if (status == 0) {
243                 if (nn->in_grace)
244                         __nfsd4_create_reclaim_record_grace(clp, dname,
245                                         HEXDIR_LEN, nn);
246                 vfs_fsync(nn->rec_file, 0);
247         } else {
248                 printk(KERN_ERR "NFSD: failed to write recovery record"
249                                 " (err %d); please check that %s exists"
250                                 " and is writeable", status,
251                                 user_recovery_dirname);
252         }
253         mnt_drop_write_file(nn->rec_file);
254 out_creds:
255         nfs4_reset_creds(original_cred);
256 }
257 
258 typedef int (recdir_func)(struct dentry *, struct dentry *, struct nfsd_net *);
259 
260 struct name_list {
261         char name[HEXDIR_LEN];
262         struct list_head list;
263 };
264 
265 struct nfs4_dir_ctx {
266         struct dir_context ctx;
267         struct list_head names;
268 };
269 
270 static bool
271 nfsd4_build_namelist(struct dir_context *__ctx, const char *name, int namlen,
272                 loff_t offset, u64 ino, unsigned int d_type)
273 {
274         struct nfs4_dir_ctx *ctx =
275                 container_of(__ctx, struct nfs4_dir_ctx, ctx);
276         struct name_list *entry;
277 
278         if (namlen != HEXDIR_LEN - 1)
279                 return true;
280         entry = kmalloc(sizeof(struct name_list), GFP_KERNEL);
281         if (entry == NULL)
282                 return false;
283         memcpy(entry->name, name, HEXDIR_LEN - 1);
284         entry->name[HEXDIR_LEN - 1] = '\0';
285         list_add(&entry->list, &ctx->names);
286         return true;
287 }
288 
289 static int
290 nfsd4_list_rec_dir(recdir_func *f, struct nfsd_net *nn)
291 {
292         const struct cred *original_cred;
293         struct dentry *dir = nn->rec_file->f_path.dentry;
294         struct nfs4_dir_ctx ctx = {
295                 .ctx.actor = nfsd4_build_namelist,
296                 .names = LIST_HEAD_INIT(ctx.names)
297         };
298         struct name_list *entry, *tmp;
299         int status;
300 
301         status = nfs4_save_creds(&original_cred);
302         if (status < 0)
303                 return status;
304 
305         status = vfs_llseek(nn->rec_file, 0, SEEK_SET);
306         if (status < 0) {
307                 nfs4_reset_creds(original_cred);
308                 return status;
309         }
310 
311         status = iterate_dir(nn->rec_file, &ctx.ctx);
312         inode_lock_nested(d_inode(dir), I_MUTEX_PARENT);
313 
314         list_for_each_entry_safe(entry, tmp, &ctx.names, list) {
315                 if (!status) {
316                         struct dentry *dentry;
317                         dentry = lookup_one_len(entry->name, dir, HEXDIR_LEN-1);
318                         if (IS_ERR(dentry)) {
319                                 status = PTR_ERR(dentry);
320                                 break;
321                         }
322                         status = f(dir, dentry, nn);
323                         dput(dentry);
324                 }
325                 list_del(&entry->list);
326                 kfree(entry);
327         }
328         inode_unlock(d_inode(dir));
329         nfs4_reset_creds(original_cred);
330 
331         list_for_each_entry_safe(entry, tmp, &ctx.names, list) {
332                 dprintk("NFSD: %s. Left entry %s\n", __func__, entry->name);
333                 list_del(&entry->list);
334                 kfree(entry);
335         }
336         return status;
337 }
338 
339 static int
340 nfsd4_unlink_clid_dir(char *name, int namlen, struct nfsd_net *nn)
341 {
342         struct dentry *dir, *dentry;
343         int status;
344 
345         dprintk("NFSD: nfsd4_unlink_clid_dir. name %.*s\n", namlen, name);
346 
347         dir = nn->rec_file->f_path.dentry;
348         inode_lock_nested(d_inode(dir), I_MUTEX_PARENT);
349         dentry = lookup_one_len(name, dir, namlen);
350         if (IS_ERR(dentry)) {
351                 status = PTR_ERR(dentry);
352                 goto out_unlock;
353         }
354         status = -ENOENT;
355         if (d_really_is_negative(dentry))
356                 goto out;
357         status = vfs_rmdir(&nop_mnt_idmap, d_inode(dir), dentry);
358 out:
359         dput(dentry);
360 out_unlock:
361         inode_unlock(d_inode(dir));
362         return status;
363 }
364 
365 static void
366 __nfsd4_remove_reclaim_record_grace(const char *dname, int len,
367                 struct nfsd_net *nn)
368 {
369         struct xdr_netobj name;
370         struct nfs4_client_reclaim *crp;
371 
372         name.data = kmemdup(dname, len, GFP_KERNEL);
373         if (!name.data) {
374                 dprintk("%s: failed to allocate memory for name.data!\n",
375                         __func__);
376                 return;
377         }
378         name.len = len;
379         crp = nfsd4_find_reclaim_client(name, nn);
380         kfree(name.data);
381         if (crp)
382                 nfs4_remove_reclaim_record(crp, nn);
383 }
384 
385 static void
386 nfsd4_remove_clid_dir(struct nfs4_client *clp)
387 {
388         const struct cred *original_cred;
389         char dname[HEXDIR_LEN];
390         int status;
391         struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
392 
393         if (!nn->rec_file || !test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
394                 return;
395 
396         status = nfs4_make_rec_clidname(dname, &clp->cl_name);
397         if (status)
398                 return legacy_recdir_name_error(clp, status);
399 
400         status = mnt_want_write_file(nn->rec_file);
401         if (status)
402                 goto out;
403         clear_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
404 
405         status = nfs4_save_creds(&original_cred);
406         if (status < 0)
407                 goto out_drop_write;
408 
409         status = nfsd4_unlink_clid_dir(dname, HEXDIR_LEN-1, nn);
410         nfs4_reset_creds(original_cred);
411         if (status == 0) {
412                 vfs_fsync(nn->rec_file, 0);
413                 if (nn->in_grace)
414                         __nfsd4_remove_reclaim_record_grace(dname,
415                                         HEXDIR_LEN, nn);
416         }
417 out_drop_write:
418         mnt_drop_write_file(nn->rec_file);
419 out:
420         if (status)
421                 printk("NFSD: Failed to remove expired client state directory"
422                                 " %.*s\n", HEXDIR_LEN, dname);
423 }
424 
425 static int
426 purge_old(struct dentry *parent, struct dentry *child, struct nfsd_net *nn)
427 {
428         int status;
429         struct xdr_netobj name;
430 
431         if (child->d_name.len != HEXDIR_LEN - 1) {
432                 printk("%s: illegal name %pd in recovery directory\n",
433                                 __func__, child);
434                 /* Keep trying; maybe the others are OK: */
435                 return 0;
436         }
437         name.data = kmemdup_nul(child->d_name.name, child->d_name.len, GFP_KERNEL);
438         if (!name.data) {
439                 dprintk("%s: failed to allocate memory for name.data!\n",
440                         __func__);
441                 goto out;
442         }
443         name.len = HEXDIR_LEN;
444         if (nfs4_has_reclaimed_state(name, nn))
445                 goto out_free;
446 
447         status = vfs_rmdir(&nop_mnt_idmap, d_inode(parent), child);
448         if (status)
449                 printk("failed to remove client recovery directory %pd\n",
450                                 child);
451 out_free:
452         kfree(name.data);
453 out:
454         /* Keep trying, success or failure: */
455         return 0;
456 }
457 
458 static void
459 nfsd4_recdir_purge_old(struct nfsd_net *nn)
460 {
461         int status;
462 
463         nn->in_grace = false;
464         if (!nn->rec_file)
465                 return;
466         status = mnt_want_write_file(nn->rec_file);
467         if (status)
468                 goto out;
469         status = nfsd4_list_rec_dir(purge_old, nn);
470         if (status == 0)
471                 vfs_fsync(nn->rec_file, 0);
472         mnt_drop_write_file(nn->rec_file);
473 out:
474         nfs4_release_reclaim(nn);
475         if (status)
476                 printk("nfsd4: failed to purge old clients from recovery"
477                         " directory %pD\n", nn->rec_file);
478 }
479 
480 static int
481 load_recdir(struct dentry *parent, struct dentry *child, struct nfsd_net *nn)
482 {
483         struct xdr_netobj name;
484         struct xdr_netobj princhash = { .len = 0, .data = NULL };
485 
486         if (child->d_name.len != HEXDIR_LEN - 1) {
487                 printk("%s: illegal name %pd in recovery directory\n",
488                                 __func__, child);
489                 /* Keep trying; maybe the others are OK: */
490                 return 0;
491         }
492         name.data = kmemdup_nul(child->d_name.name, child->d_name.len, GFP_KERNEL);
493         if (!name.data) {
494                 dprintk("%s: failed to allocate memory for name.data!\n",
495                         __func__);
496                 goto out;
497         }
498         name.len = HEXDIR_LEN;
499         if (!nfs4_client_to_reclaim(name, princhash, nn))
500                 kfree(name.data);
501 out:
502         return 0;
503 }
504 
505 static int
506 nfsd4_recdir_load(struct net *net) {
507         int status;
508         struct nfsd_net *nn =  net_generic(net, nfsd_net_id);
509 
510         if (!nn->rec_file)
511                 return 0;
512 
513         status = nfsd4_list_rec_dir(load_recdir, nn);
514         if (status)
515                 printk("nfsd4: failed loading clients from recovery"
516                         " directory %pD\n", nn->rec_file);
517         return status;
518 }
519 
520 /*
521  * Hold reference to the recovery directory.
522  */
523 
524 static int
525 nfsd4_init_recdir(struct net *net)
526 {
527         struct nfsd_net *nn = net_generic(net, nfsd_net_id);
528         const struct cred *original_cred;
529         int status;
530 
531         printk("NFSD: Using %s as the NFSv4 state recovery directory\n",
532                         user_recovery_dirname);
533 
534         BUG_ON(nn->rec_file);
535 
536         status = nfs4_save_creds(&original_cred);
537         if (status < 0) {
538                 printk("NFSD: Unable to change credentials to find recovery"
539                        " directory: error %d\n",
540                        status);
541                 return status;
542         }
543 
544         nn->rec_file = filp_open(user_recovery_dirname, O_RDONLY | O_DIRECTORY, 0);
545         if (IS_ERR(nn->rec_file)) {
546                 printk("NFSD: unable to find recovery directory %s\n",
547                                 user_recovery_dirname);
548                 status = PTR_ERR(nn->rec_file);
549                 nn->rec_file = NULL;
550         }
551 
552         nfs4_reset_creds(original_cred);
553         if (!status)
554                 nn->in_grace = true;
555         return status;
556 }
557 
558 static void
559 nfsd4_shutdown_recdir(struct net *net)
560 {
561         struct nfsd_net *nn = net_generic(net, nfsd_net_id);
562 
563         if (!nn->rec_file)
564                 return;
565         fput(nn->rec_file);
566         nn->rec_file = NULL;
567 }
568 
569 static int
570 nfs4_legacy_state_init(struct net *net)
571 {
572         struct nfsd_net *nn = net_generic(net, nfsd_net_id);
573         int i;
574 
575         nn->reclaim_str_hashtbl = kmalloc_array(CLIENT_HASH_SIZE,
576                                                 sizeof(struct list_head),
577                                                 GFP_KERNEL);
578         if (!nn->reclaim_str_hashtbl)
579                 return -ENOMEM;
580 
581         for (i = 0; i < CLIENT_HASH_SIZE; i++)
582                 INIT_LIST_HEAD(&nn->reclaim_str_hashtbl[i]);
583         nn->reclaim_str_hashtbl_size = 0;
584 
585         return 0;
586 }
587 
588 static void
589 nfs4_legacy_state_shutdown(struct net *net)
590 {
591         struct nfsd_net *nn = net_generic(net, nfsd_net_id);
592 
593         kfree(nn->reclaim_str_hashtbl);
594 }
595 
596 static int
597 nfsd4_load_reboot_recovery_data(struct net *net)
598 {
599         int status;
600 
601         status = nfsd4_init_recdir(net);
602         if (status)
603                 return status;
604 
605         status = nfsd4_recdir_load(net);
606         if (status)
607                 nfsd4_shutdown_recdir(net);
608 
609         return status;
610 }
611 
612 static int
613 nfsd4_legacy_tracking_init(struct net *net)
614 {
615         int status;
616 
617         /* XXX: The legacy code won't work in a container */
618         if (net != &init_net) {
619                 pr_warn("NFSD: attempt to initialize legacy client tracking in a container ignored.\n");
620                 return -EINVAL;
621         }
622 
623         status = nfs4_legacy_state_init(net);
624         if (status)
625                 return status;
626 
627         status = nfsd4_load_reboot_recovery_data(net);
628         if (status)
629                 goto err;
630         pr_info("NFSD: Using legacy client tracking operations.\n");
631         return 0;
632 
633 err:
634         nfs4_legacy_state_shutdown(net);
635         return status;
636 }
637 
638 static void
639 nfsd4_legacy_tracking_exit(struct net *net)
640 {
641         struct nfsd_net *nn = net_generic(net, nfsd_net_id);
642 
643         nfs4_release_reclaim(nn);
644         nfsd4_shutdown_recdir(net);
645         nfs4_legacy_state_shutdown(net);
646 }
647 
648 /*
649  * Change the NFSv4 recovery directory to recdir.
650  */
651 int
652 nfs4_reset_recoverydir(char *recdir)
653 {
654         int status;
655         struct path path;
656 
657         status = kern_path(recdir, LOOKUP_FOLLOW, &path);
658         if (status)
659                 return status;
660         status = -ENOTDIR;
661         if (d_is_dir(path.dentry)) {
662                 strcpy(user_recovery_dirname, recdir);
663                 status = 0;
664         }
665         path_put(&path);
666         return status;
667 }
668 
669 char *
670 nfs4_recoverydir(void)
671 {
672         return user_recovery_dirname;
673 }
674 
675 static int
676 nfsd4_check_legacy_client(struct nfs4_client *clp)
677 {
678         int status;
679         char dname[HEXDIR_LEN];
680         struct nfs4_client_reclaim *crp;
681         struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
682         struct xdr_netobj name;
683 
684         /* did we already find that this client is stable? */
685         if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
686                 return 0;
687 
688         status = nfs4_make_rec_clidname(dname, &clp->cl_name);
689         if (status) {
690                 legacy_recdir_name_error(clp, status);
691                 return status;
692         }
693 
694         /* look for it in the reclaim hashtable otherwise */
695         name.data = kmemdup(dname, HEXDIR_LEN, GFP_KERNEL);
696         if (!name.data) {
697                 dprintk("%s: failed to allocate memory for name.data!\n",
698                         __func__);
699                 goto out_enoent;
700         }
701         name.len = HEXDIR_LEN;
702         crp = nfsd4_find_reclaim_client(name, nn);
703         kfree(name.data);
704         if (crp) {
705                 set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
706                 crp->cr_clp = clp;
707                 return 0;
708         }
709 
710 out_enoent:
711         return -ENOENT;
712 }
713 
714 static const struct nfsd4_client_tracking_ops nfsd4_legacy_tracking_ops = {
715         .init           = nfsd4_legacy_tracking_init,
716         .exit           = nfsd4_legacy_tracking_exit,
717         .create         = nfsd4_create_clid_dir,
718         .remove         = nfsd4_remove_clid_dir,
719         .check          = nfsd4_check_legacy_client,
720         .grace_done     = nfsd4_recdir_purge_old,
721         .version        = 1,
722         .msglen         = 0,
723 };
724 #endif /* CONFIG_NFSD_LEGACY_CLIENT_TRACKING */
725 
726 /* Globals */
727 #define NFSD_PIPE_DIR           "nfsd"
728 #define NFSD_CLD_PIPE           "cld"
729 
730 /* per-net-ns structure for holding cld upcall info */
731 struct cld_net {
732         struct rpc_pipe         *cn_pipe;
733         spinlock_t               cn_lock;
734         struct list_head         cn_list;
735         unsigned int             cn_xid;
736         struct crypto_shash     *cn_tfm;
737 #ifdef CONFIG_NFSD_LEGACY_CLIENT_TRACKING
738         bool                     cn_has_legacy;
739 #endif
740 };
741 
742 struct cld_upcall {
743         struct list_head         cu_list;
744         struct cld_net          *cu_net;
745         struct completion        cu_done;
746         union {
747                 struct cld_msg_hdr       cu_hdr;
748                 struct cld_msg           cu_msg;
749                 struct cld_msg_v2        cu_msg_v2;
750         } cu_u;
751 };
752 
753 static int
754 __cld_pipe_upcall(struct rpc_pipe *pipe, void *cmsg, struct nfsd_net *nn)
755 {
756         int ret;
757         struct rpc_pipe_msg msg;
758         struct cld_upcall *cup = container_of(cmsg, struct cld_upcall, cu_u);
759 
760         memset(&msg, 0, sizeof(msg));
761         msg.data = cmsg;
762         msg.len = nn->client_tracking_ops->msglen;
763 
764         ret = rpc_queue_upcall(pipe, &msg);
765         if (ret < 0) {
766                 goto out;
767         }
768 
769         wait_for_completion(&cup->cu_done);
770 
771         if (msg.errno < 0)
772                 ret = msg.errno;
773 out:
774         return ret;
775 }
776 
777 static int
778 cld_pipe_upcall(struct rpc_pipe *pipe, void *cmsg, struct nfsd_net *nn)
779 {
780         int ret;
781 
782         /*
783          * -EAGAIN occurs when pipe is closed and reopened while there are
784          *  upcalls queued.
785          */
786         do {
787                 ret = __cld_pipe_upcall(pipe, cmsg, nn);
788         } while (ret == -EAGAIN);
789 
790         return ret;
791 }
792 
793 static ssize_t
794 __cld_pipe_inprogress_downcall(const struct cld_msg_v2 __user *cmsg,
795                 struct nfsd_net *nn)
796 {
797         uint8_t cmd, princhashlen;
798         struct xdr_netobj name, princhash = { .len = 0, .data = NULL };
799         uint16_t namelen;
800 
801         if (get_user(cmd, &cmsg->cm_cmd)) {
802                 dprintk("%s: error when copying cmd from userspace", __func__);
803                 return -EFAULT;
804         }
805         if (cmd == Cld_GraceStart) {
806                 if (nn->client_tracking_ops->version >= 2) {
807                         const struct cld_clntinfo __user *ci;
808 
809                         ci = &cmsg->cm_u.cm_clntinfo;
810                         if (get_user(namelen, &ci->cc_name.cn_len))
811                                 return -EFAULT;
812                         if (!namelen) {
813                                 dprintk("%s: namelen should not be zero", __func__);
814                                 return -EINVAL;
815                         }
816                         name.data = memdup_user(&ci->cc_name.cn_id, namelen);
817                         if (IS_ERR(name.data))
818                                 return PTR_ERR(name.data);
819                         name.len = namelen;
820                         get_user(princhashlen, &ci->cc_princhash.cp_len);
821                         if (princhashlen > 0) {
822                                 princhash.data = memdup_user(
823                                                 &ci->cc_princhash.cp_data,
824                                                 princhashlen);
825                                 if (IS_ERR(princhash.data)) {
826                                         kfree(name.data);
827                                         return PTR_ERR(princhash.data);
828                                 }
829                                 princhash.len = princhashlen;
830                         } else
831                                 princhash.len = 0;
832                 } else {
833                         const struct cld_name __user *cnm;
834 
835                         cnm = &cmsg->cm_u.cm_name;
836                         if (get_user(namelen, &cnm->cn_len))
837                                 return -EFAULT;
838                         if (!namelen) {
839                                 dprintk("%s: namelen should not be zero", __func__);
840                                 return -EINVAL;
841                         }
842                         name.data = memdup_user(&cnm->cn_id, namelen);
843                         if (IS_ERR(name.data))
844                                 return PTR_ERR(name.data);
845                         name.len = namelen;
846                 }
847 #ifdef CONFIG_NFSD_LEGACY_CLIENT_TRACKING
848                 if (name.len > 5 && memcmp(name.data, "hash:", 5) == 0) {
849                         struct cld_net *cn = nn->cld_net;
850 
851                         name.len = name.len - 5;
852                         memmove(name.data, name.data + 5, name.len);
853                         cn->cn_has_legacy = true;
854                 }
855 #endif
856                 if (!nfs4_client_to_reclaim(name, princhash, nn)) {
857                         kfree(name.data);
858                         kfree(princhash.data);
859                         return -EFAULT;
860                 }
861                 return nn->client_tracking_ops->msglen;
862         }
863         return -EFAULT;
864 }
865 
866 static ssize_t
867 cld_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
868 {
869         struct cld_upcall *tmp, *cup;
870         struct cld_msg_hdr __user *hdr = (struct cld_msg_hdr __user *)src;
871         struct cld_msg_v2 __user *cmsg = (struct cld_msg_v2 __user *)src;
872         uint32_t xid;
873         struct nfsd_net *nn = net_generic(file_inode(filp)->i_sb->s_fs_info,
874                                                 nfsd_net_id);
875         struct cld_net *cn = nn->cld_net;
876         int16_t status;
877 
878         if (mlen != nn->client_tracking_ops->msglen) {
879                 dprintk("%s: got %zu bytes, expected %zu\n", __func__, mlen,
880                         nn->client_tracking_ops->msglen);
881                 return -EINVAL;
882         }
883 
884         /* copy just the xid so we can try to find that */
885         if (copy_from_user(&xid, &hdr->cm_xid, sizeof(xid)) != 0) {
886                 dprintk("%s: error when copying xid from userspace", __func__);
887                 return -EFAULT;
888         }
889 
890         /*
891          * copy the status so we know whether to remove the upcall from the
892          * list (for -EINPROGRESS, we just want to make sure the xid is
893          * valid, not remove the upcall from the list)
894          */
895         if (get_user(status, &hdr->cm_status)) {
896                 dprintk("%s: error when copying status from userspace", __func__);
897                 return -EFAULT;
898         }
899 
900         /* walk the list and find corresponding xid */
901         cup = NULL;
902         spin_lock(&cn->cn_lock);
903         list_for_each_entry(tmp, &cn->cn_list, cu_list) {
904                 if (get_unaligned(&tmp->cu_u.cu_hdr.cm_xid) == xid) {
905                         cup = tmp;
906                         if (status != -EINPROGRESS)
907                                 list_del_init(&cup->cu_list);
908                         break;
909                 }
910         }
911         spin_unlock(&cn->cn_lock);
912 
913         /* couldn't find upcall? */
914         if (!cup) {
915                 dprintk("%s: couldn't find upcall -- xid=%u\n", __func__, xid);
916                 return -EINVAL;
917         }
918 
919         if (status == -EINPROGRESS)
920                 return __cld_pipe_inprogress_downcall(cmsg, nn);
921 
922         if (copy_from_user(&cup->cu_u.cu_msg_v2, src, mlen) != 0)
923                 return -EFAULT;
924 
925         complete(&cup->cu_done);
926         return mlen;
927 }
928 
929 static void
930 cld_pipe_destroy_msg(struct rpc_pipe_msg *msg)
931 {
932         struct cld_msg *cmsg = msg->data;
933         struct cld_upcall *cup = container_of(cmsg, struct cld_upcall,
934                                                  cu_u.cu_msg);
935 
936         /* errno >= 0 means we got a downcall */
937         if (msg->errno >= 0)
938                 return;
939 
940         complete(&cup->cu_done);
941 }
942 
943 static const struct rpc_pipe_ops cld_upcall_ops = {
944         .upcall         = rpc_pipe_generic_upcall,
945         .downcall       = cld_pipe_downcall,
946         .destroy_msg    = cld_pipe_destroy_msg,
947 };
948 
949 static struct dentry *
950 nfsd4_cld_register_sb(struct super_block *sb, struct rpc_pipe *pipe)
951 {
952         struct dentry *dir, *dentry;
953 
954         dir = rpc_d_lookup_sb(sb, NFSD_PIPE_DIR);
955         if (dir == NULL)
956                 return ERR_PTR(-ENOENT);
957         dentry = rpc_mkpipe_dentry(dir, NFSD_CLD_PIPE, NULL, pipe);
958         dput(dir);
959         return dentry;
960 }
961 
962 static void
963 nfsd4_cld_unregister_sb(struct rpc_pipe *pipe)
964 {
965         if (pipe->dentry)
966                 rpc_unlink(pipe->dentry);
967 }
968 
969 static struct dentry *
970 nfsd4_cld_register_net(struct net *net, struct rpc_pipe *pipe)
971 {
972         struct super_block *sb;
973         struct dentry *dentry;
974 
975         sb = rpc_get_sb_net(net);
976         if (!sb)
977                 return NULL;
978         dentry = nfsd4_cld_register_sb(sb, pipe);
979         rpc_put_sb_net(net);
980         return dentry;
981 }
982 
983 static void
984 nfsd4_cld_unregister_net(struct net *net, struct rpc_pipe *pipe)
985 {
986         struct super_block *sb;
987 
988         sb = rpc_get_sb_net(net);
989         if (sb) {
990                 nfsd4_cld_unregister_sb(pipe);
991                 rpc_put_sb_net(net);
992         }
993 }
994 
995 /* Initialize rpc_pipefs pipe for communication with client tracking daemon */
996 static int
997 __nfsd4_init_cld_pipe(struct net *net)
998 {
999         int ret;
1000         struct dentry *dentry;
1001         struct nfsd_net *nn = net_generic(net, nfsd_net_id);
1002         struct cld_net *cn;
1003 
1004         if (nn->cld_net)
1005                 return 0;
1006 
1007         cn = kzalloc(sizeof(*cn), GFP_KERNEL);
1008         if (!cn) {
1009                 ret = -ENOMEM;
1010                 goto err;
1011         }
1012 
1013         cn->cn_pipe = rpc_mkpipe_data(&cld_upcall_ops, RPC_PIPE_WAIT_FOR_OPEN);
1014         if (IS_ERR(cn->cn_pipe)) {
1015                 ret = PTR_ERR(cn->cn_pipe);
1016                 goto err;
1017         }
1018         spin_lock_init(&cn->cn_lock);
1019         INIT_LIST_HEAD(&cn->cn_list);
1020 
1021         dentry = nfsd4_cld_register_net(net, cn->cn_pipe);
1022         if (IS_ERR(dentry)) {
1023                 ret = PTR_ERR(dentry);
1024                 goto err_destroy_data;
1025         }
1026 
1027         cn->cn_pipe->dentry = dentry;
1028 #ifdef CONFIG_NFSD_LEGACY_CLIENT_TRACKING
1029         cn->cn_has_legacy = false;
1030 #endif
1031         nn->cld_net = cn;
1032         return 0;
1033 
1034 err_destroy_data:
1035         rpc_destroy_pipe_data(cn->cn_pipe);
1036 err:
1037         kfree(cn);
1038         printk(KERN_ERR "NFSD: unable to create nfsdcld upcall pipe (%d)\n",
1039                         ret);
1040         return ret;
1041 }
1042 
1043 static int
1044 nfsd4_init_cld_pipe(struct net *net)
1045 {
1046         int status;
1047 
1048         status = __nfsd4_init_cld_pipe(net);
1049         if (!status)
1050                 pr_info("NFSD: Using old nfsdcld client tracking operations.\n");
1051         return status;
1052 }
1053 
1054 static void
1055 nfsd4_remove_cld_pipe(struct net *net)
1056 {
1057         struct nfsd_net *nn = net_generic(net, nfsd_net_id);
1058         struct cld_net *cn = nn->cld_net;
1059 
1060         nfsd4_cld_unregister_net(net, cn->cn_pipe);
1061         rpc_destroy_pipe_data(cn->cn_pipe);
1062         if (cn->cn_tfm)
1063                 crypto_free_shash(cn->cn_tfm);
1064         kfree(nn->cld_net);
1065         nn->cld_net = NULL;
1066 }
1067 
1068 static struct cld_upcall *
1069 alloc_cld_upcall(struct nfsd_net *nn)
1070 {
1071         struct cld_upcall *new, *tmp;
1072         struct cld_net *cn = nn->cld_net;
1073 
1074         new = kzalloc(sizeof(*new), GFP_KERNEL);
1075         if (!new)
1076                 return new;
1077 
1078         /* FIXME: hard cap on number in flight? */
1079 restart_search:
1080         spin_lock(&cn->cn_lock);
1081         list_for_each_entry(tmp, &cn->cn_list, cu_list) {
1082                 if (tmp->cu_u.cu_msg.cm_xid == cn->cn_xid) {
1083                         cn->cn_xid++;
1084                         spin_unlock(&cn->cn_lock);
1085                         goto restart_search;
1086                 }
1087         }
1088         init_completion(&new->cu_done);
1089         new->cu_u.cu_msg.cm_vers = nn->client_tracking_ops->version;
1090         put_unaligned(cn->cn_xid++, &new->cu_u.cu_msg.cm_xid);
1091         new->cu_net = cn;
1092         list_add(&new->cu_list, &cn->cn_list);
1093         spin_unlock(&cn->cn_lock);
1094 
1095         dprintk("%s: allocated xid %u\n", __func__, new->cu_u.cu_msg.cm_xid);
1096 
1097         return new;
1098 }
1099 
1100 static void
1101 free_cld_upcall(struct cld_upcall *victim)
1102 {
1103         struct cld_net *cn = victim->cu_net;
1104 
1105         spin_lock(&cn->cn_lock);
1106         list_del(&victim->cu_list);
1107         spin_unlock(&cn->cn_lock);
1108         kfree(victim);
1109 }
1110 
1111 /* Ask daemon to create a new record */
1112 static void
1113 nfsd4_cld_create(struct nfs4_client *clp)
1114 {
1115         int ret;
1116         struct cld_upcall *cup;
1117         struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
1118         struct cld_net *cn = nn->cld_net;
1119 
1120         /* Don't upcall if it's already stored */
1121         if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
1122                 return;
1123 
1124         cup = alloc_cld_upcall(nn);
1125         if (!cup) {
1126                 ret = -ENOMEM;
1127                 goto out_err;
1128         }
1129 
1130         cup->cu_u.cu_msg.cm_cmd = Cld_Create;
1131         cup->cu_u.cu_msg.cm_u.cm_name.cn_len = clp->cl_name.len;
1132         memcpy(cup->cu_u.cu_msg.cm_u.cm_name.cn_id, clp->cl_name.data,
1133                         clp->cl_name.len);
1134 
1135         ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_u.cu_msg, nn);
1136         if (!ret) {
1137                 ret = cup->cu_u.cu_msg.cm_status;
1138                 set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
1139         }
1140 
1141         free_cld_upcall(cup);
1142 out_err:
1143         if (ret)
1144                 printk(KERN_ERR "NFSD: Unable to create client "
1145                                 "record on stable storage: %d\n", ret);
1146 }
1147 
1148 /* Ask daemon to create a new record */
1149 static void
1150 nfsd4_cld_create_v2(struct nfs4_client *clp)
1151 {
1152         int ret;
1153         struct cld_upcall *cup;
1154         struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
1155         struct cld_net *cn = nn->cld_net;
1156         struct cld_msg_v2 *cmsg;
1157         struct crypto_shash *tfm = cn->cn_tfm;
1158         struct xdr_netobj cksum;
1159         char *principal = NULL;
1160 
1161         /* Don't upcall if it's already stored */
1162         if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
1163                 return;
1164 
1165         cup = alloc_cld_upcall(nn);
1166         if (!cup) {
1167                 ret = -ENOMEM;
1168                 goto out_err;
1169         }
1170 
1171         cmsg = &cup->cu_u.cu_msg_v2;
1172         cmsg->cm_cmd = Cld_Create;
1173         cmsg->cm_u.cm_clntinfo.cc_name.cn_len = clp->cl_name.len;
1174         memcpy(cmsg->cm_u.cm_clntinfo.cc_name.cn_id, clp->cl_name.data,
1175                         clp->cl_name.len);
1176         if (clp->cl_cred.cr_raw_principal)
1177                 principal = clp->cl_cred.cr_raw_principal;
1178         else if (clp->cl_cred.cr_principal)
1179                 principal = clp->cl_cred.cr_principal;
1180         if (principal) {
1181                 cksum.len = crypto_shash_digestsize(tfm);
1182                 cksum.data = kmalloc(cksum.len, GFP_KERNEL);
1183                 if (cksum.data == NULL) {
1184                         ret = -ENOMEM;
1185                         goto out;
1186                 }
1187                 ret = crypto_shash_tfm_digest(tfm, principal, strlen(principal),
1188                                               cksum.data);
1189                 if (ret) {
1190                         kfree(cksum.data);
1191                         goto out;
1192                 }
1193                 cmsg->cm_u.cm_clntinfo.cc_princhash.cp_len = cksum.len;
1194                 memcpy(cmsg->cm_u.cm_clntinfo.cc_princhash.cp_data,
1195                        cksum.data, cksum.len);
1196                 kfree(cksum.data);
1197         } else
1198                 cmsg->cm_u.cm_clntinfo.cc_princhash.cp_len = 0;
1199 
1200         ret = cld_pipe_upcall(cn->cn_pipe, cmsg, nn);
1201         if (!ret) {
1202                 ret = cmsg->cm_status;
1203                 set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
1204         }
1205 
1206 out:
1207         free_cld_upcall(cup);
1208 out_err:
1209         if (ret)
1210                 pr_err("NFSD: Unable to create client record on stable storage: %d\n",
1211                                 ret);
1212 }
1213 
1214 /* Ask daemon to create a new record */
1215 static void
1216 nfsd4_cld_remove(struct nfs4_client *clp)
1217 {
1218         int ret;
1219         struct cld_upcall *cup;
1220         struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
1221         struct cld_net *cn = nn->cld_net;
1222 
1223         /* Don't upcall if it's already removed */
1224         if (!test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
1225                 return;
1226 
1227         cup = alloc_cld_upcall(nn);
1228         if (!cup) {
1229                 ret = -ENOMEM;
1230                 goto out_err;
1231         }
1232 
1233         cup->cu_u.cu_msg.cm_cmd = Cld_Remove;
1234         cup->cu_u.cu_msg.cm_u.cm_name.cn_len = clp->cl_name.len;
1235         memcpy(cup->cu_u.cu_msg.cm_u.cm_name.cn_id, clp->cl_name.data,
1236                         clp->cl_name.len);
1237 
1238         ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_u.cu_msg, nn);
1239         if (!ret) {
1240                 ret = cup->cu_u.cu_msg.cm_status;
1241                 clear_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
1242         }
1243 
1244         free_cld_upcall(cup);
1245 out_err:
1246         if (ret)
1247                 printk(KERN_ERR "NFSD: Unable to remove client "
1248                                 "record from stable storage: %d\n", ret);
1249 }
1250 
1251 /*
1252  * For older nfsdcld's that do not allow us to "slurp" the clients
1253  * from the tracking database during startup.
1254  *
1255  * Check for presence of a record, and update its timestamp
1256  */
1257 static int
1258 nfsd4_cld_check_v0(struct nfs4_client *clp)
1259 {
1260         int ret;
1261         struct cld_upcall *cup;
1262         struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
1263         struct cld_net *cn = nn->cld_net;
1264 
1265         /* Don't upcall if one was already stored during this grace pd */
1266         if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
1267                 return 0;
1268 
1269         cup = alloc_cld_upcall(nn);
1270         if (!cup) {
1271                 printk(KERN_ERR "NFSD: Unable to check client record on "
1272                                 "stable storage: %d\n", -ENOMEM);
1273                 return -ENOMEM;
1274         }
1275 
1276         cup->cu_u.cu_msg.cm_cmd = Cld_Check;
1277         cup->cu_u.cu_msg.cm_u.cm_name.cn_len = clp->cl_name.len;
1278         memcpy(cup->cu_u.cu_msg.cm_u.cm_name.cn_id, clp->cl_name.data,
1279                         clp->cl_name.len);
1280 
1281         ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_u.cu_msg, nn);
1282         if (!ret) {
1283                 ret = cup->cu_u.cu_msg.cm_status;
1284                 set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
1285         }
1286 
1287         free_cld_upcall(cup);
1288         return ret;
1289 }
1290 
1291 /*
1292  * For newer nfsdcld's that allow us to "slurp" the clients
1293  * from the tracking database during startup.
1294  *
1295  * Check for presence of a record in the reclaim_str_hashtbl
1296  */
1297 static int
1298 nfsd4_cld_check(struct nfs4_client *clp)
1299 {
1300         struct nfs4_client_reclaim *crp;
1301         struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
1302 
1303         /* did we already find that this client is stable? */
1304         if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
1305                 return 0;
1306 
1307         /* look for it in the reclaim hashtable otherwise */
1308         crp = nfsd4_find_reclaim_client(clp->cl_name, nn);
1309         if (crp)
1310                 goto found;
1311 
1312 #ifdef CONFIG_NFSD_LEGACY_CLIENT_TRACKING
1313         if (nn->cld_net->cn_has_legacy) {
1314                 int status;
1315                 char dname[HEXDIR_LEN];
1316                 struct xdr_netobj name;
1317 
1318                 status = nfs4_make_rec_clidname(dname, &clp->cl_name);
1319                 if (status)
1320                         return -ENOENT;
1321 
1322                 name.data = kmemdup(dname, HEXDIR_LEN, GFP_KERNEL);
1323                 if (!name.data) {
1324                         dprintk("%s: failed to allocate memory for name.data!\n",
1325                                 __func__);
1326                         return -ENOENT;
1327                 }
1328                 name.len = HEXDIR_LEN;
1329                 crp = nfsd4_find_reclaim_client(name, nn);
1330                 kfree(name.data);
1331                 if (crp)
1332                         goto found;
1333 
1334         }
1335 #endif
1336         return -ENOENT;
1337 found:
1338         crp->cr_clp = clp;
1339         return 0;
1340 }
1341 
1342 static int
1343 nfsd4_cld_check_v2(struct nfs4_client *clp)
1344 {
1345         struct nfs4_client_reclaim *crp;
1346         struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
1347         struct cld_net *cn = nn->cld_net;
1348         int status;
1349         struct crypto_shash *tfm = cn->cn_tfm;
1350         struct xdr_netobj cksum;
1351         char *principal = NULL;
1352 
1353         /* did we already find that this client is stable? */
1354         if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
1355                 return 0;
1356 
1357         /* look for it in the reclaim hashtable otherwise */
1358         crp = nfsd4_find_reclaim_client(clp->cl_name, nn);
1359         if (crp)
1360                 goto found;
1361 
1362 #ifdef CONFIG_NFSD_LEGACY_CLIENT_TRACKING
1363         if (cn->cn_has_legacy) {
1364                 struct xdr_netobj name;
1365                 char dname[HEXDIR_LEN];
1366 
1367                 status = nfs4_make_rec_clidname(dname, &clp->cl_name);
1368                 if (status)
1369                         return -ENOENT;
1370 
1371                 name.data = kmemdup(dname, HEXDIR_LEN, GFP_KERNEL);
1372                 if (!name.data) {
1373                         dprintk("%s: failed to allocate memory for name.data\n",
1374                                         __func__);
1375                         return -ENOENT;
1376                 }
1377                 name.len = HEXDIR_LEN;
1378                 crp = nfsd4_find_reclaim_client(name, nn);
1379                 kfree(name.data);
1380                 if (crp)
1381                         goto found;
1382 
1383         }
1384 #endif
1385         return -ENOENT;
1386 found:
1387         if (crp->cr_princhash.len) {
1388                 if (clp->cl_cred.cr_raw_principal)
1389                         principal = clp->cl_cred.cr_raw_principal;
1390                 else if (clp->cl_cred.cr_principal)
1391                         principal = clp->cl_cred.cr_principal;
1392                 if (principal == NULL)
1393                         return -ENOENT;
1394                 cksum.len = crypto_shash_digestsize(tfm);
1395                 cksum.data = kmalloc(cksum.len, GFP_KERNEL);
1396                 if (cksum.data == NULL)
1397                         return -ENOENT;
1398                 status = crypto_shash_tfm_digest(tfm, principal,
1399                                                  strlen(principal), cksum.data);
1400                 if (status) {
1401                         kfree(cksum.data);
1402                         return -ENOENT;
1403                 }
1404                 if (memcmp(crp->cr_princhash.data, cksum.data,
1405                                 crp->cr_princhash.len)) {
1406                         kfree(cksum.data);
1407                         return -ENOENT;
1408                 }
1409                 kfree(cksum.data);
1410         }
1411         crp->cr_clp = clp;
1412         return 0;
1413 }
1414 
1415 static int
1416 nfsd4_cld_grace_start(struct nfsd_net *nn)
1417 {
1418         int ret;
1419         struct cld_upcall *cup;
1420         struct cld_net *cn = nn->cld_net;
1421 
1422         cup = alloc_cld_upcall(nn);
1423         if (!cup) {
1424                 ret = -ENOMEM;
1425                 goto out_err;
1426         }
1427 
1428         cup->cu_u.cu_msg.cm_cmd = Cld_GraceStart;
1429         ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_u.cu_msg, nn);
1430         if (!ret)
1431                 ret = cup->cu_u.cu_msg.cm_status;
1432 
1433         free_cld_upcall(cup);
1434 out_err:
1435         if (ret)
1436                 dprintk("%s: Unable to get clients from userspace: %d\n",
1437                         __func__, ret);
1438         return ret;
1439 }
1440 
1441 /* For older nfsdcld's that need cm_gracetime */
1442 static void
1443 nfsd4_cld_grace_done_v0(struct nfsd_net *nn)
1444 {
1445         int ret;
1446         struct cld_upcall *cup;
1447         struct cld_net *cn = nn->cld_net;
1448 
1449         cup = alloc_cld_upcall(nn);
1450         if (!cup) {
1451                 ret = -ENOMEM;
1452                 goto out_err;
1453         }
1454 
1455         cup->cu_u.cu_msg.cm_cmd = Cld_GraceDone;
1456         cup->cu_u.cu_msg.cm_u.cm_gracetime = nn->boot_time;
1457         ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_u.cu_msg, nn);
1458         if (!ret)
1459                 ret = cup->cu_u.cu_msg.cm_status;
1460 
1461         free_cld_upcall(cup);
1462 out_err:
1463         if (ret)
1464                 printk(KERN_ERR "NFSD: Unable to end grace period: %d\n", ret);
1465 }
1466 
1467 /*
1468  * For newer nfsdcld's that do not need cm_gracetime.  We also need to call
1469  * nfs4_release_reclaim() to clear out the reclaim_str_hashtbl.
1470  */
1471 static void
1472 nfsd4_cld_grace_done(struct nfsd_net *nn)
1473 {
1474         int ret;
1475         struct cld_upcall *cup;
1476         struct cld_net *cn = nn->cld_net;
1477 
1478         cup = alloc_cld_upcall(nn);
1479         if (!cup) {
1480                 ret = -ENOMEM;
1481                 goto out_err;
1482         }
1483 
1484         cup->cu_u.cu_msg.cm_cmd = Cld_GraceDone;
1485         ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_u.cu_msg, nn);
1486         if (!ret)
1487                 ret = cup->cu_u.cu_msg.cm_status;
1488 
1489         free_cld_upcall(cup);
1490 out_err:
1491         nfs4_release_reclaim(nn);
1492         if (ret)
1493                 printk(KERN_ERR "NFSD: Unable to end grace period: %d\n", ret);
1494 }
1495 
1496 static int
1497 nfs4_cld_state_init(struct net *net)
1498 {
1499         struct nfsd_net *nn = net_generic(net, nfsd_net_id);
1500         int i;
1501 
1502         nn->reclaim_str_hashtbl = kmalloc_array(CLIENT_HASH_SIZE,
1503                                                 sizeof(struct list_head),
1504                                                 GFP_KERNEL);
1505         if (!nn->reclaim_str_hashtbl)
1506                 return -ENOMEM;
1507 
1508         for (i = 0; i < CLIENT_HASH_SIZE; i++)
1509                 INIT_LIST_HEAD(&nn->reclaim_str_hashtbl[i]);
1510         nn->reclaim_str_hashtbl_size = 0;
1511         nn->track_reclaim_completes = true;
1512         atomic_set(&nn->nr_reclaim_complete, 0);
1513 
1514         return 0;
1515 }
1516 
1517 static void
1518 nfs4_cld_state_shutdown(struct net *net)
1519 {
1520         struct nfsd_net *nn = net_generic(net, nfsd_net_id);
1521 
1522         nn->track_reclaim_completes = false;
1523         kfree(nn->reclaim_str_hashtbl);
1524 }
1525 
1526 static bool
1527 cld_running(struct nfsd_net *nn)
1528 {
1529         struct cld_net *cn = nn->cld_net;
1530         struct rpc_pipe *pipe = cn->cn_pipe;
1531 
1532         return pipe->nreaders || pipe->nwriters;
1533 }
1534 
1535 static int
1536 nfsd4_cld_get_version(struct nfsd_net *nn)
1537 {
1538         int ret = 0;
1539         struct cld_upcall *cup;
1540         struct cld_net *cn = nn->cld_net;
1541         uint8_t version;
1542 
1543         cup = alloc_cld_upcall(nn);
1544         if (!cup) {
1545                 ret = -ENOMEM;
1546                 goto out_err;
1547         }
1548         cup->cu_u.cu_msg.cm_cmd = Cld_GetVersion;
1549         ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_u.cu_msg, nn);
1550         if (!ret) {
1551                 ret = cup->cu_u.cu_msg.cm_status;
1552                 if (ret)
1553                         goto out_free;
1554                 version = cup->cu_u.cu_msg.cm_u.cm_version;
1555                 dprintk("%s: userspace returned version %u\n",
1556                                 __func__, version);
1557                 if (version < 1)
1558                         version = 1;
1559                 else if (version > CLD_UPCALL_VERSION)
1560                         version = CLD_UPCALL_VERSION;
1561 
1562                 switch (version) {
1563                 case 1:
1564                         nn->client_tracking_ops = &nfsd4_cld_tracking_ops;
1565                         break;
1566                 case 2:
1567                         nn->client_tracking_ops = &nfsd4_cld_tracking_ops_v2;
1568                         break;
1569                 default:
1570                         break;
1571                 }
1572         }
1573 out_free:
1574         free_cld_upcall(cup);
1575 out_err:
1576         if (ret)
1577                 dprintk("%s: Unable to get version from userspace: %d\n",
1578                         __func__, ret);
1579         return ret;
1580 }
1581 
1582 static int
1583 nfsd4_cld_tracking_init(struct net *net)
1584 {
1585         int status;
1586         struct nfsd_net *nn = net_generic(net, nfsd_net_id);
1587         bool running;
1588         int retries = 10;
1589         struct crypto_shash *tfm;
1590 
1591         status = nfs4_cld_state_init(net);
1592         if (status)
1593                 return status;
1594 
1595         status = __nfsd4_init_cld_pipe(net);
1596         if (status)
1597                 goto err_shutdown;
1598 
1599         /*
1600          * rpc pipe upcalls take 30 seconds to time out, so we don't want to
1601          * queue an upcall unless we know that nfsdcld is running (because we
1602          * want this to fail fast so that nfsd4_client_tracking_init() can try
1603          * the next client tracking method).  nfsdcld should already be running
1604          * before nfsd is started, so the wait here is for nfsdcld to open the
1605          * pipefs file we just created.
1606          */
1607         while (!(running = cld_running(nn)) && retries--)
1608                 msleep(100);
1609 
1610         if (!running) {
1611                 status = -ETIMEDOUT;
1612                 goto err_remove;
1613         }
1614         tfm = crypto_alloc_shash("sha256", 0, 0);
1615         if (IS_ERR(tfm)) {
1616                 status = PTR_ERR(tfm);
1617                 goto err_remove;
1618         }
1619         nn->cld_net->cn_tfm = tfm;
1620 
1621         status = nfsd4_cld_get_version(nn);
1622         if (status == -EOPNOTSUPP)
1623                 pr_warn("NFSD: nfsdcld GetVersion upcall failed. Please upgrade nfsdcld.\n");
1624 
1625         status = nfsd4_cld_grace_start(nn);
1626         if (status) {
1627                 if (status == -EOPNOTSUPP)
1628                         pr_warn("NFSD: nfsdcld GraceStart upcall failed. Please upgrade nfsdcld.\n");
1629                 nfs4_release_reclaim(nn);
1630                 goto err_remove;
1631         } else
1632                 pr_info("NFSD: Using nfsdcld client tracking operations.\n");
1633         return 0;
1634 
1635 err_remove:
1636         nfsd4_remove_cld_pipe(net);
1637 err_shutdown:
1638         nfs4_cld_state_shutdown(net);
1639         return status;
1640 }
1641 
1642 static void
1643 nfsd4_cld_tracking_exit(struct net *net)
1644 {
1645         struct nfsd_net *nn = net_generic(net, nfsd_net_id);
1646 
1647         nfs4_release_reclaim(nn);
1648         nfsd4_remove_cld_pipe(net);
1649         nfs4_cld_state_shutdown(net);
1650 }
1651 
1652 /* For older nfsdcld's */
1653 static const struct nfsd4_client_tracking_ops nfsd4_cld_tracking_ops_v0 = {
1654         .init           = nfsd4_init_cld_pipe,
1655         .exit           = nfsd4_remove_cld_pipe,
1656         .create         = nfsd4_cld_create,
1657         .remove         = nfsd4_cld_remove,
1658         .check          = nfsd4_cld_check_v0,
1659         .grace_done     = nfsd4_cld_grace_done_v0,
1660         .version        = 1,
1661         .msglen         = sizeof(struct cld_msg),
1662 };
1663 
1664 /* For newer nfsdcld's */
1665 static const struct nfsd4_client_tracking_ops nfsd4_cld_tracking_ops = {
1666         .init           = nfsd4_cld_tracking_init,
1667         .exit           = nfsd4_cld_tracking_exit,
1668         .create         = nfsd4_cld_create,
1669         .remove         = nfsd4_cld_remove,
1670         .check          = nfsd4_cld_check,
1671         .grace_done     = nfsd4_cld_grace_done,
1672         .version        = 1,
1673         .msglen         = sizeof(struct cld_msg),
1674 };
1675 
1676 /* v2 create/check ops include the principal, if available */
1677 static const struct nfsd4_client_tracking_ops nfsd4_cld_tracking_ops_v2 = {
1678         .init           = nfsd4_cld_tracking_init,
1679         .exit           = nfsd4_cld_tracking_exit,
1680         .create         = nfsd4_cld_create_v2,
1681         .remove         = nfsd4_cld_remove,
1682         .check          = nfsd4_cld_check_v2,
1683         .grace_done     = nfsd4_cld_grace_done,
1684         .version        = 2,
1685         .msglen         = sizeof(struct cld_msg_v2),
1686 };
1687 
1688 #ifdef CONFIG_NFSD_LEGACY_CLIENT_TRACKING
1689 /* upcall via usermodehelper */
1690 static char cltrack_prog[PATH_MAX] = "/sbin/nfsdcltrack";
1691 module_param_string(cltrack_prog, cltrack_prog, sizeof(cltrack_prog),
1692                         S_IRUGO|S_IWUSR);
1693 MODULE_PARM_DESC(cltrack_prog, "Path to the nfsdcltrack upcall program");
1694 
1695 static bool cltrack_legacy_disable;
1696 module_param(cltrack_legacy_disable, bool, S_IRUGO|S_IWUSR);
1697 MODULE_PARM_DESC(cltrack_legacy_disable,
1698                 "Disable legacy recoverydir conversion. Default: false");
1699 
1700 #define LEGACY_TOPDIR_ENV_PREFIX "NFSDCLTRACK_LEGACY_TOPDIR="
1701 #define LEGACY_RECDIR_ENV_PREFIX "NFSDCLTRACK_LEGACY_RECDIR="
1702 #define HAS_SESSION_ENV_PREFIX "NFSDCLTRACK_CLIENT_HAS_SESSION="
1703 #define GRACE_START_ENV_PREFIX "NFSDCLTRACK_GRACE_START="
1704 
1705 static char *
1706 nfsd4_cltrack_legacy_topdir(void)
1707 {
1708         int copied;
1709         size_t len;
1710         char *result;
1711 
1712         if (cltrack_legacy_disable)
1713                 return NULL;
1714 
1715         len = strlen(LEGACY_TOPDIR_ENV_PREFIX) +
1716                 strlen(nfs4_recoverydir()) + 1;
1717 
1718         result = kmalloc(len, GFP_KERNEL);
1719         if (!result)
1720                 return result;
1721 
1722         copied = snprintf(result, len, LEGACY_TOPDIR_ENV_PREFIX "%s",
1723                                 nfs4_recoverydir());
1724         if (copied >= len) {
1725                 /* just return nothing if output was truncated */
1726                 kfree(result);
1727                 return NULL;
1728         }
1729 
1730         return result;
1731 }
1732 
1733 static char *
1734 nfsd4_cltrack_legacy_recdir(const struct xdr_netobj *name)
1735 {
1736         int copied;
1737         size_t len;
1738         char *result;
1739 
1740         if (cltrack_legacy_disable)
1741                 return NULL;
1742 
1743         /* +1 is for '/' between "topdir" and "recdir" */
1744         len = strlen(LEGACY_RECDIR_ENV_PREFIX) +
1745                 strlen(nfs4_recoverydir()) + 1 + HEXDIR_LEN;
1746 
1747         result = kmalloc(len, GFP_KERNEL);
1748         if (!result)
1749                 return result;
1750 
1751         copied = snprintf(result, len, LEGACY_RECDIR_ENV_PREFIX "%s/",
1752                                 nfs4_recoverydir());
1753         if (copied > (len - HEXDIR_LEN)) {
1754                 /* just return nothing if output will be truncated */
1755                 kfree(result);
1756                 return NULL;
1757         }
1758 
1759         copied = nfs4_make_rec_clidname(result + copied, name);
1760         if (copied) {
1761                 kfree(result);
1762                 return NULL;
1763         }
1764 
1765         return result;
1766 }
1767 
1768 static char *
1769 nfsd4_cltrack_client_has_session(struct nfs4_client *clp)
1770 {
1771         int copied;
1772         size_t len;
1773         char *result;
1774 
1775         /* prefix + Y/N character + terminating NULL */
1776         len = strlen(HAS_SESSION_ENV_PREFIX) + 1 + 1;
1777 
1778         result = kmalloc(len, GFP_KERNEL);
1779         if (!result)
1780                 return result;
1781 
1782         copied = snprintf(result, len, HAS_SESSION_ENV_PREFIX "%c",
1783                                 clp->cl_minorversion ? 'Y' : 'N');
1784         if (copied >= len) {
1785                 /* just return nothing if output was truncated */
1786                 kfree(result);
1787                 return NULL;
1788         }
1789 
1790         return result;
1791 }
1792 
1793 static char *
1794 nfsd4_cltrack_grace_start(time64_t grace_start)
1795 {
1796         int copied;
1797         size_t len;
1798         char *result;
1799 
1800         /* prefix + max width of int64_t string + terminating NULL */
1801         len = strlen(GRACE_START_ENV_PREFIX) + 22 + 1;
1802 
1803         result = kmalloc(len, GFP_KERNEL);
1804         if (!result)
1805                 return result;
1806 
1807         copied = snprintf(result, len, GRACE_START_ENV_PREFIX "%lld",
1808                                 grace_start);
1809         if (copied >= len) {
1810                 /* just return nothing if output was truncated */
1811                 kfree(result);
1812                 return NULL;
1813         }
1814 
1815         return result;
1816 }
1817 
1818 static int
1819 nfsd4_umh_cltrack_upcall(char *cmd, char *arg, char *env0, char *env1)
1820 {
1821         char *envp[3];
1822         char *argv[4];
1823         int ret;
1824 
1825         if (unlikely(!cltrack_prog[0])) {
1826                 dprintk("%s: cltrack_prog is disabled\n", __func__);
1827                 return -EACCES;
1828         }
1829 
1830         dprintk("%s: cmd: %s\n", __func__, cmd);
1831         dprintk("%s: arg: %s\n", __func__, arg ? arg : "(null)");
1832         dprintk("%s: env0: %s\n", __func__, env0 ? env0 : "(null)");
1833         dprintk("%s: env1: %s\n", __func__, env1 ? env1 : "(null)");
1834 
1835         envp[0] = env0;
1836         envp[1] = env1;
1837         envp[2] = NULL;
1838 
1839         argv[0] = (char *)cltrack_prog;
1840         argv[1] = cmd;
1841         argv[2] = arg;
1842         argv[3] = NULL;
1843 
1844         ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
1845         /*
1846          * Disable the upcall mechanism if we're getting an ENOENT or EACCES
1847          * error. The admin can re-enable it on the fly by using sysfs
1848          * once the problem has been fixed.
1849          */
1850         if (ret == -ENOENT || ret == -EACCES) {
1851                 dprintk("NFSD: %s was not found or isn't executable (%d). "
1852                         "Setting cltrack_prog to blank string!",
1853                         cltrack_prog, ret);
1854                 cltrack_prog[0] = '\0';
1855         }
1856         dprintk("%s: %s return value: %d\n", __func__, cltrack_prog, ret);
1857 
1858         return ret;
1859 }
1860 
1861 static char *
1862 bin_to_hex_dup(const unsigned char *src, int srclen)
1863 {
1864         char *buf;
1865 
1866         /* +1 for terminating NULL */
1867         buf = kzalloc((srclen * 2) + 1, GFP_KERNEL);
1868         if (!buf)
1869                 return buf;
1870 
1871         bin2hex(buf, src, srclen);
1872         return buf;
1873 }
1874 
1875 static int
1876 nfsd4_umh_cltrack_init(struct net *net)
1877 {
1878         int ret;
1879         struct nfsd_net *nn = net_generic(net, nfsd_net_id);
1880         char *grace_start = nfsd4_cltrack_grace_start(nn->boot_time);
1881 
1882         /* XXX: The usermode helper s not working in container yet. */
1883         if (net != &init_net) {
1884                 pr_warn("NFSD: attempt to initialize umh client tracking in a container ignored.\n");
1885                 kfree(grace_start);
1886                 return -EINVAL;
1887         }
1888 
1889         ret = nfsd4_umh_cltrack_upcall("init", NULL, grace_start, NULL);
1890         kfree(grace_start);
1891         if (!ret)
1892                 pr_info("NFSD: Using UMH upcall client tracking operations.\n");
1893         return ret;
1894 }
1895 
1896 static void
1897 nfsd4_cltrack_upcall_lock(struct nfs4_client *clp)
1898 {
1899         wait_on_bit_lock(&clp->cl_flags, NFSD4_CLIENT_UPCALL_LOCK,
1900                          TASK_UNINTERRUPTIBLE);
1901 }
1902 
1903 static void
1904 nfsd4_cltrack_upcall_unlock(struct nfs4_client *clp)
1905 {
1906         smp_mb__before_atomic();
1907         clear_bit(NFSD4_CLIENT_UPCALL_LOCK, &clp->cl_flags);
1908         smp_mb__after_atomic();
1909         wake_up_bit(&clp->cl_flags, NFSD4_CLIENT_UPCALL_LOCK);
1910 }
1911 
1912 static void
1913 nfsd4_umh_cltrack_create(struct nfs4_client *clp)
1914 {
1915         char *hexid, *has_session, *grace_start;
1916         struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
1917 
1918         /*
1919          * With v4.0 clients, there's little difference in outcome between a
1920          * create and check operation, and we can end up calling into this
1921          * function multiple times per client (once for each openowner). So,
1922          * for v4.0 clients skip upcalling once the client has been recorded
1923          * on stable storage.
1924          *
1925          * For v4.1+ clients, the outcome of the two operations is different,
1926          * so we must ensure that we upcall for the create operation. v4.1+
1927          * clients call this on RECLAIM_COMPLETE though, so we should only end
1928          * up doing a single create upcall per client.
1929          */
1930         if (clp->cl_minorversion == 0 &&
1931             test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
1932                 return;
1933 
1934         hexid = bin_to_hex_dup(clp->cl_name.data, clp->cl_name.len);
1935         if (!hexid) {
1936                 dprintk("%s: can't allocate memory for upcall!\n", __func__);
1937                 return;
1938         }
1939 
1940         has_session = nfsd4_cltrack_client_has_session(clp);
1941         grace_start = nfsd4_cltrack_grace_start(nn->boot_time);
1942 
1943         nfsd4_cltrack_upcall_lock(clp);
1944         if (!nfsd4_umh_cltrack_upcall("create", hexid, has_session, grace_start))
1945                 set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
1946         nfsd4_cltrack_upcall_unlock(clp);
1947 
1948         kfree(has_session);
1949         kfree(grace_start);
1950         kfree(hexid);
1951 }
1952 
1953 static void
1954 nfsd4_umh_cltrack_remove(struct nfs4_client *clp)
1955 {
1956         char *hexid;
1957 
1958         if (!test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
1959                 return;
1960 
1961         hexid = bin_to_hex_dup(clp->cl_name.data, clp->cl_name.len);
1962         if (!hexid) {
1963                 dprintk("%s: can't allocate memory for upcall!\n", __func__);
1964                 return;
1965         }
1966 
1967         nfsd4_cltrack_upcall_lock(clp);
1968         if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags) &&
1969             nfsd4_umh_cltrack_upcall("remove", hexid, NULL, NULL) == 0)
1970                 clear_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
1971         nfsd4_cltrack_upcall_unlock(clp);
1972 
1973         kfree(hexid);
1974 }
1975 
1976 static int
1977 nfsd4_umh_cltrack_check(struct nfs4_client *clp)
1978 {
1979         int ret;
1980         char *hexid, *has_session, *legacy;
1981 
1982         if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
1983                 return 0;
1984 
1985         hexid = bin_to_hex_dup(clp->cl_name.data, clp->cl_name.len);
1986         if (!hexid) {
1987                 dprintk("%s: can't allocate memory for upcall!\n", __func__);
1988                 return -ENOMEM;
1989         }
1990 
1991         has_session = nfsd4_cltrack_client_has_session(clp);
1992         legacy = nfsd4_cltrack_legacy_recdir(&clp->cl_name);
1993 
1994         nfsd4_cltrack_upcall_lock(clp);
1995         if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) {
1996                 ret = 0;
1997         } else {
1998                 ret = nfsd4_umh_cltrack_upcall("check", hexid, has_session, legacy);
1999                 if (ret == 0)
2000                         set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
2001         }
2002         nfsd4_cltrack_upcall_unlock(clp);
2003         kfree(has_session);
2004         kfree(legacy);
2005         kfree(hexid);
2006 
2007         return ret;
2008 }
2009 
2010 static void
2011 nfsd4_umh_cltrack_grace_done(struct nfsd_net *nn)
2012 {
2013         char *legacy;
2014         char timestr[22]; /* FIXME: better way to determine max size? */
2015 
2016         sprintf(timestr, "%lld", nn->boot_time);
2017         legacy = nfsd4_cltrack_legacy_topdir();
2018         nfsd4_umh_cltrack_upcall("gracedone", timestr, legacy, NULL);
2019         kfree(legacy);
2020 }
2021 
2022 static const struct nfsd4_client_tracking_ops nfsd4_umh_tracking_ops = {
2023         .init           = nfsd4_umh_cltrack_init,
2024         .exit           = NULL,
2025         .create         = nfsd4_umh_cltrack_create,
2026         .remove         = nfsd4_umh_cltrack_remove,
2027         .check          = nfsd4_umh_cltrack_check,
2028         .grace_done     = nfsd4_umh_cltrack_grace_done,
2029         .version        = 1,
2030         .msglen         = 0,
2031 };
2032 
2033 static inline int check_for_legacy_methods(int status, struct net *net)
2034 {
2035         struct nfsd_net *nn = net_generic(net, nfsd_net_id);
2036         struct path path;
2037 
2038         /*
2039          * Next, try the UMH upcall.
2040          */
2041         nn->client_tracking_ops = &nfsd4_umh_tracking_ops;
2042         status = nn->client_tracking_ops->init(net);
2043         if (!status)
2044                 return status;
2045 
2046         /*
2047          * Finally, See if the recoverydir exists and is a directory.
2048          * If it is, then use the legacy ops.
2049          */
2050         nn->client_tracking_ops = &nfsd4_legacy_tracking_ops;
2051         status = kern_path(nfs4_recoverydir(), LOOKUP_FOLLOW, &path);
2052         if (!status) {
2053                 status = !d_is_dir(path.dentry);
2054                 path_put(&path);
2055                 if (status)
2056                         return -ENOTDIR;
2057                 status = nn->client_tracking_ops->init(net);
2058         }
2059         return status;
2060 }
2061 #else
2062 static inline int check_for_legacy_methods(int status, struct net *net)
2063 {
2064         return status;
2065 }
2066 #endif /* CONFIG_LEGACY_NFSD_CLIENT_TRACKING */
2067 
2068 int
2069 nfsd4_client_tracking_init(struct net *net)
2070 {
2071         struct nfsd_net *nn = net_generic(net, nfsd_net_id);
2072         int status;
2073 
2074         /* just run the init if it the method is already decided */
2075         if (nn->client_tracking_ops)
2076                 goto do_init;
2077 
2078         /* First, try to use nfsdcld */
2079         nn->client_tracking_ops = &nfsd4_cld_tracking_ops;
2080         status = nn->client_tracking_ops->init(net);
2081         if (!status)
2082                 return status;
2083         if (status != -ETIMEDOUT) {
2084                 nn->client_tracking_ops = &nfsd4_cld_tracking_ops_v0;
2085                 status = nn->client_tracking_ops->init(net);
2086                 if (!status)
2087                         return status;
2088         }
2089 
2090         status = check_for_legacy_methods(status, net);
2091         if (status)
2092                 goto out;
2093 do_init:
2094         status = nn->client_tracking_ops->init(net);
2095 out:
2096         if (status) {
2097                 pr_warn("NFSD: Unable to initialize client recovery tracking! (%d)\n", status);
2098                 pr_warn("NFSD: Is nfsdcld running? If not, enable CONFIG_NFSD_LEGACY_CLIENT_TRACKING.\n");
2099                 nn->client_tracking_ops = NULL;
2100         }
2101         return status;
2102 }
2103 
2104 void
2105 nfsd4_client_tracking_exit(struct net *net)
2106 {
2107         struct nfsd_net *nn = net_generic(net, nfsd_net_id);
2108 
2109         if (nn->client_tracking_ops) {
2110                 if (nn->client_tracking_ops->exit)
2111                         nn->client_tracking_ops->exit(net);
2112                 nn->client_tracking_ops = NULL;
2113         }
2114 }
2115 
2116 void
2117 nfsd4_client_record_create(struct nfs4_client *clp)
2118 {
2119         struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
2120 
2121         if (nn->client_tracking_ops)
2122                 nn->client_tracking_ops->create(clp);
2123 }
2124 
2125 void
2126 nfsd4_client_record_remove(struct nfs4_client *clp)
2127 {
2128         struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
2129 
2130         if (nn->client_tracking_ops)
2131                 nn->client_tracking_ops->remove(clp);
2132 }
2133 
2134 int
2135 nfsd4_client_record_check(struct nfs4_client *clp)
2136 {
2137         struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
2138 
2139         if (nn->client_tracking_ops)
2140                 return nn->client_tracking_ops->check(clp);
2141 
2142         return -EOPNOTSUPP;
2143 }
2144 
2145 void
2146 nfsd4_record_grace_done(struct nfsd_net *nn)
2147 {
2148         if (nn->client_tracking_ops)
2149                 nn->client_tracking_ops->grace_done(nn);
2150 }
2151 
2152 static int
2153 rpc_pipefs_event(struct notifier_block *nb, unsigned long event, void *ptr)
2154 {
2155         struct super_block *sb = ptr;
2156         struct net *net = sb->s_fs_info;
2157         struct nfsd_net *nn = net_generic(net, nfsd_net_id);
2158         struct cld_net *cn = nn->cld_net;
2159         struct dentry *dentry;
2160         int ret = 0;
2161 
2162         if (!try_module_get(THIS_MODULE))
2163                 return 0;
2164 
2165         if (!cn) {
2166                 module_put(THIS_MODULE);
2167                 return 0;
2168         }
2169 
2170         switch (event) {
2171         case RPC_PIPEFS_MOUNT:
2172                 dentry = nfsd4_cld_register_sb(sb, cn->cn_pipe);
2173                 if (IS_ERR(dentry)) {
2174                         ret = PTR_ERR(dentry);
2175                         break;
2176                 }
2177                 cn->cn_pipe->dentry = dentry;
2178                 break;
2179         case RPC_PIPEFS_UMOUNT:
2180                 if (cn->cn_pipe->dentry)
2181                         nfsd4_cld_unregister_sb(cn->cn_pipe);
2182                 break;
2183         default:
2184                 ret = -ENOTSUPP;
2185                 break;
2186         }
2187         module_put(THIS_MODULE);
2188         return ret;
2189 }
2190 
2191 static struct notifier_block nfsd4_cld_block = {
2192         .notifier_call = rpc_pipefs_event,
2193 };
2194 
2195 int
2196 register_cld_notifier(void)
2197 {
2198         WARN_ON(!nfsd_net_id);
2199         return rpc_pipefs_notifier_register(&nfsd4_cld_block);
2200 }
2201 
2202 void
2203 unregister_cld_notifier(void)
2204 {
2205         rpc_pipefs_notifier_unregister(&nfsd4_cld_block);
2206 }
2207 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php