hrev45359 adds 2 changesets to branch 'master' old head: 0b269c601fca3163876b463baaa5a52cef8ccf26 new head: c5a88cf7e6c5f032e1aecea28cf3d90d0c1b7310 overview: http://cgit.haiku-os.org/haiku/log/?qt=range&q=c5a88cf+%5E0b269c6 ---------------------------------------------------------------------------- 1a0386d: 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. c5a88cf: nfs4: VFS uses signed offsets while NFS4 expects unsigned [ Pawel Dziepak <pdziepak@xxxxxxxxxxx> ] ---------------------------------------------------------------------------- 3 files changed, 62 insertions(+), 33 deletions(-) src/add-ons/kernel/file_systems/nfs4/Inode.cpp | 8 +- .../file_systems/nfs4/ReplyInterpreter.cpp | 2 +- src/system/kernel/fs/vfs.cpp | 85 +++++++++++++------- ############################################################################ Commit: 1a0386d743c1e6ffa823e2158192247509564c88 URL: http://cgit.haiku-os.org/haiku/commit/?id=1a0386d Author: Pawel Dziepak <pdziepak@xxxxxxxxxxx> Date: Tue Mar 12 16:35:54 2013 UTC Ticket: https://dev.haiku-os.org/ticket/8661 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. ---------------------------------------------------------------------------- diff --git a/src/system/kernel/fs/vfs.cpp b/src/system/kernel/fs/vfs.cpp index 27613f8..399caf5 100644 --- a/src/system/kernel/fs/vfs.cpp +++ b/src/system/kernel/fs/vfs.cpp @@ -1524,47 +1524,53 @@ create_advisory_locking(struct vnode* vnode) } -/*! Retrieves the first lock that has been set by the current team. +/*! Returns \c true when either \a flock is \c NULL or the \a flock intersects + with the advisory_lock \a lock. +*/ +static bool +advisory_lock_intersects(struct advisory_lock* lock, struct flock* flock) +{ + if (flock == NULL) + return true; + + return lock->start <= flock->l_start - 1 + flock->l_len + && lock->end >= flock->l_start; +} + + +/*! Tests whether acquiring a lock would block. */ static status_t -get_advisory_lock(struct vnode* vnode, struct flock* flock) +test_advisory_lock(struct vnode* vnode, struct flock* flock) { + flock->l_type = F_UNLCK; + struct advisory_locking* locking = get_advisory_locking(vnode); if (locking == NULL) - return B_BAD_VALUE; + return B_OK; - // TODO: this should probably get the flock by its file descriptor! team_id team = team_get_current_team_id(); - status_t status = B_BAD_VALUE; LockList::Iterator iterator = locking->locks.GetIterator(); while (iterator.HasNext()) { struct advisory_lock* lock = iterator.Next(); - if (lock->team == team) { - flock->l_start = lock->start; - flock->l_len = lock->end - lock->start + 1; - status = B_OK; - break; + if (lock->team != team && advisory_lock_intersects(lock, flock)) { + // locks do overlap + if (flock->l_type != F_RDLCK || !lock->shared) { + // collision + flock->l_type = lock->shared ? F_RDLCK : F_WRLCK; + flock->l_whence = SEEK_SET; + flock->l_start = lock->start; + flock->l_len = lock->end - lock->start + 1; + flock->l_pid = lock->team; + break; + } } } put_advisory_locking(locking); - return status; -} - - -/*! Returns \c true when either \a flock is \c NULL or the \a flock intersects - with the advisory_lock \a lock. -*/ -static bool -advisory_lock_intersects(struct advisory_lock* lock, struct flock* flock) -{ - if (flock == NULL) - return true; - - return lock->start <= flock->l_start - 1 + flock->l_len - && lock->end >= flock->l_start; + return B_OK; } @@ -6018,15 +6024,34 @@ common_fcntl(int fd, int op, size_t argument, bool kernel) case F_GETLK: if (vnode != NULL) { + struct flock normalizedLock; + + memcpy(&normalizedLock, &flock, sizeof(struct flock)); + status = normalize_flock(descriptor, &normalizedLock); + if (status != B_OK) + break; + if (HAS_FS_CALL(vnode, test_lock)) { status = FS_CALL(vnode, test_lock, descriptor->cookie, - &flock); + &normalizedLock); } else - status = get_advisory_lock(vnode, &flock); + status = test_advisory_lock(vnode, &normalizedLock); if (status == B_OK) { - // copy back flock structure - status = user_memcpy((struct flock*)argument, &flock, - sizeof(struct flock)); + if (normalizedLock.l_type == F_UNLCK) { + // no conflicting lock found, copy back the same struct + // we were given except change type to F_UNLCK + flock.l_type = F_UNLCK; + status = user_memcpy((struct flock*)argument, &flock, + sizeof(struct flock)); + } else { + // a conflicting lock was found, copy back its range and + // type + if (normalizedLock.l_len == OFF_MAX) + normalizedLock.l_len = 0; + + status = user_memcpy((struct flock*)argument, + &normalizedLock, sizeof(struct flock)); + } } } else status = B_BAD_VALUE; ############################################################################ Revision: hrev45359 Commit: c5a88cf7e6c5f032e1aecea28cf3d90d0c1b7310 URL: http://cgit.haiku-os.org/haiku/commit/?id=c5a88cf Author: Pawel Dziepak <pdziepak@xxxxxxxxxxx> Date: Tue Mar 12 16:36:53 2013 UTC nfs4: VFS uses signed offsets while NFS4 expects unsigned ---------------------------------------------------------------------------- diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index fe3d60d..abebe6f 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -696,9 +696,13 @@ Inode::TestLock(OpenFileCookie* cookie, struct flock* lock) LockType ltype = sGetLockType(lock->l_type, false); uint64 position = lock->l_start; - uint64 length = lock->l_len; - bool conflict; + uint64 length; + if (lock->l_len + lock->l_start == OFF_MAX) + length = UINT64_MAX; + else + length = lock->l_len; + bool conflict; result = NFS4Inode::TestLock(cookie, <ype, &position, &length, conflict); if (result != B_OK) return result; diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index 271cabb..1dbcd8d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -234,7 +234,7 @@ ReplyInterpreter::Lock(LockInfo* linfo) status_t ReplyInterpreter::LockT(uint64* pos, uint64* len, LockType* type) { - status_t res = _OperationError(OpLockU); + status_t res = _OperationError(OpLockT); if (res != B_WOULD_BLOCK || NFS4Error() != NFS4ERR_DENIED) return res;