nfsctl.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:8k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * linux/fs/nfsd/nfsctl.c
  3.  *
  4.  * Syscall interface to knfsd.
  5.  *
  6.  * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
  7.  */
  8. #include <linux/config.h>
  9. #include <linux/module.h>
  10. #include <linux/version.h>
  11. #include <linux/linkage.h>
  12. #include <linux/sched.h>
  13. #include <linux/errno.h>
  14. #include <linux/fs.h>
  15. #include <linux/fcntl.h>
  16. #include <linux/net.h>
  17. #include <linux/in.h>
  18. #include <linux/unistd.h>
  19. #include <linux/slab.h>
  20. #include <linux/proc_fs.h>
  21. #include <linux/nfs.h>
  22. #include <linux/sunrpc/svc.h>
  23. #include <linux/nfsd/nfsd.h>
  24. #include <linux/nfsd/cache.h>
  25. #include <linux/nfsd/xdr.h>
  26. #include <linux/nfsd/syscall.h>
  27. #include <asm/uaccess.h>
  28. #include <linux/smp.h>
  29. #include <linux/smp_lock.h>
  30. static int nfsctl_svc(struct nfsctl_svc *data);
  31. static int nfsctl_addclient(struct nfsctl_client *data);
  32. static int nfsctl_delclient(struct nfsctl_client *data);
  33. static int nfsctl_export(struct nfsctl_export *data);
  34. static int nfsctl_unexport(struct nfsctl_export *data);
  35. static int nfsctl_getfh(struct nfsctl_fhparm *, __u8 *);
  36. static int nfsctl_getfd(struct nfsctl_fdparm *, __u8 *);
  37. static int nfsctl_getfs(struct nfsctl_fsparm *, struct knfsd_fh *);
  38. #ifdef notyet
  39. static int nfsctl_ugidupdate(struct nfsctl_ugidmap *data);
  40. #endif
  41. static int initialized;
  42. int exp_procfs_exports(char *buffer, char **start, off_t offset,
  43.                              int length, int *eof, void *data);
  44. void proc_export_init(void)
  45. {
  46. if (!proc_mkdir("fs/nfs", 0))
  47. return;
  48. create_proc_read_entry("fs/nfs/exports", 0, 0, exp_procfs_exports,NULL);
  49. }
  50. /*
  51.  * Initialize nfsd
  52.  */
  53. static void
  54. nfsd_init(void)
  55. {
  56. nfsd_stat_init(); /* Statistics */
  57. nfsd_cache_init(); /* RPC reply cache */
  58. nfsd_export_init(); /* Exports table */
  59. nfsd_lockd_init(); /* lockd->nfsd callbacks */
  60. proc_export_init();
  61. initialized = 1;
  62. }
  63. static inline int
  64. nfsctl_svc(struct nfsctl_svc *data)
  65. {
  66. return nfsd_svc(data->svc_port, data->svc_nthreads);
  67. }
  68. static inline int
  69. nfsctl_addclient(struct nfsctl_client *data)
  70. {
  71. return exp_addclient(data);
  72. }
  73. static inline int
  74. nfsctl_delclient(struct nfsctl_client *data)
  75. {
  76. return exp_delclient(data);
  77. }
  78. static inline int
  79. nfsctl_export(struct nfsctl_export *data)
  80. {
  81. return exp_export(data);
  82. }
  83. static inline int
  84. nfsctl_unexport(struct nfsctl_export *data)
  85. {
  86. return exp_unexport(data);
  87. }
  88. #ifdef notyet
  89. static inline int
  90. nfsctl_ugidupdate(nfs_ugidmap *data)
  91. {
  92. return -EINVAL;
  93. }
  94. #endif
  95. static inline int
  96. nfsctl_getfs(struct nfsctl_fsparm *data, struct knfsd_fh *res)
  97. {
  98. struct sockaddr_in *sin;
  99. struct svc_client *clp;
  100. int err = 0;
  101. if (data->gd_addr.sa_family != AF_INET)
  102. return -EPROTONOSUPPORT;
  103. sin = (struct sockaddr_in *)&data->gd_addr;
  104. if (data->gd_maxlen > NFS3_FHSIZE)
  105. data->gd_maxlen = NFS3_FHSIZE;
  106. exp_readlock();
  107. if (!(clp = exp_getclient(sin)))
  108. err = -EPERM;
  109. else
  110. err = exp_rootfh(clp, 0, 0, data->gd_path, res, data->gd_maxlen);
  111. exp_unlock();
  112. return err;
  113. }
  114. static inline int
  115. nfsctl_getfd(struct nfsctl_fdparm *data, __u8 *res)
  116. {
  117. struct sockaddr_in *sin;
  118. struct svc_client *clp;
  119. int err = 0;
  120. struct knfsd_fh fh;
  121. if (data->gd_addr.sa_family != AF_INET)
  122. return -EPROTONOSUPPORT;
  123. if (data->gd_version < 2 || data->gd_version > NFSSVC_MAXVERS)
  124. return -EINVAL;
  125. sin = (struct sockaddr_in *)&data->gd_addr;
  126. exp_readlock();
  127. if (!(clp = exp_getclient(sin)))
  128. err = -EPERM;
  129. else
  130. err = exp_rootfh(clp, 0, 0, data->gd_path, &fh, NFS_FHSIZE);
  131. exp_unlock();
  132. if (err == 0) {
  133. if (fh.fh_size > NFS_FHSIZE)
  134. err = -EINVAL;
  135. else {
  136. memset(res,0, NFS_FHSIZE);
  137. memcpy(res, &fh.fh_base, fh.fh_size);
  138. }
  139. }
  140. return err;
  141. }
  142. static inline int
  143. nfsctl_getfh(struct nfsctl_fhparm *data, __u8 *res)
  144. {
  145. struct sockaddr_in *sin;
  146. struct svc_client *clp;
  147. int err = 0;
  148. struct knfsd_fh fh;
  149. if (data->gf_addr.sa_family != AF_INET)
  150. return -EPROTONOSUPPORT;
  151. if (data->gf_version < 2 || data->gf_version > NFSSVC_MAXVERS)
  152. return -EINVAL;
  153. sin = (struct sockaddr_in *)&data->gf_addr;
  154. exp_readlock();
  155. if (!(clp = exp_getclient(sin)))
  156. err = -EPERM;
  157. else
  158. err = exp_rootfh(clp, to_kdev_t(data->gf_dev), data->gf_ino, NULL, &fh, NFS_FHSIZE);
  159. exp_unlock();
  160. if (err == 0) {
  161. if (fh.fh_size > NFS_FHSIZE)
  162. err = -EINVAL;
  163. else {
  164. memset(res,0, NFS_FHSIZE);
  165. memcpy(res, &fh.fh_base, fh.fh_size);
  166. }
  167. }
  168. return err;
  169. }
  170. #ifdef CONFIG_NFSD
  171. #define handle_sys_nfsservctl sys_nfsservctl
  172. #endif
  173. static struct {
  174. int argsize, respsize;
  175. }  sizes[] = {
  176. /* NFSCTL_SVC        */ { sizeof(struct nfsctl_svc), 0 },
  177. /* NFSCTL_ADDCLIENT  */ { sizeof(struct nfsctl_client), 0},
  178. /* NFSCTL_DELCLIENT  */ { sizeof(struct nfsctl_client), 0},
  179. /* NFSCTL_EXPORT     */ { sizeof(struct nfsctl_export), 0},
  180. /* NFSCTL_UNEXPORT   */ { sizeof(struct nfsctl_export), 0},
  181. /* NFSCTL_UGIDUPDATE */ { sizeof(struct nfsctl_uidmap), 0},
  182. /* NFSCTL_GETFH      */ { sizeof(struct nfsctl_fhparm), NFS_FHSIZE},
  183. /* NFSCTL_GETFD      */ { sizeof(struct nfsctl_fdparm), NFS_FHSIZE},
  184. /* NFSCTL_GETFS      */ { sizeof(struct nfsctl_fsparm), sizeof(struct knfsd_fh)},
  185. };
  186. #define CMD_MAX (sizeof(sizes)/sizeof(sizes[0])-1)
  187. long
  188. asmlinkage handle_sys_nfsservctl(int cmd, void *opaque_argp, void *opaque_resp)
  189. {
  190. struct nfsctl_arg * argp = opaque_argp;
  191. union nfsctl_res * resp = opaque_resp;
  192. struct nfsctl_arg * arg = NULL;
  193. union nfsctl_res * res = NULL;
  194. int err;
  195. int argsize, respsize;
  196. MOD_INC_USE_COUNT;
  197. lock_kernel ();
  198. if (!initialized)
  199. nfsd_init();
  200. err = -EPERM;
  201. if (!capable(CAP_SYS_ADMIN)) {
  202. goto done;
  203. }
  204. err = -EINVAL;
  205. if (cmd<0 || cmd > CMD_MAX)
  206. goto done;
  207. err = -EFAULT;
  208. argsize = sizes[cmd].argsize + (int)&((struct nfsctl_arg *)0)->u;
  209. respsize = sizes[cmd].respsize; /* maximum */
  210. if (!access_ok(VERIFY_READ, argp, argsize)
  211.  || (resp && !access_ok(VERIFY_WRITE, resp, respsize))) {
  212. goto done;
  213. }
  214. err = -ENOMEM; /* ??? */
  215. if (!(arg = kmalloc(sizeof(*arg), GFP_USER)) ||
  216.     (resp && !(res = kmalloc(sizeof(*res), GFP_USER)))) {
  217. goto done;
  218. }
  219. err = -EINVAL;
  220. copy_from_user(arg, argp, argsize);
  221. if (arg->ca_version != NFSCTL_VERSION) {
  222. printk(KERN_WARNING "nfsd: incompatible version in syscall.n");
  223. goto done;
  224. }
  225. switch(cmd) {
  226. case NFSCTL_SVC:
  227. err = nfsctl_svc(&arg->ca_svc);
  228. break;
  229. case NFSCTL_ADDCLIENT:
  230. err = nfsctl_addclient(&arg->ca_client);
  231. break;
  232. case NFSCTL_DELCLIENT:
  233. err = nfsctl_delclient(&arg->ca_client);
  234. break;
  235. case NFSCTL_EXPORT:
  236. err = nfsctl_export(&arg->ca_export);
  237. break;
  238. case NFSCTL_UNEXPORT:
  239. err = nfsctl_unexport(&arg->ca_export);
  240. break;
  241. #ifdef notyet
  242. case NFSCTL_UGIDUPDATE:
  243. err = nfsctl_ugidupdate(&arg->ca_umap);
  244. break;
  245. #endif
  246. case NFSCTL_GETFH:
  247. err = nfsctl_getfh(&arg->ca_getfh, res->cr_getfh);
  248. break;
  249. case NFSCTL_GETFD:
  250. err = nfsctl_getfd(&arg->ca_getfd, res->cr_getfh);
  251. break;
  252. case NFSCTL_GETFS:
  253. err = nfsctl_getfs(&arg->ca_getfs, &res->cr_getfs);
  254. respsize = res->cr_getfs.fh_size+ (int)&((struct knfsd_fh*)0)->fh_base;
  255. break;
  256. default:
  257. err = -EINVAL;
  258. }
  259. if (!err && resp && respsize)
  260. copy_to_user(resp, res, respsize);
  261. done:
  262. if (arg)
  263. kfree(arg);
  264. if (res)
  265. kfree(res);
  266. unlock_kernel ();
  267. MOD_DEC_USE_COUNT;
  268. return err;
  269. }
  270. #ifdef MODULE
  271. /* New-style module support since 2.1.18 */
  272. EXPORT_NO_SYMBOLS;
  273. MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>");
  274. MODULE_LICENSE("GPL");
  275. struct nfsd_linkage nfsd_linkage_s = {
  276. do_nfsservctl: handle_sys_nfsservctl,
  277. };
  278. /*
  279.  * Initialize the module
  280.  */
  281. int
  282. init_module(void)
  283. {
  284. printk(KERN_INFO "Installing knfsd (copyright (C) 1996 okir@monad.swb.de).n");
  285. nfsd_linkage = &nfsd_linkage_s;
  286. return 0;
  287. }
  288. /*
  289.  * Clean up the mess before unloading the module
  290.  */
  291. void
  292. cleanup_module(void)
  293. {
  294. nfsd_linkage = NULL;
  295. nfsd_export_shutdown();
  296. nfsd_cache_shutdown();
  297. remove_proc_entry("fs/nfs/exports", NULL);
  298. remove_proc_entry("fs/nfs", NULL);
  299. nfsd_stat_shutdown();
  300. nfsd_lockd_shutdown();
  301. }
  302. #endif