diff --git a/acinclude.m4 b/acinclude.m4 index ae20bdeabd..199862127d 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -915,6 +915,8 @@ case $AFS_SYSNAME in *_linux* | *_umlinux*) LINUX_KERNEL_LINUX_SYSCALL_H LINUX_KERNEL_LINUX_SEQ_FILE_H LINUX_KERNEL_POSIX_LOCK_FILE_WAIT_ARG + LINUX_POSIX_TEST_LOCK_RETURNS_CONFLICT + LINUX_POSIX_TEST_LOCK_CONFLICT_ARG LINUX_KERNEL_SELINUX LINUX_KERNEL_SOCK_CREATE LINUX_KERNEL_PAGE_FOLLOW_LINK diff --git a/src/afs/LINUX/osi_vnodeops.c b/src/afs/LINUX/osi_vnodeops.c index 557129b66d..3bee72675f 100644 --- a/src/afs/LINUX/osi_vnodeops.c +++ b/src/afs/LINUX/osi_vnodeops.c @@ -504,13 +504,19 @@ afs_linux_lock(struct file *fp, int cmd, struct file_lock *flp) struct vcache *vcp = VTOAFS(FILE_INODE(fp)); cred_t *credp = crref(); struct AFS_FLOCK flock; +#if defined(POSIX_TEST_LOCK_CONFLICT_ARG) + struct file_lock conflict; +#elif defined(POSIX_TEST_LOCK_RETURNS_CONFLICT) + struct file_lock *conflict; +#endif + /* Convert to a lock format afs_lockctl understands. */ memset((char *)&flock, 0, sizeof(flock)); flock.l_type = flp->fl_type; flock.l_pid = flp->fl_pid; flock.l_whence = 0; flock.l_start = flp->fl_start; - flock.l_len = flp->fl_end - flp->fl_start; + flock.l_len = flp->fl_end - flp->fl_start + 1; /* Safe because there are no large files, yet */ #if defined(F_GETLK64) && (F_GETLK != F_GETLK64) @@ -529,12 +535,12 @@ afs_linux_lock(struct file *fp, int cmd, struct file_lock *flp) #ifdef AFS_LINUX24_ENV if ((code == 0 || flp->fl_type == F_UNLCK) && (cmd == F_SETLK || cmd == F_SETLKW)) { -#ifdef POSIX_LOCK_FILE_WAIT_ARG +# ifdef POSIX_LOCK_FILE_WAIT_ARG code = posix_lock_file(fp, flp, 0); -#else +# else flp->fl_flags &=~ FL_SLEEP; code = posix_lock_file(fp, flp); -#endif +# endif if (code && flp->fl_type != F_UNLCK) { struct AFS_FLOCK flock2; flock2 = flock; @@ -544,12 +550,40 @@ afs_linux_lock(struct file *fp, int cmd, struct file_lock *flp) AFS_GUNLOCK(); } } + /* If lockctl says there are no conflicting locks, then also check with the + * kernel, as lockctl knows nothing about byte range locks + */ + if (code == 0 && cmd == F_GETLK && flock.l_type == F_UNLCK) { +# if defined(POSIX_TEST_LOCK_CONFLICT_ARG) + if (posix_test_lock(fp, flp, &conflict)) { + locks_copy_lock(flp, &conflict); + flp->fl_type = F_UNLCK; + crfree(credp); + return 0; + } +# elif defined(POSIX_TEST_LOCK_RETURNS_CONFLICT) + if ((conflict = posix_test_lock(fp, flp))) { + locks_copy_lock(flp, conflict); + flp->fl_type = F_UNLCK; + crfee(credp); + return 0; + } +# else + posix_test_lock(fp, flp); + /* If we found a lock in the kernel's structure, return it */ + if (flp->fl_type != F_UNLCK) { + crfree(credp); + return 0; + } + } +# endif + #endif /* Convert flock back to Linux's file_lock */ flp->fl_type = flock.l_type; flp->fl_pid = flock.l_pid; flp->fl_start = flock.l_start; - flp->fl_end = flock.l_start + flock.l_len; + flp->fl_end = flock.l_start + flock.l_len - 1; crfree(credp); return -code; diff --git a/src/afs/VNOPS/afs_vnop_flock.c b/src/afs/VNOPS/afs_vnop_flock.c index 30e83a751d..bc405f2150 100644 --- a/src/afs/VNOPS/afs_vnop_flock.c +++ b/src/afs/VNOPS/afs_vnop_flock.c @@ -485,8 +485,13 @@ DoLockWarning(void) /* otherwise, it is time to nag the user */ lastWarnTime = now; +#ifdef AFS_LINUX26_ENV + afs_warn + ("afs: byte-range locks only enforced for processes on this machine.\n"); +#else afs_warn ("afs: byte-range lock/unlock ignored; make sure no one else is running this program.\n"); +#endif } diff --git a/src/cf/linux-test4.m4 b/src/cf/linux-test4.m4 index 2976499419..0b28ce1be6 100644 --- a/src/cf/linux-test4.m4 +++ b/src/cf/linux-test4.m4 @@ -486,7 +486,6 @@ AC_DEFUN([LINUX_KERNEL_POSIX_LOCK_FILE_WAIT_ARG], [ ac_cv_linux_kernel_posix_lock_file_wait_arg=no)]) AC_MSG_RESULT($ac_cv_linux_kernel_posix_lock_file_wait_arg)]) - AC_DEFUN([LINUX_KERNEL_SOCK_CREATE], [ AC_MSG_CHECKING([for 5th argument in sock_create found in some SELinux kernels]) AC_CACHE_VAL([ac_cv_linux_kernel_sock_create_v], [ @@ -1215,3 +1214,34 @@ _p.owner= "";], if test "x$ac_cv_linux_struct_proc_dir_entry_has_owner" = "xyes"; then AC_DEFINE([STRUCT_PROC_DIR_ENTRY_HAS_OWNER], 1, [define if struct proc_dir_entry has an owner member]) fi]) + +AC_DEFUN([LINUX_POSIX_TEST_LOCK_RETURNS_CONFLICT], [ + AC_MSG_CHECKING([if posix_test_lock returns a struct file_lock]) + AC_CACHE_VAL([ac_cv_linux_posix_test_lock_returns_conflict], [ + AC_TRY_KBUILD( +[#include ], +[struct file_lock *lock; + struct file * file; +lock = posix_test_lock(file, lock);], + ac_cv_linux_posix_test_lock_returns_conflict=yes, + ac_cv_linux_posix_test_lock_returns_conflict=no)]) + AC_MSG_RESULT($ac_cv_linux_posix_test_lock_returns_conflict) + if test "x$ac_cv_linux_posix_test_lock_returns_conflict" = "xyes"; then + AC_DEFINE([POSIX_TEST_LOCK_RETURNS_CONFLICT], 1, [define if posix_test_lock returns the conflicting lock]) + fi]) + +AC_DEFUN([LINUX_POSIX_TEST_LOCK_CONFLICT_ARG], [ + AC_MSG_CHECKING([if posix_test_lock takes a conflict argument]) + AC_CACHE_VAL([ac_cv_linux_posix_test_lock_conflict_arg], [ + AC_TRY_KBUILD( +[#include ], +[ struct file_lock *lock; + struct file *file; + posix_test_lock(file, lock, lock);], + ac_cv_linux_posix_test_lock_conflict_arg=yes, + ac_cv_lonuc_posix_test_lock_conflict_arg=no)]) + AC_MSG_RESULT($ac_cv_linux_posix_test_lock_conflict_arg) + if test "x$ac_cv_linux_posix_test_lock_conflict_arg" = "xyes"; then + AC_DEFINE([POSIX_TEST_LOCK_CONFLICT_ARG], 1, [define if posix_test_lock takes a conflict argument]) + fi]) +