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