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)
#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;
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;
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], [
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 <linux/fs.h>],
+[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 <linux/fs.h>],
+[ 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])
+