/core/10.5/fusefs/fuse_locking.c

http://macfuse.googlecode.com/ · C · 352 lines · 227 code · 47 blank · 78 comment · 71 complexity · b56b2691d35c1c62f7062f992ee62030 MD5 · raw file

  1. /*
  2. * Copyright (C) 2006-2008 Google. All Rights Reserved.
  3. * Amit Singh <singh@>
  4. */
  5. /*
  6. * Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
  7. *
  8. * This file contains Original Code and/or Modifications of Original Code as
  9. * defined in and that are subject to the Apple Public Source License Version
  10. * 2.0 (the 'License'). You may not use this file except in compliance with
  11. * the License. Please obtain a copy of the License at
  12. * http://www.opensource.apple.com/apsl/ and read it before using this file.
  13. *
  14. * The Original Code and all software distributed under the License are
  15. * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  16. * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  17. * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
  18. * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see
  19. * the License for the specific language governing rights and limitations
  20. * under the License.
  21. */
  22. #include "fuse.h"
  23. #include "fuse_ipc.h"
  24. #include "fuse_node.h"
  25. #include "fuse_locking.h"
  26. lck_attr_t *fuse_lock_attr = NULL;
  27. lck_grp_attr_t *fuse_group_attr = NULL;
  28. lck_grp_t *fuse_lock_group = NULL;
  29. lck_mtx_t *fuse_device_mutex = NULL;
  30. #if M_MACFUSE_ENABLE_TSLOCKING
  31. /*
  32. * Largely identical to HFS+ locking. Much of the code is from hfs_cnode.c.
  33. */
  34. /*
  35. * Lock a fusenode.
  36. */
  37. __private_extern__
  38. int
  39. fusefs_lock(fusenode_t cp, enum fusefslocktype locktype)
  40. {
  41. void *thread = current_thread();
  42. if (locktype == FUSEFS_SHARED_LOCK) {
  43. lck_rw_lock_shared(cp->nodelock);
  44. cp->nodelockowner = FUSEFS_SHARED_OWNER;
  45. } else {
  46. lck_rw_lock_exclusive(cp->nodelock);
  47. cp->nodelockowner = thread;
  48. }
  49. /*
  50. * Skip nodes that no longer exist (were deleted).
  51. */
  52. if ((locktype != FUSEFS_FORCE_LOCK) && (cp->c_flag & C_NOEXISTS)) {
  53. fusefs_unlock(cp);
  54. return ENOENT;
  55. }
  56. return 0;
  57. }
  58. /*
  59. * Lock a pair of fusenodes.
  60. */
  61. __private_extern__
  62. int
  63. fusefs_lockpair(fusenode_t cp1, fusenode_t cp2, enum fusefslocktype locktype)
  64. {
  65. fusenode_t first, last;
  66. int error;
  67. /*
  68. * If cnodes match then just lock one.
  69. */
  70. if (cp1 == cp2) {
  71. return fusefs_lock(cp1, locktype);
  72. }
  73. /*
  74. * Lock in cnode parent-child order (if there is a relationship);
  75. * otherwise lock in cnode address order.
  76. */
  77. if ((cp1->vtype == VDIR) && (cp1->nodeid == cp2->parent_nodeid)) {
  78. first = cp1;
  79. last = cp2;
  80. } else if (cp1 < cp2) {
  81. first = cp1;
  82. last = cp2;
  83. } else {
  84. first = cp2;
  85. last = cp1;
  86. }
  87. if ( (error = fusefs_lock(first, locktype))) {
  88. return error;
  89. }
  90. if ( (error = fusefs_lock(last, locktype))) {
  91. fusefs_unlock(first);
  92. return error;
  93. }
  94. return 0;
  95. }
  96. /*
  97. * Check ordering of two fusenodes. Return true if they are are in-order.
  98. */
  99. static int
  100. fusefs_isordered(fusenode_t cp1, fusenode_t cp2)
  101. {
  102. if (cp1 == cp2) {
  103. return 0;
  104. }
  105. if (cp1 == NULL || cp2 == (fusenode_t )0xffffffff) {
  106. return 1;
  107. }
  108. if (cp2 == NULL || cp1 == (fusenode_t )0xffffffff) {
  109. return 0;
  110. }
  111. if (cp1->nodeid == cp2->parent_nodeid) {
  112. return 1; /* cp1 is the parent and should go first */
  113. }
  114. if (cp2->nodeid == cp1->parent_nodeid) {
  115. return 0; /* cp1 is the child and should go last */
  116. }
  117. return (cp1 < cp2); /* fall-back is to use address order */
  118. }
  119. /*
  120. * Acquire 4 fusenode locks.
  121. * - locked in fusenode parent-child order (if there is a relationship)
  122. * otherwise lock in fusenode address order (lesser address first).
  123. * - all or none of the locks are taken
  124. * - only one lock taken per fusenode (dup fusenodes are skipped)
  125. * - some of the fusenode pointers may be null
  126. */
  127. __private_extern__
  128. int
  129. fusefs_lockfour(fusenode_t cp1, fusenode_t cp2, fusenode_t cp3, fusenode_t cp4,
  130. enum fusefslocktype locktype)
  131. {
  132. fusenode_t a[3];
  133. fusenode_t b[3];
  134. fusenode_t list[4];
  135. fusenode_t tmp;
  136. int i, j, k;
  137. int error;
  138. if (fusefs_isordered(cp1, cp2)) {
  139. a[0] = cp1; a[1] = cp2;
  140. } else {
  141. a[0] = cp2; a[1] = cp1;
  142. }
  143. if (fusefs_isordered(cp3, cp4)) {
  144. b[0] = cp3; b[1] = cp4;
  145. } else {
  146. b[0] = cp4; b[1] = cp3;
  147. }
  148. a[2] = (fusenode_t )0xffffffff; /* sentinel value */
  149. b[2] = (fusenode_t )0xffffffff; /* sentinel value */
  150. /*
  151. * Build the lock list, skipping over duplicates
  152. */
  153. for (i = 0, j = 0, k = 0; (i < 2 || j < 2); ) {
  154. tmp = fusefs_isordered(a[i], b[j]) ? a[i++] : b[j++];
  155. if (k == 0 || tmp != list[k-1])
  156. list[k++] = tmp;
  157. }
  158. /*
  159. * Now we can lock using list[0 - k].
  160. * Skip over NULL entries.
  161. */
  162. for (i = 0; i < k; ++i) {
  163. if (list[i])
  164. if ((error = fusefs_lock(list[i], locktype))) {
  165. /* Drop any locks we acquired. */
  166. while (--i >= 0) {
  167. if (list[i])
  168. fusefs_unlock(list[i]);
  169. }
  170. return error;
  171. }
  172. }
  173. return 0;
  174. }
  175. /*
  176. * Unlock a fusenode.
  177. */
  178. __private_extern__
  179. void
  180. fusefs_unlock(fusenode_t cp)
  181. {
  182. u_int32_t c_flag;
  183. vnode_t vp = NULLVP;
  184. #if M_MACFUSE_RSRC_FORK
  185. vnode_t rvp = NULLVP;
  186. #endif
  187. c_flag = cp->c_flag;
  188. cp->c_flag &= ~(C_NEED_DVNODE_PUT | C_NEED_DATA_SETSIZE);
  189. #if M_MACFUSE_RSRC_FORK
  190. cp->c_flag &= ~(C_NEED_RVNODE_PUT | C_NEED_RSRC_SETSIZE);
  191. #endif
  192. if (c_flag & (C_NEED_DVNODE_PUT | C_NEED_DATA_SETSIZE)) {
  193. vp = cp->vp;
  194. }
  195. #if M_MACFUSE_RSRC_FORK
  196. if (c_flag & (C_NEED_RVNODE_PUT | C_NEED_RSRC_SETSIZE)) {
  197. rvp = cp->c_rsrc_vp;
  198. }
  199. #endif
  200. cp->nodelockowner = NULL;
  201. fusefs_lck_rw_done(cp->nodelock);
  202. /* Perform any vnode post processing after fusenode lock is dropped. */
  203. if (vp) {
  204. if (c_flag & C_NEED_DATA_SETSIZE) {
  205. ubc_setsize(vp, 0);
  206. }
  207. if (c_flag & C_NEED_DVNODE_PUT) {
  208. vnode_put(vp);
  209. }
  210. }
  211. #if M_MACFUSE_RSRC_FORK
  212. if (rvp) {
  213. if (c_flag & C_NEED_RSRC_SETSIZE) {
  214. ubc_setsize(rvp, 0);
  215. }
  216. if (c_flag & C_NEED_RVNODE_PUT) {
  217. vnode_put(rvp);
  218. }
  219. }
  220. #endif
  221. }
  222. /*
  223. * Unlock a pair of fusenodes.
  224. */
  225. __private_extern__
  226. void
  227. fusefs_unlockpair(fusenode_t cp1, fusenode_t cp2)
  228. {
  229. fusefs_unlock(cp1);
  230. if (cp2 != cp1) {
  231. fusefs_unlock(cp2);
  232. }
  233. }
  234. /*
  235. * Unlock a group of fusenodes.
  236. */
  237. __private_extern__
  238. void
  239. fusefs_unlockfour(fusenode_t cp1, fusenode_t cp2,
  240. fusenode_t cp3, fusenode_t cp4)
  241. {
  242. fusenode_t list[4];
  243. int i, k = 0;
  244. if (cp1) {
  245. fusefs_unlock(cp1);
  246. list[k++] = cp1;
  247. }
  248. if (cp2) {
  249. for (i = 0; i < k; ++i) {
  250. if (list[i] == cp2)
  251. goto skip1;
  252. }
  253. fusefs_unlock(cp2);
  254. list[k++] = cp2;
  255. }
  256. skip1:
  257. if (cp3) {
  258. for (i = 0; i < k; ++i) {
  259. if (list[i] == cp3)
  260. goto skip2;
  261. }
  262. fusefs_unlock(cp3);
  263. list[k++] = cp3;
  264. }
  265. skip2:
  266. if (cp4) {
  267. for (i = 0; i < k; ++i) {
  268. if (list[i] == cp4)
  269. return;
  270. }
  271. fusefs_unlock(cp4);
  272. }
  273. }
  274. /*
  275. * Protect a fusenode against truncation.
  276. *
  277. * Used mainly by read/write since they don't hold the fusenode lock across
  278. * calls to the cluster layer.
  279. *
  280. * The process doing a truncation must take the lock exclusive. The read/write
  281. * processes can take it non-exclusive.
  282. */
  283. __private_extern__
  284. void
  285. fusefs_lock_truncate(fusenode_t cp, lck_rw_type_t lck_rw_type)
  286. {
  287. if (cp->nodelockowner == current_thread()) {
  288. panic("MacFUSE: fusefs_lock_truncate: cnode %p locked!", cp);
  289. }
  290. lck_rw_lock(cp->truncatelock, lck_rw_type);
  291. }
  292. __private_extern__
  293. void
  294. fusefs_unlock_truncate(fusenode_t cp)
  295. {
  296. fusefs_lck_rw_done(cp->truncatelock);
  297. }
  298. #endif
  299. #include <IOKit/IOLocks.h>
  300. __private_extern__
  301. void
  302. fusefs_lck_rw_done(lck_rw_t *lock)
  303. {
  304. IORWLockUnlock((IORWLock *)lock);
  305. }