Annotation of linux/fs/locks.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  *  linux/fs/locks.c
                      3:  *
                      4:  *  Provide support for fcntl()'s F_GETLK, F_SETLK, and F_SETLKW calls.
                      5:  *  Doug Evans, 92Aug07, [email protected].
                      6:  *
                      7:  * FIXME: two things aren't handled yet:
                      8:  *     - deadlock detection/avoidance (of dubious merit, but since it's in
                      9:  *       the definition, I guess it should be provided eventually)
                     10:  *     - mandatory locks (requires lots of changes elsewhere)
                     11:  */
                     12: 
                     13: #include <asm/segment.h>
                     14: 
                     15: #include <linux/sched.h>
                     16: #include <linux/kernel.h>
                     17: #include <linux/errno.h>
                     18: #include <linux/stat.h>
                     19: #include <linux/fcntl.h>
                     20: 
                     21: #define OFFSET_MAX     0x7fffffff      /* FIXME: move elsewhere? */
                     22: 
                     23: static int copy_flock(struct file *filp, struct file_lock *fl, struct flock *l);
                     24: static int conflict(struct file_lock *caller_fl, struct file_lock *sys_fl);
                     25: static int overlap(struct file_lock *fl1, struct file_lock *fl2);
                     26: static int lock_it(struct file *filp, struct file_lock *caller);
                     27: static int unlock_it(struct file *filp, struct file_lock *caller);
                     28: static struct file_lock *alloc_lock(struct file *filp, struct file_lock *template);
                     29: static void free_lock(struct file *filp, struct file_lock *fl);
                     30: 
                     31: static struct file_lock file_lock_table[NR_FILE_LOCKS];
                     32: static struct file_lock *file_lock_free_list;
                     33: 
                     34: /*
                     35:  * Called at boot time to initialize the lock table ...
                     36:  */
                     37: 
                     38: void fcntl_init_locks(void)
                     39: {
                     40:        struct file_lock *fl;
                     41: 
                     42:        for (fl = &file_lock_table[0]; fl < file_lock_table + NR_FILE_LOCKS - 1; fl++) {
                     43:                fl->fl_next = fl + 1;
                     44:                fl->fl_owner = NULL;
                     45:        }
                     46:        file_lock_table[NR_FILE_LOCKS - 1].fl_next = NULL;
                     47:        file_lock_table[NR_FILE_LOCKS - 1].fl_owner = NULL;
                     48:        file_lock_free_list = &file_lock_table[0];
                     49: }
                     50: 
                     51: int fcntl_getlk(unsigned int fd, struct flock *l)
                     52: {      
                     53:        struct flock flock;
                     54:        struct file *filp;
                     55:        struct file_lock *fl,file_lock;
                     56: 
                     57:        if (fd >= NR_OPEN || !(filp = current->filp[fd]))
                     58:                return -EBADF;
                     59:        verify_area(l, sizeof(*l));
                     60:        memcpy_fromfs(&flock, l, sizeof(flock));
                     61:        if (flock.l_type == F_UNLCK)
                     62:                return -EINVAL;
                     63:        if (!copy_flock(filp, &file_lock, &flock))
                     64:                return -EINVAL;
                     65: 
                     66:        for (fl = filp->f_inode->i_flock; fl != NULL; fl = fl->fl_next) {
                     67:                if (conflict(&file_lock, fl)) {
                     68:                        flock.l_pid = fl->fl_owner->pid;
                     69:                        flock.l_start = fl->fl_start;
                     70:                        flock.l_len = fl->fl_end == OFFSET_MAX ? 0 :
                     71:                                fl->fl_end - fl->fl_start + 1;
                     72:                        flock.l_whence = fl->fl_whence;
                     73:                        flock.l_type = fl->fl_type;
                     74:                        memcpy_tofs(l, &flock, sizeof(flock));
                     75:                        return 0;
                     76:                }
                     77:        }
                     78: 
                     79:        flock.l_type = F_UNLCK;                 /* no conflict found */
                     80:        memcpy_tofs(l, &flock, sizeof(flock));
                     81:        return 0;
                     82: }
                     83: 
                     84: /*
                     85:  * This function implements both F_SETLK and F_SETLKW.
                     86:  */
                     87: 
                     88: int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l)
                     89: {      
                     90:        struct file *filp;
                     91:        struct file_lock *fl,file_lock;
                     92:        struct flock flock;
                     93: 
                     94:        /*
                     95:         * Get arguments and validate them ...
                     96:         */
                     97: 
                     98:        if (fd >= NR_OPEN || !(filp = current->filp[fd]))
                     99:                return -EBADF;
                    100:        verify_area(l, sizeof(*l));
                    101:        memcpy_fromfs(&flock, l, sizeof(flock));
                    102:        if (!copy_flock(filp, &file_lock, &flock))
                    103:                return -EINVAL;
                    104:        switch (file_lock.fl_type) {
                    105:        case F_RDLCK :
                    106:                if (!(filp->f_mode & 1))
                    107:                        return -EBADF;
                    108:                break;
                    109:        case F_WRLCK :
                    110:                if (!(filp->f_mode & 2))
                    111:                        return -EBADF;
                    112:                break;
                    113:        case F_UNLCK :
                    114:                break;
                    115:        }
                    116: 
                    117:        /*
                    118:         * F_UNLCK needs to be handled differently ...
                    119:         */
                    120: 
                    121:        if (file_lock.fl_type == F_UNLCK)
                    122:                return unlock_it(filp, &file_lock);
                    123: 
                    124:        /*
                    125:         * Scan for a conflicting lock ...
                    126:         */
                    127: 
                    128: repeat:
                    129:        for (fl = filp->f_inode->i_flock; fl != NULL; fl = fl->fl_next) {
                    130:                if (!conflict(&file_lock, fl))
                    131:                        continue;
                    132:                /*
                    133:                 * File is locked by another process. If this is F_SETLKW
                    134:                 * wait for the lock to be released.
                    135:                 * FIXME: We need to check for deadlocks here.
                    136:                 */
                    137:                if (cmd == F_SETLKW) {
                    138:                        interruptible_sleep_on(&fl->fl_wait);
                    139:                        goto repeat;
                    140:                }
                    141:                return -EAGAIN;
                    142:        }
                    143: 
                    144:        /*
                    145:         * Lock doesn't conflict with any other lock ...
                    146:         */
                    147: 
                    148:        return lock_it(filp, &file_lock);
                    149: }
                    150: 
                    151: /*
                    152:  * This function is called when the file is closed.
                    153:  */
                    154: 
                    155: void fcntl_remove_locks(struct task_struct *task, struct file *filp)
                    156: {
                    157:        struct file_lock *fl,*next;
                    158: 
                    159:        for (fl = filp->f_inode->i_flock; fl != NULL; ) {
                    160:                /*
                    161:                 * If this one is freed, {fl_next} gets clobbered when the
                    162:                 * entry is moved to the free list, so grab it now ...
                    163:                 */
                    164:                next = fl->fl_next;
                    165:                if (fl->fl_owner == task)
                    166:                        free_lock(filp, fl);
                    167:                fl = next;
                    168:        }
                    169: }
                    170: 
                    171: /*
                    172:  * Verify a "struct flock" and copy it to a "struct file_lock" ...
                    173:  * Result is a boolean indicating success.
                    174:  */
                    175: 
                    176: static int copy_flock(struct file *filp, struct file_lock *fl, struct flock *l)
                    177: {
                    178:        off_t start;
                    179: 
                    180:        if (!filp->f_inode)     /* just in case */
                    181:                return 0;
                    182:        if (!S_ISREG(filp->f_inode->i_mode))
                    183:                return 0;
                    184:        if (l->l_type != F_UNLCK && l->l_type != F_RDLCK && l->l_type != F_WRLCK)
                    185:                return 0;
                    186:        switch (l->l_whence) {
                    187:        case 0 /*SEEK_SET*/ : start = 0; break;
                    188:        case 1 /*SEEK_CUR*/ : start = filp->f_pos; break;
                    189:        case 2 /*SEEK_END*/ : start = filp->f_inode->i_size; break;
                    190:        default : return 0;
                    191:        }
                    192:        if ((start += l->l_start) < 0 || l->l_len < 0)
                    193:                return 0;
                    194:        fl->fl_type = l->l_type;
                    195:        fl->fl_start = start;   /* we record the absolute position */
                    196:        fl->fl_whence = 0;      /* FIXME: do we record {l_start} as passed? */
                    197:        if (l->l_len == 0 || (fl->fl_end = start + l->l_len - 1) < 0)
                    198:                fl->fl_end = OFFSET_MAX;
                    199:        fl->fl_owner = current;
                    200:        fl->fl_wait = NULL;             /* just for cleanliness */
                    201:        return 1;
                    202: }
                    203: 
                    204: /*
                    205:  * Determine if lock {sys_fl} blocks lock {caller_fl} ...
                    206:  */
                    207: 
                    208: static int conflict(struct file_lock *caller_fl, struct file_lock *sys_fl)
                    209: {
                    210:        if (caller_fl->fl_owner == sys_fl->fl_owner)
                    211:                return 0;
                    212:        if (!overlap(caller_fl, sys_fl))
                    213:                return 0;
                    214:        switch (caller_fl->fl_type) {
                    215:        case F_RDLCK :
                    216:                return sys_fl->fl_type != F_RDLCK;
                    217:        case F_WRLCK :
                    218:                return 1;       /* overlapping region not owned by caller */
                    219:        }
                    220:        return 0;       /* shouldn't get here, but just in case */
                    221: }
                    222: 
                    223: static int overlap(struct file_lock *fl1, struct file_lock *fl2)
                    224: {
                    225:        if (fl1->fl_start <= fl2->fl_start) {
                    226:                return fl1->fl_end >= fl2->fl_start;
                    227:        } else {
                    228:                return fl2->fl_end >= fl1->fl_start;
                    229:        }
                    230: }
                    231: 
                    232: /*
                    233:  * Add a lock to a file ...
                    234:  * Result is 0 for success or -ENOLCK.
                    235:  *
                    236:  * We try to be real clever here and always minimize the number of table
                    237:  * entries we use. For example we merge adjacent locks whenever possible. This
                    238:  * consumes a bit of cpu and code space, is it really worth it? Beats me.
                    239:  *
                    240:  * I've tried to keep the following as small and simple as possible. If you can
                    241:  * make it smaller or simpler, please do. /dje 92Aug11
                    242:  *
                    243:  * WARNING: We assume the lock doesn't conflict with any other lock.
                    244:  */
                    245: 
                    246: static int lock_it(struct file *filp, struct file_lock *caller)
                    247: {
                    248:        struct file_lock *fl,*new;
                    249: 
                    250:        /*
                    251:         * It's easier if we allocate a slot for the lock first, and then
                    252:         * release it later if we have to (IE: if it can be merged with
                    253:         * another). This way the for() loop always knows that {caller} is an
                    254:         * existing entry. This will cause the routine to fail unnecessarily
                    255:         * in rare cases, but perfection can be pushed too far. :-)
                    256:         */
                    257: 
                    258:        if ((caller = alloc_lock(filp, caller)) == NULL)
                    259:                return -ENOLCK;
                    260: 
                    261:        /*
                    262:         * First scan to see if we are changing/augmenting an existing lock ...
                    263:         */
                    264: 
                    265:        for (fl = filp->f_inode->i_flock; fl != NULL; fl = fl->fl_next) {
                    266:                if (caller->fl_owner != fl->fl_owner)
                    267:                        continue;
                    268:                if (caller == fl)
                    269:                        continue;
                    270:                if (!overlap(caller, fl)) {
                    271:                        /*
                    272:                         * Detect adjacent regions (if same lock type) ...
                    273:                         */
                    274:                        if (caller->fl_type != fl->fl_type)
                    275:                                continue;
                    276:                        if (caller->fl_end + 1 == fl->fl_start) {
                    277:                                fl->fl_start = caller->fl_start;
                    278:                                free_lock(filp, caller);
                    279:                                caller = fl;
                    280:                                /* must continue, may overlap others now */
                    281:                        } else if (caller->fl_start - 1 == fl->fl_end) {
                    282:                                fl->fl_end = caller->fl_end;
                    283:                                free_lock(filp, caller);
                    284:                                caller = fl;
                    285:                                /* must continue, may overlap others now */
                    286:                        }
                    287:                        continue;
                    288:                }
                    289:                /*
                    290:                 * We've found an overlapping region. Is it a change of lock
                    291:                 * type, or are we changing the size of the locked space?
                    292:                 */
                    293:                if (caller->fl_type != fl->fl_type) {
                    294:                        if (caller->fl_start > fl->fl_start && caller->fl_end < fl->fl_end) {
                    295:                                /*
                    296:                                 * The new lock splits the old one in two ...
                    297:                                 * {fl} is the bottom piece, {caller} is the
                    298:                                 * new lock, and {new} is the top piece.
                    299:                                 */
                    300:                                if ((new = alloc_lock(filp, fl)) == NULL) {
                    301:                                        free_lock(filp, caller);
                    302:                                        return -ENOLCK;
                    303:                                }
                    304:                                fl->fl_end = caller->fl_start - 1;
                    305:                                new->fl_start = caller->fl_end + 1;
                    306:                                return 0;
                    307:                        }
                    308:                        if (caller->fl_start <= fl->fl_start && caller->fl_end >= fl->fl_end) {
                    309:                                /*
                    310:                                 * The new lock completely replaces old one ...
                    311:                                 */
                    312:                                free_lock(filp, fl);
                    313:                                return 0;
                    314:                        }
                    315:                        if (caller->fl_end < fl->fl_end) {
                    316:                                fl->fl_start = caller->fl_end + 1;
                    317:                                /* must continue, may be more overlaps */
                    318:                        } else if (caller->fl_start > fl->fl_start) {
                    319:                                fl->fl_end = caller->fl_start - 1;
                    320:                                /* must continue, may be more overlaps */
                    321:                        } else {
                    322:                                printk("lock_it: program bug: unanticipated overlap\n");
                    323:                                free_lock(filp, caller);
                    324:                                return -ENOLCK;
                    325:                        }
                    326:                } else {        /* The new lock augments an existing lock ... */
                    327:                        int grew = 0;
                    328: 
                    329:                        if (caller->fl_start < fl->fl_start) {
                    330:                                fl->fl_start = caller->fl_start;
                    331:                                grew = 1;
                    332:                        }
                    333:                        if (caller->fl_end > fl->fl_end) {
                    334:                                fl->fl_end = caller->fl_end;
                    335:                                grew = 1;
                    336:                        }
                    337:                        free_lock(filp, caller);
                    338:                        caller = fl;
                    339:                        if (!grew)
                    340:                                return 0;
                    341:                        /* must continue, may be more overlaps */
                    342:                }
                    343:        }
                    344: 
                    345:        /*
                    346:         * New lock doesn't overlap any regions ...
                    347:         * alloc_lock() has already been called, so we're done!
                    348:         */
                    349: 
                    350:        return 0;
                    351: }
                    352: 
                    353: /*
                    354:  * Handle F_UNLCK ...
                    355:  * Result is 0 for success, or -EINVAL or -ENOLCK.
                    356:  * ENOLCK can happen when a lock is split into two.
                    357:  */
                    358: 
                    359: static int unlock_it(struct file *filp, struct file_lock *caller)
                    360: {
                    361:        int one_unlocked = 0;
                    362:        struct file_lock *fl,*next;
                    363: 
                    364:        for (fl = filp->f_inode->i_flock; fl != NULL; ) {
                    365:                if (caller->fl_owner != fl->fl_owner || !overlap(caller, fl)) {
                    366:                        fl = fl->fl_next;
                    367:                        continue;
                    368:                }
                    369:                one_unlocked = 1;
                    370:                if (caller->fl_start > fl->fl_start && caller->fl_end < fl->fl_end) {
                    371:                        /*
                    372:                         * Lock is split in two ...
                    373:                         * {fl} is the bottom piece, {next} is the top piece.
                    374:                         */
                    375:                        if ((next = alloc_lock(filp, fl)) == NULL)
                    376:                                return -ENOLCK;
                    377:                        fl->fl_end = caller->fl_start - 1;
                    378:                        next->fl_start = caller->fl_end + 1;
                    379:                        return 0;
                    380:                }
                    381:                /*
                    382:                 * At this point we know there is an overlap and we know the
                    383:                 * lock isn't split into two ...
                    384:                 *
                    385:                 * Unless the lock table is broken, entries will not overlap.
                    386:                 * IE: User X won't have an entry locking bytes 1-3 and another
                    387:                 * entry locking bytes 3-5. Therefore, if the area being
                    388:                 * unlocked is a subset of the total area, we don't need to
                    389:                 * traverse any more of the list. The code is a tad more
                    390:                 * complicated by this optimization. Perhaps it's not worth it.
                    391:                 *
                    392:                 * WARNING: We assume free_lock() does not alter
                    393:                 *      {fl_start, fl_end}.
                    394:                 *
                    395:                 * {fl_next} gets clobbered when the entry is moved to
                    396:                 * the free list, so grab it now ...
                    397:                 */
                    398:                next = fl->fl_next;
                    399:                if (caller->fl_start <= fl->fl_start && caller->fl_end >= fl->fl_end) {
                    400:                        free_lock(filp, fl);
                    401:                } else if (caller->fl_start > fl->fl_start) {
                    402:                        fl->fl_end = caller->fl_start - 1;
                    403:                } else {
                    404:                        /* caller->fl_end < fl->fl_end */
                    405:                        fl->fl_start = caller->fl_end + 1;
                    406:                }
                    407:                if (caller->fl_start >= fl->fl_start && caller->fl_end <= fl->fl_end)
                    408:                        return 0;               /* no more to be found */
                    409:                fl = next;
                    410:                /* must continue, there may be more to unlock */
                    411:        }
                    412: 
                    413:        return one_unlocked ? 0 : -EINVAL;
                    414: }
                    415: 
                    416: static struct file_lock *alloc_lock(struct file *filp, struct file_lock *template)
                    417: {
                    418:        struct file_lock *new;
                    419: 
                    420:        if (file_lock_free_list == NULL)
                    421:                return NULL;                    /* no available entry */
                    422:        if (file_lock_free_list->fl_owner != NULL)
                    423:                panic("alloc_lock: broken free list\n");
                    424: 
                    425:        new = file_lock_free_list;              /* remove from free list */
                    426:        file_lock_free_list = file_lock_free_list->fl_next;
                    427: 
                    428:        *new = *template;
                    429: 
                    430:        new->fl_next = filp->f_inode->i_flock;  /* insert into file's list */
                    431:        filp->f_inode->i_flock = new;
                    432: 
                    433:        new->fl_owner = current;        /* FIXME: needed? */
                    434:        new->fl_wait = NULL;
                    435:        return new;
                    436: }
                    437: 
                    438: /*
                    439:  * Add a lock to the free list ...
                    440:  *
                    441:  * WARNING: We must not alter {fl_start, fl_end}. See unlock_it().
                    442:  */
                    443: 
                    444: static void free_lock(struct file *filp, struct file_lock *fl)
                    445: {
                    446:        struct file_lock **fl_p;
                    447: 
                    448:        if (fl->fl_owner == NULL)       /* sanity check */
                    449:                panic("free_lock: broken lock list\n");
                    450: 
                    451:        /*
                    452:         * We only use a singly linked list to save some memory space
                    453:         * (the only place we'd use a doubly linked list is here).
                    454:         */
                    455: 
                    456:        for (fl_p = &filp->f_inode->i_flock; *fl_p != NULL; fl_p = &(*fl_p)->fl_next) {
                    457:                if (*fl_p == fl)
                    458:                        break;
                    459:        }
                    460:        if (*fl_p == NULL) {
                    461:                printk("free_lock: lock is not in file's lock list\n");
                    462:        } else {
                    463:                *fl_p = (*fl_p)->fl_next;
                    464:        }
                    465: 
                    466:        fl->fl_next = file_lock_free_list;      /* add to free list */
                    467:        file_lock_free_list = fl;
                    468:        fl->fl_owner = NULL;                    /* for sanity checks */
                    469: 
                    470:        wake_up(&fl->fl_wait);
                    471: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.