[haiku-commits] haiku: hrev45359 - in src: system/kernel/fs add-ons/kernel/file_systems/nfs4

  • From: pdziepak@xxxxxxxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Tue, 12 Mar 2013 17:40:07 +0100 (CET)

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, &ltype, &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;
 


Other related posts:

  • » [haiku-commits] haiku: hrev45359 - in src: system/kernel/fs add-ons/kernel/file_systems/nfs4 - pdziepak