PageRenderTime 49ms CodeModel.GetById 31ms app.highlight 15ms RepoModel.GetById 1ms app.codeStats 0ms

/core/10.4/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/*
  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}