nfs4recover.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984
  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. #include <linux/file.h>
  35. #include <linux/slab.h>
  36. #include <linux/namei.h>
  37. #include <linux/crypto.h>
  38. #include <linux/sched.h>
  39. #include <linux/fs.h>
  40. #include <net/net_namespace.h>
  41. #include <linux/sunrpc/rpc_pipe_fs.h>
  42. #include <linux/sunrpc/clnt.h>
  43. #include <linux/nfsd/cld.h>
  44. #include "nfsd.h"
  45. #include "state.h"
  46. #include "vfs.h"
  47. #include "netns.h"
  48. #define NFSDDBG_FACILITY NFSDDBG_PROC
  49. /* Declarations */
  50. struct nfsd4_client_tracking_ops {
  51. int (*init)(struct net *);
  52. void (*exit)(struct net *);
  53. void (*create)(struct nfs4_client *);
  54. void (*remove)(struct nfs4_client *);
  55. int (*check)(struct nfs4_client *);
  56. void (*grace_done)(struct net *, time_t);
  57. };
  58. /* Globals */
  59. static struct file *rec_file;
  60. static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery";
  61. static struct nfsd4_client_tracking_ops *client_tracking_ops;
  62. static int
  63. nfs4_save_creds(const struct cred **original_creds)
  64. {
  65. struct cred *new;
  66. new = prepare_creds();
  67. if (!new)
  68. return -ENOMEM;
  69. new->fsuid = 0;
  70. new->fsgid = 0;
  71. *original_creds = override_creds(new);
  72. put_cred(new);
  73. return 0;
  74. }
  75. static void
  76. nfs4_reset_creds(const struct cred *original)
  77. {
  78. revert_creds(original);
  79. }
  80. static void
  81. md5_to_hex(char *out, char *md5)
  82. {
  83. int i;
  84. for (i=0; i<16; i++) {
  85. unsigned char c = md5[i];
  86. *out++ = '0' + ((c&0xf0)>>4) + (c>=0xa0)*('a'-'9'-1);
  87. *out++ = '0' + (c&0x0f) + ((c&0x0f)>=0x0a)*('a'-'9'-1);
  88. }
  89. *out = '\0';
  90. }
  91. __be32
  92. nfs4_make_rec_clidname(char *dname, struct xdr_netobj *clname)
  93. {
  94. struct xdr_netobj cksum;
  95. struct hash_desc desc;
  96. struct scatterlist sg;
  97. __be32 status = nfserr_jukebox;
  98. dprintk("NFSD: nfs4_make_rec_clidname for %.*s\n",
  99. clname->len, clname->data);
  100. desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
  101. desc.tfm = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC);
  102. if (IS_ERR(desc.tfm))
  103. goto out_no_tfm;
  104. cksum.len = crypto_hash_digestsize(desc.tfm);
  105. cksum.data = kmalloc(cksum.len, GFP_KERNEL);
  106. if (cksum.data == NULL)
  107. goto out;
  108. sg_init_one(&sg, clname->data, clname->len);
  109. if (crypto_hash_digest(&desc, &sg, sg.length, cksum.data))
  110. goto out;
  111. md5_to_hex(dname, cksum.data);
  112. status = nfs_ok;
  113. out:
  114. kfree(cksum.data);
  115. crypto_free_hash(desc.tfm);
  116. out_no_tfm:
  117. return status;
  118. }
  119. static void
  120. nfsd4_create_clid_dir(struct nfs4_client *clp)
  121. {
  122. const struct cred *original_cred;
  123. char *dname = clp->cl_recdir;
  124. struct dentry *dir, *dentry;
  125. int status;
  126. dprintk("NFSD: nfsd4_create_clid_dir for \"%s\"\n", dname);
  127. if (test_and_set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
  128. return;
  129. if (!rec_file)
  130. return;
  131. status = nfs4_save_creds(&original_cred);
  132. if (status < 0)
  133. return;
  134. dir = rec_file->f_path.dentry;
  135. /* lock the parent */
  136. mutex_lock(&dir->d_inode->i_mutex);
  137. dentry = lookup_one_len(dname, dir, HEXDIR_LEN-1);
  138. if (IS_ERR(dentry)) {
  139. status = PTR_ERR(dentry);
  140. goto out_unlock;
  141. }
  142. if (dentry->d_inode)
  143. /*
  144. * In the 4.1 case, where we're called from
  145. * reclaim_complete(), records from the previous reboot
  146. * may still be left, so this is OK.
  147. *
  148. * In the 4.0 case, we should never get here; but we may
  149. * as well be forgiving and just succeed silently.
  150. */
  151. goto out_put;
  152. status = mnt_want_write_file(rec_file);
  153. if (status)
  154. goto out_put;
  155. status = vfs_mkdir(dir->d_inode, dentry, S_IRWXU);
  156. mnt_drop_write_file(rec_file);
  157. out_put:
  158. dput(dentry);
  159. out_unlock:
  160. mutex_unlock(&dir->d_inode->i_mutex);
  161. if (status == 0)
  162. vfs_fsync(rec_file, 0);
  163. else
  164. printk(KERN_ERR "NFSD: failed to write recovery record"
  165. " (err %d); please check that %s exists"
  166. " and is writeable", status,
  167. user_recovery_dirname);
  168. nfs4_reset_creds(original_cred);
  169. }
  170. typedef int (recdir_func)(struct dentry *, struct dentry *);
  171. struct name_list {
  172. char name[HEXDIR_LEN];
  173. struct list_head list;
  174. };
  175. static int
  176. nfsd4_build_namelist(void *arg, const char *name, int namlen,
  177. loff_t offset, u64 ino, unsigned int d_type)
  178. {
  179. struct list_head *names = arg;
  180. struct name_list *entry;
  181. if (namlen != HEXDIR_LEN - 1)
  182. return 0;
  183. entry = kmalloc(sizeof(struct name_list), GFP_KERNEL);
  184. if (entry == NULL)
  185. return -ENOMEM;
  186. memcpy(entry->name, name, HEXDIR_LEN - 1);
  187. entry->name[HEXDIR_LEN - 1] = '\0';
  188. list_add(&entry->list, names);
  189. return 0;
  190. }
  191. static int
  192. nfsd4_list_rec_dir(recdir_func *f)
  193. {
  194. const struct cred *original_cred;
  195. struct dentry *dir = rec_file->f_path.dentry;
  196. LIST_HEAD(names);
  197. int status;
  198. status = nfs4_save_creds(&original_cred);
  199. if (status < 0)
  200. return status;
  201. status = vfs_llseek(rec_file, 0, SEEK_SET);
  202. if (status < 0) {
  203. nfs4_reset_creds(original_cred);
  204. return status;
  205. }
  206. status = vfs_readdir(rec_file, nfsd4_build_namelist, &names);
  207. mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT);
  208. while (!list_empty(&names)) {
  209. struct name_list *entry;
  210. entry = list_entry(names.next, struct name_list, list);
  211. if (!status) {
  212. struct dentry *dentry;
  213. dentry = lookup_one_len(entry->name, dir, HEXDIR_LEN-1);
  214. if (IS_ERR(dentry)) {
  215. status = PTR_ERR(dentry);
  216. break;
  217. }
  218. status = f(dir, dentry);
  219. dput(dentry);
  220. }
  221. list_del(&entry->list);
  222. kfree(entry);
  223. }
  224. mutex_unlock(&dir->d_inode->i_mutex);
  225. nfs4_reset_creds(original_cred);
  226. return status;
  227. }
  228. static int
  229. nfsd4_unlink_clid_dir(char *name, int namlen)
  230. {
  231. struct dentry *dir, *dentry;
  232. int status;
  233. dprintk("NFSD: nfsd4_unlink_clid_dir. name %.*s\n", namlen, name);
  234. dir = rec_file->f_path.dentry;
  235. mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT);
  236. dentry = lookup_one_len(name, dir, namlen);
  237. if (IS_ERR(dentry)) {
  238. status = PTR_ERR(dentry);
  239. goto out_unlock;
  240. }
  241. status = -ENOENT;
  242. if (!dentry->d_inode)
  243. goto out;
  244. status = vfs_rmdir(dir->d_inode, dentry);
  245. out:
  246. dput(dentry);
  247. out_unlock:
  248. mutex_unlock(&dir->d_inode->i_mutex);
  249. return status;
  250. }
  251. static void
  252. nfsd4_remove_clid_dir(struct nfs4_client *clp)
  253. {
  254. const struct cred *original_cred;
  255. int status;
  256. if (!rec_file || !test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
  257. return;
  258. status = mnt_want_write_file(rec_file);
  259. if (status)
  260. goto out;
  261. clear_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
  262. status = nfs4_save_creds(&original_cred);
  263. if (status < 0)
  264. goto out;
  265. status = nfsd4_unlink_clid_dir(clp->cl_recdir, HEXDIR_LEN-1);
  266. nfs4_reset_creds(original_cred);
  267. if (status == 0)
  268. vfs_fsync(rec_file, 0);
  269. mnt_drop_write_file(rec_file);
  270. out:
  271. if (status)
  272. printk("NFSD: Failed to remove expired client state directory"
  273. " %.*s\n", HEXDIR_LEN, clp->cl_recdir);
  274. }
  275. static int
  276. purge_old(struct dentry *parent, struct dentry *child)
  277. {
  278. int status;
  279. if (nfs4_has_reclaimed_state(child->d_name.name, false))
  280. return 0;
  281. status = vfs_rmdir(parent->d_inode, child);
  282. if (status)
  283. printk("failed to remove client recovery directory %s\n",
  284. child->d_name.name);
  285. /* Keep trying, success or failure: */
  286. return 0;
  287. }
  288. static void
  289. nfsd4_recdir_purge_old(struct net *net, time_t boot_time)
  290. {
  291. int status;
  292. if (!rec_file)
  293. return;
  294. status = mnt_want_write_file(rec_file);
  295. if (status)
  296. goto out;
  297. status = nfsd4_list_rec_dir(purge_old);
  298. if (status == 0)
  299. vfs_fsync(rec_file, 0);
  300. mnt_drop_write_file(rec_file);
  301. out:
  302. if (status)
  303. printk("nfsd4: failed to purge old clients from recovery"
  304. " directory %s\n", rec_file->f_path.dentry->d_name.name);
  305. }
  306. static int
  307. load_recdir(struct dentry *parent, struct dentry *child)
  308. {
  309. if (child->d_name.len != HEXDIR_LEN - 1) {
  310. printk("nfsd4: illegal name %s in recovery directory\n",
  311. child->d_name.name);
  312. /* Keep trying; maybe the others are OK: */
  313. return 0;
  314. }
  315. nfs4_client_to_reclaim(child->d_name.name);
  316. return 0;
  317. }
  318. static int
  319. nfsd4_recdir_load(void) {
  320. int status;
  321. if (!rec_file)
  322. return 0;
  323. status = nfsd4_list_rec_dir(load_recdir);
  324. if (status)
  325. printk("nfsd4: failed loading clients from recovery"
  326. " directory %s\n", rec_file->f_path.dentry->d_name.name);
  327. return status;
  328. }
  329. /*
  330. * Hold reference to the recovery directory.
  331. */
  332. static int
  333. nfsd4_init_recdir(void)
  334. {
  335. const struct cred *original_cred;
  336. int status;
  337. printk("NFSD: Using %s as the NFSv4 state recovery directory\n",
  338. user_recovery_dirname);
  339. BUG_ON(rec_file);
  340. status = nfs4_save_creds(&original_cred);
  341. if (status < 0) {
  342. printk("NFSD: Unable to change credentials to find recovery"
  343. " directory: error %d\n",
  344. status);
  345. return status;
  346. }
  347. rec_file = filp_open(user_recovery_dirname, O_RDONLY | O_DIRECTORY, 0);
  348. if (IS_ERR(rec_file)) {
  349. printk("NFSD: unable to find recovery directory %s\n",
  350. user_recovery_dirname);
  351. status = PTR_ERR(rec_file);
  352. rec_file = NULL;
  353. }
  354. nfs4_reset_creds(original_cred);
  355. return status;
  356. }
  357. static int
  358. nfsd4_load_reboot_recovery_data(struct net *net)
  359. {
  360. int status;
  361. nfs4_lock_state();
  362. status = nfsd4_init_recdir();
  363. if (!status)
  364. status = nfsd4_recdir_load();
  365. nfs4_unlock_state();
  366. if (status)
  367. printk(KERN_ERR "NFSD: Failure reading reboot recovery data\n");
  368. return status;
  369. }
  370. static void
  371. nfsd4_shutdown_recdir(void)
  372. {
  373. if (!rec_file)
  374. return;
  375. fput(rec_file);
  376. rec_file = NULL;
  377. }
  378. static void
  379. nfsd4_legacy_tracking_exit(struct net *net)
  380. {
  381. nfs4_release_reclaim();
  382. nfsd4_shutdown_recdir();
  383. }
  384. /*
  385. * Change the NFSv4 recovery directory to recdir.
  386. */
  387. int
  388. nfs4_reset_recoverydir(char *recdir)
  389. {
  390. int status;
  391. struct path path;
  392. status = kern_path(recdir, LOOKUP_FOLLOW, &path);
  393. if (status)
  394. return status;
  395. status = -ENOTDIR;
  396. if (S_ISDIR(path.dentry->d_inode->i_mode)) {
  397. strcpy(user_recovery_dirname, recdir);
  398. status = 0;
  399. }
  400. path_put(&path);
  401. return status;
  402. }
  403. char *
  404. nfs4_recoverydir(void)
  405. {
  406. return user_recovery_dirname;
  407. }
  408. static int
  409. nfsd4_check_legacy_client(struct nfs4_client *clp)
  410. {
  411. /* did we already find that this client is stable? */
  412. if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
  413. return 0;
  414. /* look for it in the reclaim hashtable otherwise */
  415. if (nfsd4_find_reclaim_client(clp)) {
  416. set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
  417. return 0;
  418. }
  419. return -ENOENT;
  420. }
  421. static struct nfsd4_client_tracking_ops nfsd4_legacy_tracking_ops = {
  422. .init = nfsd4_load_reboot_recovery_data,
  423. .exit = nfsd4_legacy_tracking_exit,
  424. .create = nfsd4_create_clid_dir,
  425. .remove = nfsd4_remove_clid_dir,
  426. .check = nfsd4_check_legacy_client,
  427. .grace_done = nfsd4_recdir_purge_old,
  428. };
  429. /* Globals */
  430. #define NFSD_PIPE_DIR "nfsd"
  431. #define NFSD_CLD_PIPE "cld"
  432. /* per-net-ns structure for holding cld upcall info */
  433. struct cld_net {
  434. struct rpc_pipe *cn_pipe;
  435. spinlock_t cn_lock;
  436. struct list_head cn_list;
  437. unsigned int cn_xid;
  438. };
  439. struct cld_upcall {
  440. struct list_head cu_list;
  441. struct cld_net *cu_net;
  442. struct task_struct *cu_task;
  443. struct cld_msg cu_msg;
  444. };
  445. static int
  446. __cld_pipe_upcall(struct rpc_pipe *pipe, struct cld_msg *cmsg)
  447. {
  448. int ret;
  449. struct rpc_pipe_msg msg;
  450. memset(&msg, 0, sizeof(msg));
  451. msg.data = cmsg;
  452. msg.len = sizeof(*cmsg);
  453. /*
  454. * Set task state before we queue the upcall. That prevents
  455. * wake_up_process in the downcall from racing with schedule.
  456. */
  457. set_current_state(TASK_UNINTERRUPTIBLE);
  458. ret = rpc_queue_upcall(pipe, &msg);
  459. if (ret < 0) {
  460. set_current_state(TASK_RUNNING);
  461. goto out;
  462. }
  463. schedule();
  464. set_current_state(TASK_RUNNING);
  465. if (msg.errno < 0)
  466. ret = msg.errno;
  467. out:
  468. return ret;
  469. }
  470. static int
  471. cld_pipe_upcall(struct rpc_pipe *pipe, struct cld_msg *cmsg)
  472. {
  473. int ret;
  474. /*
  475. * -EAGAIN occurs when pipe is closed and reopened while there are
  476. * upcalls queued.
  477. */
  478. do {
  479. ret = __cld_pipe_upcall(pipe, cmsg);
  480. } while (ret == -EAGAIN);
  481. return ret;
  482. }
  483. static ssize_t
  484. cld_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
  485. {
  486. struct cld_upcall *tmp, *cup;
  487. struct cld_msg *cmsg = (struct cld_msg *)src;
  488. uint32_t xid;
  489. struct nfsd_net *nn = net_generic(filp->f_dentry->d_sb->s_fs_info,
  490. nfsd_net_id);
  491. struct cld_net *cn = nn->cld_net;
  492. if (mlen != sizeof(*cmsg)) {
  493. dprintk("%s: got %lu bytes, expected %lu\n", __func__, mlen,
  494. sizeof(*cmsg));
  495. return -EINVAL;
  496. }
  497. /* copy just the xid so we can try to find that */
  498. if (copy_from_user(&xid, &cmsg->cm_xid, sizeof(xid)) != 0) {
  499. dprintk("%s: error when copying xid from userspace", __func__);
  500. return -EFAULT;
  501. }
  502. /* walk the list and find corresponding xid */
  503. cup = NULL;
  504. spin_lock(&cn->cn_lock);
  505. list_for_each_entry(tmp, &cn->cn_list, cu_list) {
  506. if (get_unaligned(&tmp->cu_msg.cm_xid) == xid) {
  507. cup = tmp;
  508. list_del_init(&cup->cu_list);
  509. break;
  510. }
  511. }
  512. spin_unlock(&cn->cn_lock);
  513. /* couldn't find upcall? */
  514. if (!cup) {
  515. dprintk("%s: couldn't find upcall -- xid=%u\n", __func__,
  516. cup->cu_msg.cm_xid);
  517. return -EINVAL;
  518. }
  519. if (copy_from_user(&cup->cu_msg, src, mlen) != 0)
  520. return -EFAULT;
  521. wake_up_process(cup->cu_task);
  522. return mlen;
  523. }
  524. static void
  525. cld_pipe_destroy_msg(struct rpc_pipe_msg *msg)
  526. {
  527. struct cld_msg *cmsg = msg->data;
  528. struct cld_upcall *cup = container_of(cmsg, struct cld_upcall,
  529. cu_msg);
  530. /* errno >= 0 means we got a downcall */
  531. if (msg->errno >= 0)
  532. return;
  533. wake_up_process(cup->cu_task);
  534. }
  535. static const struct rpc_pipe_ops cld_upcall_ops = {
  536. .upcall = rpc_pipe_generic_upcall,
  537. .downcall = cld_pipe_downcall,
  538. .destroy_msg = cld_pipe_destroy_msg,
  539. };
  540. static struct dentry *
  541. nfsd4_cld_register_sb(struct super_block *sb, struct rpc_pipe *pipe)
  542. {
  543. struct dentry *dir, *dentry;
  544. dir = rpc_d_lookup_sb(sb, NFSD_PIPE_DIR);
  545. if (dir == NULL)
  546. return ERR_PTR(-ENOENT);
  547. dentry = rpc_mkpipe_dentry(dir, NFSD_CLD_PIPE, NULL, pipe);
  548. dput(dir);
  549. return dentry;
  550. }
  551. static void
  552. nfsd4_cld_unregister_sb(struct rpc_pipe *pipe)
  553. {
  554. if (pipe->dentry)
  555. rpc_unlink(pipe->dentry);
  556. }
  557. static struct dentry *
  558. nfsd4_cld_register_net(struct net *net, struct rpc_pipe *pipe)
  559. {
  560. struct super_block *sb;
  561. struct dentry *dentry;
  562. sb = rpc_get_sb_net(net);
  563. if (!sb)
  564. return NULL;
  565. dentry = nfsd4_cld_register_sb(sb, pipe);
  566. rpc_put_sb_net(net);
  567. return dentry;
  568. }
  569. static void
  570. nfsd4_cld_unregister_net(struct net *net, struct rpc_pipe *pipe)
  571. {
  572. struct super_block *sb;
  573. sb = rpc_get_sb_net(net);
  574. if (sb) {
  575. nfsd4_cld_unregister_sb(pipe);
  576. rpc_put_sb_net(net);
  577. }
  578. }
  579. /* Initialize rpc_pipefs pipe for communication with client tracking daemon */
  580. static int
  581. nfsd4_init_cld_pipe(struct net *net)
  582. {
  583. int ret;
  584. struct dentry *dentry;
  585. struct nfsd_net *nn = net_generic(net, nfsd_net_id);
  586. struct cld_net *cn;
  587. if (nn->cld_net)
  588. return 0;
  589. cn = kzalloc(sizeof(*cn), GFP_KERNEL);
  590. if (!cn) {
  591. ret = -ENOMEM;
  592. goto err;
  593. }
  594. cn->cn_pipe = rpc_mkpipe_data(&cld_upcall_ops, RPC_PIPE_WAIT_FOR_OPEN);
  595. if (IS_ERR(cn->cn_pipe)) {
  596. ret = PTR_ERR(cn->cn_pipe);
  597. goto err;
  598. }
  599. spin_lock_init(&cn->cn_lock);
  600. INIT_LIST_HEAD(&cn->cn_list);
  601. dentry = nfsd4_cld_register_net(net, cn->cn_pipe);
  602. if (IS_ERR(dentry)) {
  603. ret = PTR_ERR(dentry);
  604. goto err_destroy_data;
  605. }
  606. cn->cn_pipe->dentry = dentry;
  607. nn->cld_net = cn;
  608. return 0;
  609. err_destroy_data:
  610. rpc_destroy_pipe_data(cn->cn_pipe);
  611. err:
  612. kfree(cn);
  613. printk(KERN_ERR "NFSD: unable to create nfsdcld upcall pipe (%d)\n",
  614. ret);
  615. return ret;
  616. }
  617. static void
  618. nfsd4_remove_cld_pipe(struct net *net)
  619. {
  620. struct nfsd_net *nn = net_generic(net, nfsd_net_id);
  621. struct cld_net *cn = nn->cld_net;
  622. nfsd4_cld_unregister_net(net, cn->cn_pipe);
  623. rpc_destroy_pipe_data(cn->cn_pipe);
  624. kfree(nn->cld_net);
  625. nn->cld_net = NULL;
  626. }
  627. static struct cld_upcall *
  628. alloc_cld_upcall(struct cld_net *cn)
  629. {
  630. struct cld_upcall *new, *tmp;
  631. new = kzalloc(sizeof(*new), GFP_KERNEL);
  632. if (!new)
  633. return new;
  634. /* FIXME: hard cap on number in flight? */
  635. restart_search:
  636. spin_lock(&cn->cn_lock);
  637. list_for_each_entry(tmp, &cn->cn_list, cu_list) {
  638. if (tmp->cu_msg.cm_xid == cn->cn_xid) {
  639. cn->cn_xid++;
  640. spin_unlock(&cn->cn_lock);
  641. goto restart_search;
  642. }
  643. }
  644. new->cu_task = current;
  645. new->cu_msg.cm_vers = CLD_UPCALL_VERSION;
  646. put_unaligned(cn->cn_xid++, &new->cu_msg.cm_xid);
  647. new->cu_net = cn;
  648. list_add(&new->cu_list, &cn->cn_list);
  649. spin_unlock(&cn->cn_lock);
  650. dprintk("%s: allocated xid %u\n", __func__, new->cu_msg.cm_xid);
  651. return new;
  652. }
  653. static void
  654. free_cld_upcall(struct cld_upcall *victim)
  655. {
  656. struct cld_net *cn = victim->cu_net;
  657. spin_lock(&cn->cn_lock);
  658. list_del(&victim->cu_list);
  659. spin_unlock(&cn->cn_lock);
  660. kfree(victim);
  661. }
  662. /* Ask daemon to create a new record */
  663. static void
  664. nfsd4_cld_create(struct nfs4_client *clp)
  665. {
  666. int ret;
  667. struct cld_upcall *cup;
  668. /* FIXME: determine net from clp */
  669. struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id);
  670. struct cld_net *cn = nn->cld_net;
  671. /* Don't upcall if it's already stored */
  672. if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
  673. return;
  674. cup = alloc_cld_upcall(cn);
  675. if (!cup) {
  676. ret = -ENOMEM;
  677. goto out_err;
  678. }
  679. cup->cu_msg.cm_cmd = Cld_Create;
  680. cup->cu_msg.cm_u.cm_name.cn_len = clp->cl_name.len;
  681. memcpy(cup->cu_msg.cm_u.cm_name.cn_id, clp->cl_name.data,
  682. clp->cl_name.len);
  683. ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg);
  684. if (!ret) {
  685. ret = cup->cu_msg.cm_status;
  686. set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
  687. }
  688. free_cld_upcall(cup);
  689. out_err:
  690. if (ret)
  691. printk(KERN_ERR "NFSD: Unable to create client "
  692. "record on stable storage: %d\n", ret);
  693. }
  694. /* Ask daemon to create a new record */
  695. static void
  696. nfsd4_cld_remove(struct nfs4_client *clp)
  697. {
  698. int ret;
  699. struct cld_upcall *cup;
  700. /* FIXME: determine net from clp */
  701. struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id);
  702. struct cld_net *cn = nn->cld_net;
  703. /* Don't upcall if it's already removed */
  704. if (!test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
  705. return;
  706. cup = alloc_cld_upcall(cn);
  707. if (!cup) {
  708. ret = -ENOMEM;
  709. goto out_err;
  710. }
  711. cup->cu_msg.cm_cmd = Cld_Remove;
  712. cup->cu_msg.cm_u.cm_name.cn_len = clp->cl_name.len;
  713. memcpy(cup->cu_msg.cm_u.cm_name.cn_id, clp->cl_name.data,
  714. clp->cl_name.len);
  715. ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg);
  716. if (!ret) {
  717. ret = cup->cu_msg.cm_status;
  718. clear_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
  719. }
  720. free_cld_upcall(cup);
  721. out_err:
  722. if (ret)
  723. printk(KERN_ERR "NFSD: Unable to remove client "
  724. "record from stable storage: %d\n", ret);
  725. }
  726. /* Check for presence of a record, and update its timestamp */
  727. static int
  728. nfsd4_cld_check(struct nfs4_client *clp)
  729. {
  730. int ret;
  731. struct cld_upcall *cup;
  732. /* FIXME: determine net from clp */
  733. struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id);
  734. struct cld_net *cn = nn->cld_net;
  735. /* Don't upcall if one was already stored during this grace pd */
  736. if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
  737. return 0;
  738. cup = alloc_cld_upcall(cn);
  739. if (!cup) {
  740. printk(KERN_ERR "NFSD: Unable to check client record on "
  741. "stable storage: %d\n", -ENOMEM);
  742. return -ENOMEM;
  743. }
  744. cup->cu_msg.cm_cmd = Cld_Check;
  745. cup->cu_msg.cm_u.cm_name.cn_len = clp->cl_name.len;
  746. memcpy(cup->cu_msg.cm_u.cm_name.cn_id, clp->cl_name.data,
  747. clp->cl_name.len);
  748. ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg);
  749. if (!ret) {
  750. ret = cup->cu_msg.cm_status;
  751. set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
  752. }
  753. free_cld_upcall(cup);
  754. return ret;
  755. }
  756. static void
  757. nfsd4_cld_grace_done(struct net *net, time_t boot_time)
  758. {
  759. int ret;
  760. struct cld_upcall *cup;
  761. struct nfsd_net *nn = net_generic(net, nfsd_net_id);
  762. struct cld_net *cn = nn->cld_net;
  763. cup = alloc_cld_upcall(cn);
  764. if (!cup) {
  765. ret = -ENOMEM;
  766. goto out_err;
  767. }
  768. cup->cu_msg.cm_cmd = Cld_GraceDone;
  769. cup->cu_msg.cm_u.cm_gracetime = (int64_t)boot_time;
  770. ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg);
  771. if (!ret)
  772. ret = cup->cu_msg.cm_status;
  773. free_cld_upcall(cup);
  774. out_err:
  775. if (ret)
  776. printk(KERN_ERR "NFSD: Unable to end grace period: %d\n", ret);
  777. }
  778. static struct nfsd4_client_tracking_ops nfsd4_cld_tracking_ops = {
  779. .init = nfsd4_init_cld_pipe,
  780. .exit = nfsd4_remove_cld_pipe,
  781. .create = nfsd4_cld_create,
  782. .remove = nfsd4_cld_remove,
  783. .check = nfsd4_cld_check,
  784. .grace_done = nfsd4_cld_grace_done,
  785. };
  786. int
  787. nfsd4_client_tracking_init(struct net *net)
  788. {
  789. int status;
  790. struct path path;
  791. if (!client_tracking_ops) {
  792. client_tracking_ops = &nfsd4_cld_tracking_ops;
  793. status = kern_path(nfs4_recoverydir(), LOOKUP_FOLLOW, &path);
  794. if (!status) {
  795. if (S_ISDIR(path.dentry->d_inode->i_mode))
  796. client_tracking_ops =
  797. &nfsd4_legacy_tracking_ops;
  798. path_put(&path);
  799. }
  800. }
  801. status = client_tracking_ops->init(net);
  802. if (status) {
  803. printk(KERN_WARNING "NFSD: Unable to initialize client "
  804. "recovery tracking! (%d)\n", status);
  805. client_tracking_ops = NULL;
  806. }
  807. return status;
  808. }
  809. void
  810. nfsd4_client_tracking_exit(struct net *net)
  811. {
  812. if (client_tracking_ops) {
  813. client_tracking_ops->exit(net);
  814. client_tracking_ops = NULL;
  815. }
  816. }
  817. void
  818. nfsd4_client_record_create(struct nfs4_client *clp)
  819. {
  820. if (client_tracking_ops)
  821. client_tracking_ops->create(clp);
  822. }
  823. void
  824. nfsd4_client_record_remove(struct nfs4_client *clp)
  825. {
  826. if (client_tracking_ops)
  827. client_tracking_ops->remove(clp);
  828. }
  829. int
  830. nfsd4_client_record_check(struct nfs4_client *clp)
  831. {
  832. if (client_tracking_ops)
  833. return client_tracking_ops->check(clp);
  834. return -EOPNOTSUPP;
  835. }
  836. void
  837. nfsd4_record_grace_done(struct net *net, time_t boot_time)
  838. {
  839. if (client_tracking_ops)
  840. client_tracking_ops->grace_done(net, boot_time);
  841. }