[BACK]Return to vfs_lockf.c CVS log [TXT][DIR] Up to [local] / sys / kern

Annotation of sys/kern/vfs_lockf.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: vfs_lockf.c,v 1.12 2005/11/20 21:55:15 pedro Exp $    */
                      2: /*     $NetBSD: vfs_lockf.c,v 1.7 1996/02/04 02:18:21 christos Exp $   */
                      3:
                      4: /*
                      5:  * Copyright (c) 1982, 1986, 1989, 1993
                      6:  *     The Regents of the University of California.  All rights reserved.
                      7:  *
                      8:  * This code is derived from software contributed to Berkeley by
                      9:  * Scooter Morris at Genentech Inc.
                     10:  *
                     11:  * Redistribution and use in source and binary forms, with or without
                     12:  * modification, are permitted provided that the following conditions
                     13:  * are met:
                     14:  * 1. Redistributions of source code must retain the above copyright
                     15:  *    notice, this list of conditions and the following disclaimer.
                     16:  * 2. Redistributions in binary form must reproduce the above copyright
                     17:  *    notice, this list of conditions and the following disclaimer in the
                     18:  *    documentation and/or other materials provided with the distribution.
                     19:  * 3. Neither the name of the University nor the names of its contributors
                     20:  *    may be used to endorse or promote products derived from this software
                     21:  *    without specific prior written permission.
                     22:  *
                     23:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     24:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     25:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     26:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     27:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     28:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     29:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     30:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     31:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     32:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     33:  * SUCH DAMAGE.
                     34:  *
                     35:  *     @(#)ufs_lockf.c 8.3 (Berkeley) 1/6/94
                     36:  */
                     37:
                     38: #include <sys/param.h>
                     39: #include <sys/systm.h>
                     40: #include <sys/kernel.h>
                     41: #include <sys/file.h>
                     42: #include <sys/proc.h>
                     43: #include <sys/vnode.h>
                     44: #include <sys/pool.h>
                     45: #include <sys/fcntl.h>
                     46: #include <sys/lockf.h>
                     47:
                     48: struct pool lockfpool;
                     49:
                     50: /*
                     51:  * This variable controls the maximum number of processes that will
                     52:  * be checked in doing deadlock detection.
                     53:  */
                     54: int maxlockdepth = MAXDEPTH;
                     55:
                     56: #define SELF   0x1
                     57: #define OTHERS 0x2
                     58:
                     59: #ifdef LOCKF_DEBUG
                     60:
                     61: #define        DEBUG_SETLOCK           0x01
                     62: #define        DEBUG_CLEARLOCK         0x02
                     63: #define        DEBUG_GETLOCK           0x04
                     64: #define        DEBUG_FINDOVR           0x08
                     65: #define        DEBUG_SPLIT             0x10
                     66: #define        DEBUG_WAKELOCK          0x20
                     67:
                     68: int    lockf_debug = DEBUG_SETLOCK|DEBUG_CLEARLOCK|DEBUG_WAKELOCK;
                     69:
                     70: #define        DPRINTF(args, level)    if (lockf_debug & (level)) printf args
                     71: #else
                     72: #define        DPRINTF(args, level)
                     73: #endif
                     74:
                     75: void
                     76: lf_init(void)
                     77: {
                     78:        pool_init(&lockfpool, sizeof(struct lockf), 0, 0, 0,
                     79:            "lockfpl", &pool_allocator_nointr);
                     80: }
                     81:
                     82: struct lockf *lf_alloc(uid_t, int);
                     83: void lf_free(struct lockf *);
                     84:
                     85: /*
                     86:  * We enforce a limit on locks by uid, so that a single user cannot
                     87:  * run the kernel out of memory.  For now, the limit is pretty coarse.
                     88:  * There is no limit on root.
                     89:  *
                     90:  * Splitting a lock will always succeed, regardless of current allocations.
                     91:  * If you're slightly above the limit, we still have to permit an allocation
                     92:  * so that the unlock can succeed.  If the unlocking causes too many splits,
                     93:  * however, you're totally cutoff.
                     94:  */
                     95: int maxlocksperuid = 1024;
                     96:
                     97: /*
                     98:  * 3 options for allowfail.
                     99:  * 0 - always allocate.  1 - cutoff at limit.  2 - cutoff at double limit.
                    100:  */
                    101: struct lockf *
                    102: lf_alloc(uid_t uid, int allowfail)
                    103: {
                    104:        struct uidinfo *uip;
                    105:        struct lockf *lock;
                    106:
                    107:        uip = uid_find(uid);
                    108:        if (uid && allowfail && uip->ui_lockcnt >
                    109:            (allowfail == 1 ? maxlocksperuid : (maxlocksperuid * 2)))
                    110:                return (NULL);
                    111:        uip->ui_lockcnt++;
                    112:        lock = pool_get(&lockfpool, PR_WAITOK);
                    113:        lock->lf_uid = uid;
                    114:        return (lock);
                    115: }
                    116:
                    117: void
                    118: lf_free(struct lockf *lock)
                    119: {
                    120:        struct uidinfo *uip;
                    121:
                    122:        uip = uid_find(lock->lf_uid);
                    123:        uip->ui_lockcnt--;
                    124:        pool_put(&lockfpool, lock);
                    125: }
                    126:
                    127:
                    128: /*
                    129:  * Do an advisory lock operation.
                    130:  */
                    131: int
                    132: lf_advlock(struct lockf **head, off_t size, caddr_t id, int op,
                    133:     struct flock *fl, int flags)
                    134: {
                    135:        struct proc *p = curproc;
                    136:        struct lockf *lock;
                    137:        off_t start, end;
                    138:        int error;
                    139:
                    140:        /*
                    141:         * Convert the flock structure into a start and end.
                    142:         */
                    143:        switch (fl->l_whence) {
                    144:
                    145:        case SEEK_SET:
                    146:        case SEEK_CUR:
                    147:                /*
                    148:                 * Caller is responsible for adding any necessary offset
                    149:                 * when SEEK_CUR is used.
                    150:                 */
                    151:                start = fl->l_start;
                    152:                break;
                    153:
                    154:        case SEEK_END:
                    155:                start = size + fl->l_start;
                    156:                break;
                    157:
                    158:        default:
                    159:                return (EINVAL);
                    160:        }
                    161:        if (start < 0)
                    162:                return (EINVAL);
                    163:        if (fl->l_len == 0)
                    164:                end = -1;
                    165:        else {
                    166:                end = start + fl->l_len - 1;
                    167:                if (end < start)
                    168:                        return (EINVAL);
                    169:        }
                    170:
                    171:        /*
                    172:         * Avoid the common case of unlocking when inode has no locks.
                    173:         */
                    174:        if (*head == NULL) {
                    175:                if (op != F_SETLK) {
                    176:                        fl->l_type = F_UNLCK;
                    177:                        return (0);
                    178:                }
                    179:        }
                    180:
                    181:        /*
                    182:         * Create the lockf structure.
                    183:         */
                    184:        lock = lf_alloc(p->p_ucred->cr_uid, op != F_UNLCK ? 1 : 2);
                    185:        if (!lock)
                    186:                return (ENOMEM);
                    187:        lock->lf_start = start;
                    188:        lock->lf_end = end;
                    189:        lock->lf_id = id;
                    190:        lock->lf_head = head;
                    191:        lock->lf_type = fl->l_type;
                    192:        lock->lf_next = NULL;
                    193:        TAILQ_INIT(&lock->lf_blkhd);
                    194:        lock->lf_flags = flags;
                    195:        /*
                    196:         * Do the requested operation.
                    197:         */
                    198:        switch (op) {
                    199:
                    200:        case F_SETLK:
                    201:                return (lf_setlock(lock));
                    202:
                    203:        case F_UNLCK:
                    204:                error = lf_clearlock(lock);
                    205:                lf_free(lock);
                    206:                return (error);
                    207:
                    208:        case F_GETLK:
                    209:                error = lf_getlock(lock, fl);
                    210:                lf_free(lock);
                    211:                return (error);
                    212:
                    213:        default:
                    214:                lf_free(lock);
                    215:                return (EINVAL);
                    216:        }
                    217:        /* NOTREACHED */
                    218: }
                    219:
                    220: /*
                    221:  * Set a byte-range lock.
                    222:  */
                    223: int
                    224: lf_setlock(struct lockf *lock)
                    225: {
                    226:        struct lockf *block;
                    227:        struct lockf **head = lock->lf_head;
                    228:        struct lockf **prev, *overlap, *ltmp;
                    229:        static char lockstr[] = "lockf";
                    230:        int ovcase, priority, needtolink, error;
                    231:
                    232: #ifdef LOCKF_DEBUG
                    233:        if (lockf_debug & DEBUG_SETLOCK)
                    234:                lf_print("lf_setlock", lock);
                    235: #endif /* LOCKF_DEBUG */
                    236:
                    237:        /*
                    238:         * Set the priority
                    239:         */
                    240:        priority = PLOCK;
                    241:        if (lock->lf_type == F_WRLCK)
                    242:                priority += 4;
                    243:        priority |= PCATCH;
                    244:        /*
                    245:         * Scan lock list for this file looking for locks that would block us.
                    246:         */
                    247:        while ((block = lf_getblock(lock)) != NULL) {
                    248:                /*
                    249:                 * Free the structure and return if nonblocking.
                    250:                 */
                    251:                if ((lock->lf_flags & F_WAIT) == 0) {
                    252:                        lf_free(lock);
                    253:                        return (EAGAIN);
                    254:                }
                    255:                /*
                    256:                 * We are blocked. Since flock style locks cover
                    257:                 * the whole file, there is no chance for deadlock.
                    258:                 * For byte-range locks we must check for deadlock.
                    259:                 *
                    260:                 * Deadlock detection is done by looking through the
                    261:                 * wait channels to see if there are any cycles that
                    262:                 * involve us. MAXDEPTH is set just to make sure we
                    263:                 * do not go off into neverland.
                    264:                 */
                    265:                if ((lock->lf_flags & F_POSIX) &&
                    266:                    (block->lf_flags & F_POSIX)) {
                    267:                        struct proc *wproc;
                    268:                        struct lockf *waitblock;
                    269:                        int i = 0;
                    270:
                    271:                        /* The block is waiting on something */
                    272:                        wproc = (struct proc *)block->lf_id;
                    273:                        while (wproc->p_wchan &&
                    274:                            (wproc->p_wmesg == lockstr) &&
                    275:                            (i++ < maxlockdepth)) {
                    276:                                waitblock = (struct lockf *)wproc->p_wchan;
                    277:                                /* Get the owner of the blocking lock */
                    278:                                waitblock = waitblock->lf_next;
                    279:                                if ((waitblock->lf_flags & F_POSIX) == 0)
                    280:                                        break;
                    281:                                wproc = (struct proc *)waitblock->lf_id;
                    282:                                if (wproc == (struct proc *)lock->lf_id) {
                    283:                                        lf_free(lock);
                    284:                                        return (EDEADLK);
                    285:                                }
                    286:                        }
                    287:                }
                    288:                /*
                    289:                 * For flock type locks, we must first remove
                    290:                 * any shared locks that we hold before we sleep
                    291:                 * waiting for an exclusive lock.
                    292:                 */
                    293:                if ((lock->lf_flags & F_FLOCK) &&
                    294:                    lock->lf_type == F_WRLCK) {
                    295:                        lock->lf_type = F_UNLCK;
                    296:                        (void) lf_clearlock(lock);
                    297:                        lock->lf_type = F_WRLCK;
                    298:                }
                    299:                /*
                    300:                 * Add our lock to the blocked list and sleep until we're free.
                    301:                 * Remember who blocked us (for deadlock detection).
                    302:                 */
                    303:                lock->lf_next = block;
                    304: #ifdef LOCKF_DEBUG
                    305:                if (lockf_debug & DEBUG_SETLOCK) {
                    306:                        lf_print("lf_setlock", lock);
                    307:                        lf_print("lf_setlock: blocking on", block);
                    308:                }
                    309: #endif /* LOCKF_DEBUG */
                    310:                TAILQ_INSERT_TAIL(&block->lf_blkhd, lock, lf_block);
                    311:                error = tsleep(lock, priority, lockstr, 0);
                    312: #if 0
                    313:                if (error) {
                    314:                        /*
                    315:                         * Delete ourselves from the waiting to lock list.
                    316:                         */
                    317:                        TAILQ_REMOVE(&lock->lf_next->lf_blkhd, lock, lf_block);
                    318:                        lf_free(lock);
                    319:                        return (error);
                    320:                }
                    321: #else
                    322:                if (lock->lf_next != NULL) {
                    323:                        TAILQ_REMOVE(&lock->lf_next->lf_blkhd, lock, lf_block);
                    324:                        lock->lf_next = NULL;
                    325:                }
                    326:                if (error) {
                    327:                        lf_free(lock);
                    328:                        return (error);
                    329:                }
                    330: #endif
                    331:        }
                    332:        /*
                    333:         * No blocks!!  Add the lock.  Note that we will
                    334:         * downgrade or upgrade any overlapping locks this
                    335:         * process already owns.
                    336:         *
                    337:         * Skip over locks owned by other processes.
                    338:         * Handle any locks that overlap and are owned by ourselves.
                    339:         */
                    340:        prev = head;
                    341:        block = *head;
                    342:        needtolink = 1;
                    343:        for (;;) {
                    344:                ovcase = lf_findoverlap(block, lock, SELF, &prev, &overlap);
                    345:                if (ovcase)
                    346:                        block = overlap->lf_next;
                    347:                /*
                    348:                 * Six cases:
                    349:                 *      0) no overlap
                    350:                 *      1) overlap == lock
                    351:                 *      2) overlap contains lock
                    352:                 *      3) lock contains overlap
                    353:                 *      4) overlap starts before lock
                    354:                 *      5) overlap ends after lock
                    355:                 */
                    356:                switch (ovcase) {
                    357:                case 0: /* no overlap */
                    358:                        if (needtolink) {
                    359:                                *prev = lock;
                    360:                                lock->lf_next = overlap;
                    361:                        }
                    362:                        break;
                    363:
                    364:                case 1: /* overlap == lock */
                    365:                        /*
                    366:                         * If downgrading lock, others may be
                    367:                         * able to acquire it.
                    368:                         */
                    369:                        if (lock->lf_type == F_RDLCK &&
                    370:                            overlap->lf_type == F_WRLCK)
                    371:                                lf_wakelock(overlap);
                    372:                        overlap->lf_type = lock->lf_type;
                    373:                        lf_free(lock);
                    374:                        lock = overlap; /* for debug output below */
                    375:                        break;
                    376:
                    377:                case 2: /* overlap contains lock */
                    378:                        /*
                    379:                         * Check for common starting point and different types.
                    380:                         */
                    381:                        if (overlap->lf_type == lock->lf_type) {
                    382:                                lf_free(lock);
                    383:                                lock = overlap; /* for debug output below */
                    384:                                break;
                    385:                        }
                    386:                        if (overlap->lf_start == lock->lf_start) {
                    387:                                *prev = lock;
                    388:                                lock->lf_next = overlap;
                    389:                                overlap->lf_start = lock->lf_end + 1;
                    390:                        } else
                    391:                                lf_split(overlap, lock);
                    392:                        lf_wakelock(overlap);
                    393:                        break;
                    394:
                    395:                case 3: /* lock contains overlap */
                    396:                        /*
                    397:                         * If downgrading lock, others may be able to
                    398:                         * acquire it, otherwise take the list.
                    399:                         */
                    400:                        if (lock->lf_type == F_RDLCK &&
                    401:                            overlap->lf_type == F_WRLCK) {
                    402:                                lf_wakelock(overlap);
                    403:                        } else {
                    404:                                while ((ltmp =
                    405:                                    TAILQ_FIRST(&overlap->lf_blkhd))) {
                    406:                                        TAILQ_REMOVE(&overlap->lf_blkhd, ltmp,
                    407:                                            lf_block);
                    408:                                        ltmp->lf_next = lock;
                    409:                                        TAILQ_INSERT_TAIL(&lock->lf_blkhd,
                    410:                                            ltmp, lf_block);
                    411:                                }
                    412:                        }
                    413:                        /*
                    414:                         * Add the new lock if necessary and delete the overlap.
                    415:                         */
                    416:                        if (needtolink) {
                    417:                                *prev = lock;
                    418:                                lock->lf_next = overlap->lf_next;
                    419:                                prev = &lock->lf_next;
                    420:                                needtolink = 0;
                    421:                        } else
                    422:                                *prev = overlap->lf_next;
                    423:                        lf_free(overlap);
                    424:                        continue;
                    425:
                    426:                case 4: /* overlap starts before lock */
                    427:                        /*
                    428:                         * Add lock after overlap on the list.
                    429:                         */
                    430:                        lock->lf_next = overlap->lf_next;
                    431:                        overlap->lf_next = lock;
                    432:                        overlap->lf_end = lock->lf_start - 1;
                    433:                        prev = &lock->lf_next;
                    434:                        lf_wakelock(overlap);
                    435:                        needtolink = 0;
                    436:                        continue;
                    437:
                    438:                case 5: /* overlap ends after lock */
                    439:                        /*
                    440:                         * Add the new lock before overlap.
                    441:                         */
                    442:                        if (needtolink) {
                    443:                                *prev = lock;
                    444:                                lock->lf_next = overlap;
                    445:                        }
                    446:                        overlap->lf_start = lock->lf_end + 1;
                    447:                        lf_wakelock(overlap);
                    448:                        break;
                    449:                }
                    450:                break;
                    451:        }
                    452: #ifdef LOCKF_DEBUG
                    453:        if (lockf_debug & DEBUG_SETLOCK) {
                    454:                lf_print("lf_setlock: got the lock", lock);
                    455:        }
                    456: #endif /* LOCKF_DEBUG */
                    457:        return (0);
                    458: }
                    459:
                    460: /*
                    461:  * Remove a byte-range lock on an inode.
                    462:  *
                    463:  * Generally, find the lock (or an overlap to that lock)
                    464:  * and remove it (or shrink it), then wakeup anyone we can.
                    465:  */
                    466: int
                    467: lf_clearlock(struct lockf *lock)
                    468: {
                    469:        struct lockf **head = lock->lf_head;
                    470:        struct lockf *lf = *head;
                    471:        struct lockf *overlap, **prev;
                    472:        int ovcase;
                    473:
                    474:        if (lf == NULL)
                    475:                return (0);
                    476: #ifdef LOCKF_DEBUG
                    477:        if (lockf_debug & DEBUG_CLEARLOCK)
                    478:                lf_print("lf_clearlock", lock);
                    479: #endif /* LOCKF_DEBUG */
                    480:        prev = head;
                    481:        while ((ovcase = lf_findoverlap(lf, lock, SELF,
                    482:                                        &prev, &overlap)) != 0) {
                    483:                /*
                    484:                 * Wakeup the list of locks to be retried.
                    485:                 */
                    486:                lf_wakelock(overlap);
                    487:
                    488:                switch (ovcase) {
                    489:
                    490:                case 1: /* overlap == lock */
                    491:                        *prev = overlap->lf_next;
                    492:                        lf_free(overlap);
                    493:                        break;
                    494:
                    495:                case 2: /* overlap contains lock: split it */
                    496:                        if (overlap->lf_start == lock->lf_start) {
                    497:                                overlap->lf_start = lock->lf_end + 1;
                    498:                                break;
                    499:                        }
                    500:                        lf_split(overlap, lock);
                    501:                        overlap->lf_next = lock->lf_next;
                    502:                        break;
                    503:
                    504:                case 3: /* lock contains overlap */
                    505:                        *prev = overlap->lf_next;
                    506:                        lf = overlap->lf_next;
                    507:                        lf_free(overlap);
                    508:                        continue;
                    509:
                    510:                case 4: /* overlap starts before lock */
                    511:                        overlap->lf_end = lock->lf_start - 1;
                    512:                        prev = &overlap->lf_next;
                    513:                        lf = overlap->lf_next;
                    514:                        continue;
                    515:
                    516:                case 5: /* overlap ends after lock */
                    517:                        overlap->lf_start = lock->lf_end + 1;
                    518:                        break;
                    519:                }
                    520:                break;
                    521:        }
                    522:        return (0);
                    523: }
                    524:
                    525: /*
                    526:  * Check whether there is a blocking lock,
                    527:  * and if so return its process identifier.
                    528:  */
                    529: int
                    530: lf_getlock(struct lockf *lock, struct flock *fl)
                    531: {
                    532:        struct lockf *block;
                    533:
                    534: #ifdef LOCKF_DEBUG
                    535:        if (lockf_debug & DEBUG_CLEARLOCK)
                    536:                lf_print("lf_getlock", lock);
                    537: #endif /* LOCKF_DEBUG */
                    538:
                    539:        if ((block = lf_getblock(lock)) != NULL) {
                    540:                fl->l_type = block->lf_type;
                    541:                fl->l_whence = SEEK_SET;
                    542:                fl->l_start = block->lf_start;
                    543:                if (block->lf_end == -1)
                    544:                        fl->l_len = 0;
                    545:                else
                    546:                        fl->l_len = block->lf_end - block->lf_start + 1;
                    547:                if (block->lf_flags & F_POSIX)
                    548:                        fl->l_pid = ((struct proc *)(block->lf_id))->p_pid;
                    549:                else
                    550:                        fl->l_pid = -1;
                    551:        } else {
                    552:                fl->l_type = F_UNLCK;
                    553:        }
                    554:        return (0);
                    555: }
                    556:
                    557: /*
                    558:  * Walk the list of locks for an inode and
                    559:  * return the first blocking lock.
                    560:  */
                    561: struct lockf *
                    562: lf_getblock(struct lockf *lock)
                    563: {
                    564:        struct lockf **prev, *overlap, *lf;
                    565:
                    566:        prev = lock->lf_head;
                    567:        lf = *prev;
                    568:        while (lf_findoverlap(lf, lock, OTHERS, &prev, &overlap) != 0) {
                    569:                /*
                    570:                 * We've found an overlap, see if it blocks us
                    571:                 */
                    572:                if ((lock->lf_type == F_WRLCK || overlap->lf_type == F_WRLCK))
                    573:                        return (overlap);
                    574:                /*
                    575:                 * Nope, point to the next one on the list and
                    576:                 * see if it blocks us
                    577:                 */
                    578:                lf = overlap->lf_next;
                    579:        }
                    580:        return (NULL);
                    581: }
                    582:
                    583: /*
                    584:  * Walk the list of locks for an inode to
                    585:  * find an overlapping lock (if any).
                    586:  *
                    587:  * NOTE: this returns only the FIRST overlapping lock.  There
                    588:  *      may be more than one.
                    589:  */
                    590: int
                    591: lf_findoverlap(struct lockf *lf, struct lockf *lock, int type,
                    592:     struct lockf ***prev, struct lockf **overlap)
                    593: {
                    594:        off_t start, end;
                    595:
                    596: #ifdef LOCKF_DEBUG
                    597:        if (lf && lockf_debug & DEBUG_FINDOVR)
                    598:                lf_print("lf_findoverlap: looking for overlap in", lock);
                    599: #endif /* LOCKF_DEBUG */
                    600:
                    601:        *overlap = lf;
                    602:        start = lock->lf_start;
                    603:        end = lock->lf_end;
                    604:        while (lf != NULL) {
                    605:                if (((type & SELF) && lf->lf_id != lock->lf_id) ||
                    606:                    ((type & OTHERS) && lf->lf_id == lock->lf_id)) {
                    607:                        *prev = &lf->lf_next;
                    608:                        *overlap = lf = lf->lf_next;
                    609:                        continue;
                    610:                }
                    611: #ifdef LOCKF_DEBUG
                    612:                if (lockf_debug & DEBUG_FINDOVR)
                    613:                        lf_print("\tchecking", lf);
                    614: #endif /* LOCKF_DEBUG */
                    615:                /*
                    616:                 * OK, check for overlap
                    617:                 *
                    618:                 * Six cases:
                    619:                 *      0) no overlap
                    620:                 *      1) overlap == lock
                    621:                 *      2) overlap contains lock
                    622:                 *      3) lock contains overlap
                    623:                 *      4) overlap starts before lock
                    624:                 *      5) overlap ends after lock
                    625:                 */
                    626:
                    627:                /* Case 0 */
                    628:                if ((lf->lf_end != -1 && start > lf->lf_end) ||
                    629:                    (end != -1 && lf->lf_start > end)) {
                    630:                        DPRINTF(("no overlap\n"), DEBUG_FINDOVR);
                    631:                        if ((type & SELF) && end != -1 && lf->lf_start > end)
                    632:                                return (0);
                    633:                        *prev = &lf->lf_next;
                    634:                        *overlap = lf = lf->lf_next;
                    635:                        continue;
                    636:                }
                    637:                /* Case 1 */
                    638:                if ((lf->lf_start == start) && (lf->lf_end == end)) {
                    639:                        DPRINTF(("overlap == lock\n"), DEBUG_FINDOVR);
                    640:                        return (1);
                    641:                }
                    642:                /* Case 2 */
                    643:                if ((lf->lf_start <= start) &&
                    644:                    (lf->lf_end == -1 ||
                    645:                    (end != -1 && lf->lf_end >= end))) {
                    646:                        DPRINTF(("overlap contains lock\n"), DEBUG_FINDOVR);
                    647:                        return (2);
                    648:                }
                    649:                /* Case 3 */
                    650:                if (start <= lf->lf_start &&
                    651:                    (end == -1 ||
                    652:                    (lf->lf_end != -1 && end >= lf->lf_end))) {
                    653:                        DPRINTF(("lock contains overlap\n"), DEBUG_FINDOVR);
                    654:                        return (3);
                    655:                }
                    656:                /* Case 4 */
                    657:                if ((lf->lf_start < start) &&
                    658:                    ((lf->lf_end >= start) || (lf->lf_end == -1))) {
                    659:                        DPRINTF(("overlap starts before lock\n"),
                    660:                            DEBUG_FINDOVR);
                    661:                        return (4);
                    662:                }
                    663:                /* Case 5 */
                    664:                if ((lf->lf_start > start) &&
                    665:                    (end != -1) &&
                    666:                    ((lf->lf_end > end) || (lf->lf_end == -1))) {
                    667:                        DPRINTF(("overlap ends after lock\n"), DEBUG_FINDOVR);
                    668:                        return (5);
                    669:                }
                    670:                panic("lf_findoverlap: default");
                    671:        }
                    672:        return (0);
                    673: }
                    674:
                    675: /*
                    676:  * Split a lock and a contained region into
                    677:  * two or three locks as necessary.
                    678:  */
                    679: void
                    680: lf_split(struct lockf *lock1, struct lockf *lock2)
                    681: {
                    682:        struct lockf *splitlock;
                    683:
                    684: #ifdef LOCKF_DEBUG
                    685:        if (lockf_debug & DEBUG_SPLIT) {
                    686:                lf_print("lf_split", lock1);
                    687:                lf_print("splitting from", lock2);
                    688:        }
                    689: #endif /* LOCKF_DEBUG */
                    690:        /*
                    691:         * Check to see if spliting into only two pieces.
                    692:         */
                    693:        if (lock1->lf_start == lock2->lf_start) {
                    694:                lock1->lf_start = lock2->lf_end + 1;
                    695:                lock2->lf_next = lock1;
                    696:                return;
                    697:        }
                    698:        if (lock1->lf_end == lock2->lf_end) {
                    699:                lock1->lf_end = lock2->lf_start - 1;
                    700:                lock2->lf_next = lock1->lf_next;
                    701:                lock1->lf_next = lock2;
                    702:                return;
                    703:        }
                    704:        /*
                    705:         * Make a new lock consisting of the last part of
                    706:         * the encompassing lock
                    707:         */
                    708:        splitlock = lf_alloc(lock1->lf_uid, 0);
                    709:        memcpy(splitlock, lock1, sizeof(*splitlock));
                    710:        splitlock->lf_start = lock2->lf_end + 1;
                    711:        splitlock->lf_block.tqe_next = NULL;
                    712:        TAILQ_INIT(&splitlock->lf_blkhd);
                    713:        lock1->lf_end = lock2->lf_start - 1;
                    714:        /*
                    715:         * OK, now link it in
                    716:         */
                    717:        lock2->lf_next = splitlock;
                    718:        lock1->lf_next = lock2;
                    719: }
                    720:
                    721: /*
                    722:  * Wakeup a blocklist
                    723:  */
                    724: void
                    725: lf_wakelock(struct lockf *lock)
                    726: {
                    727:        struct lockf *wakelock;
                    728:
                    729:        while ((wakelock = TAILQ_FIRST(&lock->lf_blkhd))) {
                    730:                TAILQ_REMOVE(&lock->lf_blkhd, wakelock, lf_block);
                    731:                wakelock->lf_next = NULL;
                    732:                wakeup_one(wakelock);
                    733:        }
                    734: }
                    735:
                    736: #ifdef LOCKF_DEBUG
                    737: /*
                    738:  * Print out a lock.
                    739:  */
                    740: void
                    741: lf_print(char *tag, struct lockf *lock)
                    742: {
                    743:        struct lockf    *block;
                    744:
                    745:        printf("%s: lock %p for ", tag, lock);
                    746:        if (lock->lf_flags & F_POSIX)
                    747:                printf("proc %d", ((struct proc *)(lock->lf_id))->p_pid);
                    748:        else
                    749:                printf("id %p", lock->lf_id);
                    750:        printf(" %s, start %llx, end %llx",
                    751:                lock->lf_type == F_RDLCK ? "shared" :
                    752:                lock->lf_type == F_WRLCK ? "exclusive" :
                    753:                lock->lf_type == F_UNLCK ? "unlock" :
                    754:                "unknown", lock->lf_start, lock->lf_end);
                    755:        block = TAILQ_FIRST(&lock->lf_blkhd);
                    756:        if (block)
                    757:                printf(" block");
                    758:        TAILQ_FOREACH(block, &lock->lf_blkhd, lf_block)
                    759:                printf(" %p,", block);
                    760:        printf("\n");
                    761:
                    762: }
                    763:
                    764: void
                    765: lf_printlist(char *tag, struct lockf *lock)
                    766: {
                    767:        struct lockf *lf;
                    768:
                    769:        printf("%s: Lock list:\n", tag);
                    770:        for (lf = *lock->lf_head; lf; lf = lf->lf_next) {
                    771:                printf("\tlock %p for ", lf);
                    772:                if (lf->lf_flags & F_POSIX)
                    773:                        printf("proc %d", ((struct proc*)(lf->lf_id))->p_pid);
                    774:                else
                    775:                        printf("id %p", lf->lf_id);
                    776:                printf(" %s, start %llx, end %llx",
                    777:                        lf->lf_type == F_RDLCK ? "shared" :
                    778:                        lf->lf_type == F_WRLCK ? "exclusive" :
                    779:                        lf->lf_type == F_UNLCK ? "unlock" :
                    780:                        "unknown", lf->lf_start, lf->lf_end);
                    781:                printf("\n");
                    782:        }
                    783: }
                    784: #endif /* LOCKF_DEBUG */

CVSweb