fid.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. /*
  2. * V9FS FID Management
  3. *
  4. * Copyright (C) 2007 by Latchesar Ionkov <lucho@ionkov.net>
  5. * Copyright (C) 2005, 2006 by Eric Van Hensbergen <ericvh@gmail.com>
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License version 2
  9. * as published by the Free Software Foundation.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to:
  18. * Free Software Foundation
  19. * 51 Franklin Street, Fifth Floor
  20. * Boston, MA 02111-1301 USA
  21. *
  22. */
  23. #include <linux/module.h>
  24. #include <linux/errno.h>
  25. #include <linux/fs.h>
  26. #include <linux/sched.h>
  27. #include <linux/idr.h>
  28. #include <net/9p/9p.h>
  29. #include <net/9p/client.h>
  30. #include "v9fs.h"
  31. #include "v9fs_vfs.h"
  32. #include "fid.h"
  33. /**
  34. * v9fs_fid_add - add a fid to a dentry
  35. * @dentry: dentry that the fid is being added to
  36. * @fid: fid to add
  37. *
  38. */
  39. int v9fs_fid_add(struct dentry *dentry, struct p9_fid *fid)
  40. {
  41. struct v9fs_dentry *dent;
  42. P9_DPRINTK(P9_DEBUG_VFS, "fid %d dentry %s\n",
  43. fid->fid, dentry->d_name.name);
  44. dent = dentry->d_fsdata;
  45. if (!dent) {
  46. dent = kmalloc(sizeof(struct v9fs_dentry), GFP_KERNEL);
  47. if (!dent)
  48. return -ENOMEM;
  49. spin_lock_init(&dent->lock);
  50. INIT_LIST_HEAD(&dent->fidlist);
  51. dentry->d_fsdata = dent;
  52. }
  53. spin_lock(&dent->lock);
  54. list_add(&fid->dlist, &dent->fidlist);
  55. spin_unlock(&dent->lock);
  56. return 0;
  57. }
  58. /**
  59. * v9fs_fid_find - retrieve a fid that belongs to the specified uid
  60. * @dentry: dentry to look for fid in
  61. * @uid: return fid that belongs to the specified user
  62. * @any: if non-zero, return any fid associated with the dentry
  63. *
  64. */
  65. static struct p9_fid *v9fs_fid_find(struct dentry *dentry, u32 uid, int any)
  66. {
  67. struct v9fs_dentry *dent;
  68. struct p9_fid *fid, *ret;
  69. P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p) uid %d any %d\n",
  70. dentry->d_name.name, dentry, uid, any);
  71. dent = (struct v9fs_dentry *) dentry->d_fsdata;
  72. ret = NULL;
  73. if (dent) {
  74. spin_lock(&dent->lock);
  75. list_for_each_entry(fid, &dent->fidlist, dlist) {
  76. if (any || fid->uid == uid) {
  77. ret = fid;
  78. break;
  79. }
  80. }
  81. spin_unlock(&dent->lock);
  82. }
  83. return ret;
  84. }
  85. /**
  86. * v9fs_fid_lookup - lookup for a fid, try to walk if not found
  87. * @dentry: dentry to look for fid in
  88. *
  89. * Look for a fid in the specified dentry for the current user.
  90. * If no fid is found, try to create one walking from a fid from the parent
  91. * dentry (if it has one), or the root dentry. If the user haven't accessed
  92. * the fs yet, attach now and walk from the root.
  93. */
  94. struct p9_fid *v9fs_fid_lookup(struct dentry *dentry)
  95. {
  96. int i, n, l, clone, any, access;
  97. u32 uid;
  98. struct p9_fid *fid;
  99. struct dentry *d, *ds;
  100. struct v9fs_session_info *v9ses;
  101. char **wnames, *uname;
  102. v9ses = v9fs_inode2v9ses(dentry->d_inode);
  103. access = v9ses->flags & V9FS_ACCESS_MASK;
  104. switch (access) {
  105. case V9FS_ACCESS_SINGLE:
  106. case V9FS_ACCESS_USER:
  107. uid = current_fsuid();
  108. any = 0;
  109. break;
  110. case V9FS_ACCESS_ANY:
  111. uid = v9ses->uid;
  112. any = 1;
  113. break;
  114. default:
  115. uid = ~0;
  116. any = 0;
  117. break;
  118. }
  119. fid = v9fs_fid_find(dentry, uid, any);
  120. if (fid)
  121. return fid;
  122. ds = dentry->d_parent;
  123. fid = v9fs_fid_find(ds, uid, any);
  124. if (!fid) { /* walk from the root */
  125. n = 0;
  126. for (ds = dentry; !IS_ROOT(ds); ds = ds->d_parent)
  127. n++;
  128. fid = v9fs_fid_find(ds, uid, any);
  129. if (!fid) { /* the user is not attached to the fs yet */
  130. if (access == V9FS_ACCESS_SINGLE)
  131. return ERR_PTR(-EPERM);
  132. if (v9fs_extended(v9ses))
  133. uname = NULL;
  134. else
  135. uname = v9ses->uname;
  136. fid = p9_client_attach(v9ses->clnt, NULL, uname, uid,
  137. v9ses->aname);
  138. if (IS_ERR(fid))
  139. return fid;
  140. v9fs_fid_add(ds, fid);
  141. }
  142. } else /* walk from the parent */
  143. n = 1;
  144. if (ds == dentry)
  145. return fid;
  146. wnames = kmalloc(sizeof(char *) * n, GFP_KERNEL);
  147. if (!wnames)
  148. return ERR_PTR(-ENOMEM);
  149. for (d = dentry, i = (n-1); i >= 0; i--, d = d->d_parent)
  150. wnames[i] = (char *) d->d_name.name;
  151. clone = 1;
  152. i = 0;
  153. while (i < n) {
  154. l = min(n - i, P9_MAXWELEM);
  155. fid = p9_client_walk(fid, l, &wnames[i], clone);
  156. if (IS_ERR(fid)) {
  157. kfree(wnames);
  158. return fid;
  159. }
  160. i += l;
  161. clone = 0;
  162. }
  163. kfree(wnames);
  164. v9fs_fid_add(dentry, fid);
  165. return fid;
  166. }
  167. struct p9_fid *v9fs_fid_clone(struct dentry *dentry)
  168. {
  169. struct p9_fid *fid, *ret;
  170. fid = v9fs_fid_lookup(dentry);
  171. if (IS_ERR(fid))
  172. return fid;
  173. ret = p9_client_walk(fid, 0, NULL, 1);
  174. return ret;
  175. }