Ticket #8661: 0001-Fix-8661-fcntl-fd-F_GETLK-.-violates-POSIX.patch

File 0001-Fix-8661-fcntl-fd-F_GETLK-.-violates-POSIX.patch, 3.9 KB (added by pdziepak, 8 years ago)
  • src/system/kernel/fs/vfs.cpp

    From ab8ac5e4025ee6cffa5da63aec10277f0f9bb9c4 Mon Sep 17 00:00:00 2001
    From: Pawel Dziepak <pdziepak@quarnos.org>
    Date: Fri, 29 Jun 2012 17:33:10 +0200
    Subject: [PATCH] Fix #8661: fcntl(fd, F_GETLK, ...) violates POSIX
    
    The standard states that F_GETLK should check whether given lock would be
    blocked by another one and return description of the conflicting one (or
    set l_type to F_UNLCK if there is no collision).
    
    Current implementation of F_GETLK performs completely different actions, it
    "Retrieves the first lock that has been set by the current team". Moreover,
    if there are no locks (advisory_locking == NULL) an error is returned
    instead of l_type set to F_UNLCK.
    ---
     src/system/kernel/fs/vfs.cpp |   81 +++++++++++++++++++++++++++---------------
     1 file changed, 53 insertions(+), 28 deletions(-)
    
    diff --git a/src/system/kernel/fs/vfs.cpp b/src/system/kernel/fs/vfs.cpp
    index 6737a30..882c061 100644
    a b create_advisory_locking(struct vnode* vnode)  
    15241524}
    15251525
    15261526
    1527 /*! Retrieves the first lock that has been set by the current team.
     1527/*! Returns \c true when either \a flock is \c NULL or the \a flock intersects
     1528    with the advisory_lock \a lock.
     1529*/
     1530static bool
     1531advisory_lock_intersects(struct advisory_lock* lock, struct flock* flock)
     1532{
     1533    if (flock == NULL)
     1534        return true;
     1535
     1536    return lock->start <= flock->l_start - 1 + flock->l_len
     1537        && lock->end >= flock->l_start;
     1538}
     1539
     1540
     1541/*! Tests whether acquiring a lock would block.
    15281542*/
    15291543static status_t
    1530 get_advisory_lock(struct vnode* vnode, struct flock* flock)
     1544test_advisory_lock(struct vnode* vnode, struct flock* flock)
    15311545{
     1546    flock->l_type = F_UNLCK;
     1547
    15321548    struct advisory_locking* locking = get_advisory_locking(vnode);
    15331549    if (locking == NULL)
    1534         return B_BAD_VALUE;
     1550        return B_OK;
    15351551
    1536     // TODO: this should probably get the flock by its file descriptor!
    15371552    team_id team = team_get_current_team_id();
    1538     status_t status = B_BAD_VALUE;
    15391553
     1554    // test for collisions
    15401555    LockList::Iterator iterator = locking->locks.GetIterator();
    15411556    while (iterator.HasNext()) {
    15421557        struct advisory_lock* lock = iterator.Next();
    15431558
    1544         if (lock->team == team) {
    1545             flock->l_start = lock->start;
    1546             flock->l_len = lock->end - lock->start + 1;
    1547             status = B_OK;
    1548             break;
     1559        if (lock->team != team && advisory_lock_intersects(lock, flock)) {
     1560            // locks do overlap
     1561            if (flock->l_type != F_RDLCK || !lock->shared) {
     1562                // collision
     1563                flock->l_type = lock->shared ? F_RDLCK : F_WRLCK;
     1564                flock->l_whence = SEEK_SET;
     1565                flock->l_start = lock->start;
     1566                flock->l_len = lock->end - lock->start + 1;
     1567                flock->l_pid = lock->team;
     1568
     1569                break;
     1570            }
    15491571        }
    15501572    }
    15511573
    15521574    put_advisory_locking(locking);
    1553     return status;
    1554 }
    1555 
    1556 
    1557 /*! Returns \c true when either \a flock is \c NULL or the \a flock intersects
    1558     with the advisory_lock \a lock.
    1559 */
    1560 static bool
    1561 advisory_lock_intersects(struct advisory_lock* lock, struct flock* flock)
    1562 {
    1563     if (flock == NULL)
    1564         return true;
    1565 
    1566     return lock->start <= flock->l_start - 1 + flock->l_len
    1567         && lock->end >= flock->l_start;
     1575    return B_OK;
    15681576}
    15691577
    15701578
    common_fcntl(int fd, int op, uint32 argument, bool kernel)  
    60066014
    60076015        case F_GETLK:
    60086016            if (vnode != NULL) {
    6009                 status = get_advisory_lock(vnode, &flock);
     6017                struct flock tmp;
     6018                memcpy(&tmp, &flock, sizeof(struct flock));
     6019
     6020                status = normalize_flock(descriptor, &tmp);
     6021                if (status != B_OK)
     6022                    break;
     6023
     6024                status = test_advisory_lock(vnode, &tmp);
    60106025                if (status == B_OK) {
    60116026                    // copy back flock structure
    6012                     status = user_memcpy((struct flock*)argument, &flock,
    6013                         sizeof(struct flock));
     6027                    if (tmp.l_type == F_UNLCK) {
     6028                        flock.l_type = F_UNLCK;
     6029
     6030                        status = user_memcpy((struct flock*)argument, &flock,
     6031                            sizeof(struct flock));
     6032                    } else {
     6033                        if (tmp.l_len == OFF_MAX)
     6034                            tmp.l_len = 0;
     6035
     6036                        status = user_memcpy((struct flock*)argument, &tmp,
     6037                            sizeof(struct flock));
     6038                    }
    60146039                }
    60156040            } else
    60166041                status = B_BAD_VALUE;