This is the mail archive of the libc-hacker@sourceware.cygnus.com mailing list for the glibc project.

Note that libc-hacker is a closed list. You may look at the archives of this list, but subscription and posting are not open.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: struct flock with fcntl and _FILE_OFFSET_BITS=64 is broken


>>>>> Ulrich Drepper writes:

 > Andreas Jaeger <aj@suse.de> writes:
>> B) The other alternative is to add fcntl64 and handle it the usual
>> way:

 > This one.
I don't like this solution anymore.  It would mean we would have a
fcntl64 call which does basically:

int fcntl64 (int fd, int cmd, ...)

{
....
  switch (cmd)
   {
     case F_SETLK:
                cmd = F_SETLK64;
                break;
     case F_SETLKW:
                cmd = F_SETLKW64;
                break;
     case F_GETLK:
                cmd = F_GETLK;
                break;
    default:
                break;
   }
  return INLINE_SYSCALL (fcntl64, 3, fd, cmd, arg);
}

Solution a) would involve fcntl64 just as a normal syscall - without
any conversion we need to do.

Another problem is that we need to convert betweeen struct flock64 and struct
flock if fcntl64 is not available.  Solution b) would mean we have to
do this in fcntl *and* fcntl64. With solution a) there's only a
possible conversion in fcntl.

Have a look at the appended patch which implements solution a) and
requires Andrea's LFS locking patch for Linux 2.3.99.

Could you please consider this again?

Thanks,
Andreas


============================================================
Index: sysdeps/unix/sysv/linux/i386/bits/fcntl.h
--- sysdeps/unix/sysv/linux/i386/bits/fcntl.h	1998/10/25 09:09:23	1.3
+++ sysdeps/unix/sysv/linux/i386/bits/fcntl.h	2000/05/09 15:02:02
@@ -1,5 +1,5 @@
 /* O_*, F_*, FD_* bit values for Linux.
-   Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+   Copyright (C) 1995, 1996, 1997, 1998, 2000 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -69,10 +69,15 @@
 #define F_SETLK		6	/* Set record locking info (non-blocking).  */
 #define F_SETLKW	7	/* Set record locking info (blocking).  */
 
-/* XXX missing */
-#define F_GETLK64	5	/* Get record locking info.  */
-#define F_SETLK64	6	/* Set record locking info (non-blocking).  */
-#define F_SETLKW64	7	/* Set record locking info (blocking).  */
+#ifndef __USE_FILE_OFFSET64
+# define F_GETLK64	12	/* Get record locking info.  */
+# define F_SETLK64	13	/* Set record locking info (non-blocking).  */
+# define F_SETLKW64	14	/* Set record locking info (blocking).  */
+#else
+# define F_GETLK64	F_GETLK	/* Get record locking info.  */
+# define F_SETLK64	F_SETLK	/* Set record locking info (non-blocking).  */
+# define F_SETLKW64	F_SETLKW /* Set record locking info (blocking).  */
+#endif
 
 #ifdef __USE_BSD
 # define F_SETOWN	8	/* Get owner of socket (receiver of SIGIO).  */
============================================================
Index: sysdeps/unix/sysv/linux/sparc/bits/fcntl.h
--- sysdeps/unix/sysv/linux/sparc/bits/fcntl.h	2000/01/04 19:55:10	1.6.2.2
+++ sysdeps/unix/sysv/linux/sparc/bits/fcntl.h	2000/05/09 15:02:02
@@ -79,10 +79,15 @@
 # define F_GETSIG	11	/* Get number of signal to be sent.  */
 #endif
 
-/* XXX missing */
-#define F_GETLK64	7	/* Get record locking info.  */
-#define F_SETLK64	8	/* Set record locking info (non-blocking).  */
-#define F_SETLKW64	9	/* Set record locking info (blocking).  */
+#ifndef __USE_FILE_OFFSET64
+# define F_GETLK64	12	/* Get record locking info.  */
+# define F_SETLK64	13	/* Set record locking info (non-blocking).  */
+# define F_SETLKW64	14	/* Set record locking info (blocking).  */
+#else
+# define F_GETLK64	F_GETLK	/* Get record locking info.  */
+# define F_SETLK64	F_SETLK	/* Set record locking info (non-blocking).  */
+# define F_SETLKW64	F_SETLKW /* Set record locking info (blocking).  */
+#endif
 
 /* for F_[GET|SET]FL */
 #define FD_CLOEXEC	1	/* actually anything with low bit set goes */
============================================================
Index: sysdeps/unix/sysv/linux/alpha/bits/fcntl.h
--- sysdeps/unix/sysv/linux/alpha/bits/fcntl.h	1999/08/05 17:40:36	1.7.2.1
+++ sysdeps/unix/sysv/linux/alpha/bits/fcntl.h	2000/05/09 15:02:02
@@ -72,10 +72,9 @@
 #define F_SETLK		8	/* Set record locking info (non-blocking).  */
 #define F_SETLKW	9	/* Set record locking info (blocking).  */
 
-/* XXX missing */
-#define F_GETLK64	7	/* Get record locking info.  */
-#define F_SETLK64	8	/* Set record locking info (non-blocking).  */
-#define F_SETLKW64	9	/* Set record locking info (blocking).  */
+#define F_GETLK64	F_GETLK	/* Get record locking info.  */
+#define F_SETLK64	F_SETLK	/* Set record locking info (non-blocking).  */
+#define F_SETLKW64	F_SETLKW /* Set record locking info (blocking).  */
 
 #ifdef __USE_BSD
 # define F_SETOWN	5	/* Get owner of socket (receiver of SIGIO).  */
============================================================
Index: sysdeps/unix/sysv/linux/i386/lockf64.c
--- sysdeps/unix/sysv/linux/i386/lockf64.c	created
+++ sysdeps/unix/sysv/linux/i386/lockf64.c	Tue May  9 11:06:57 2000	1.1
@@ -0,0 +1,157 @@
+/* Copyright (C) 1994, 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <sysdep.h>
+
+/* lockf is a simplified interface to fcntl's locking facilities.  */
+
+#ifdef __NR_fcntl64
+extern int __syscall_fcntl64 (int __fd, int __cmd, ...);
+
+/* This is declared in fcntl.c.  */
+extern int __have_no_fcntl64;
+#endif
+
+int
+lockf64 (int fd, int cmd, off64_t len64)
+{
+  struct flock fl;
+#ifdef __NR_fcntl64
+  struct flock64 fl64;
+  int cmd64;
+#endif
+  off_t len = (off_t) len64;
+
+  memset ((char *) &fl, '\0', sizeof (fl));
+
+  /* lockf is always relative to the current file position.  */
+  fl.l_whence = SEEK_CUR;
+  fl.l_start = 0;
+  fl.l_len = len;
+
+#ifdef __NR_fcntl64
+  if (!__have_no_fcntl64)
+    {
+      memset ((char *) &fl64, '\0', sizeof (fl64));
+      fl64.l_whence = SEEK_CUR;
+      fl64.l_start = 0;
+      fl64.l_len = len64;
+    }
+#endif
+
+#ifndef __NR_fcntl64
+  if (len64 != (off64_t) len)
+    {
+      /* We can't represent the length.  */
+      __set_errno (EOVERFLOW);
+      return -1;
+    }
+#endif
+
+  switch (cmd)
+    {
+    case F_TEST:
+      /* Test the lock: return 0 if FD is unlocked or locked by this process;
+	 return -1, set errno to EACCES, if another process holds the lock.  */
+#ifdef __NR_fcntl64
+      if (!__have_no_fcntl64)
+	{
+	  int res = INLINE_SYSCALL (fcntl64, 3, fd, F_GETLK64, &fl64);
+
+	  /* If errno == ENOSYS try the 32bit interface if len64 can
+             be represented with 32 bits.  */
+
+	  if (res == 0)
+	    {
+	      if (fl64.l_type == F_UNLCK || fl64.l_pid == __getpid ())
+		return 0;
+	      __set_errno (EACCES);
+	      return -1;
+	    }
+	  else if (errno == ENOSYS)
+	    __have_no_fcntl64 = 1;
+	  else
+	    /* res < 0 && errno != ENOSYS.  */
+	    return -1;
+	  if (len64 != (off64_t) len)
+	    {
+	      /* We can't represent the length.  */
+	      __set_errno (EOVERFLOW);
+	      return -1;
+	    }
+	}
+#endif
+      if (__fcntl (fd, F_GETLK, &fl) < 0)
+	return -1;
+      if (fl.l_type == F_UNLCK || fl.l_pid == __getpid ())
+	return 0;
+      __set_errno (EACCES);
+      return -1;
+    case F_ULOCK:
+      fl.l_type = F_UNLCK;
+      cmd = F_SETLK;
+#ifdef __NR_fcntl64
+      cmd64 = F_SETLK64;
+#endif
+      break;
+    case F_LOCK:
+      fl.l_type = F_WRLCK;
+      cmd = F_SETLKW;
+#ifdef __NR_fcntl64
+      cmd64 = F_SETLKW64;
+#endif
+      break;
+    case F_TLOCK:
+      fl.l_type = F_WRLCK;
+      cmd = F_SETLK;
+#ifdef __NR_fcntl64
+      cmd64 = F_SETLK64;
+#endif
+      break;
+
+    default:
+      __set_errno (EINVAL);
+      return -1;
+    }
+#ifdef __NR_fcntl64
+  if (!__have_no_fcntl64)
+    {
+      int res = INLINE_SYSCALL (fcntl64, 3, fd, cmd64, &fl64);
+
+      /* If errno == ENOSYS try the 32bit interface if len64 can
+	 be represented with 32 bits.  */
+      if (res == 0 || errno != ENOSYS)
+	return res;
+
+      __have_no_fcntl64 = 1;
+
+      if (len64 != (off64_t) len)
+	{
+	  /* We can't represent the length.  */
+	  __set_errno (EOVERFLOW);
+	  return -1;
+	}
+    }
+#endif
+  return __fcntl (fd, cmd, &fl);
+}
============================================================
Index: sysdeps/unix/sysv/linux/i386/fcntl.c
--- sysdeps/unix/sysv/linux/i386/fcntl.c	created
+++ sysdeps/unix/sysv/linux/i386/fcntl.c	Tue May  9 11:47:12 2000	1.1
@@ -0,0 +1,124 @@
+/* Copyright (C) 2000 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdarg.h>
+
+#include <sysdep.h>
+
+/* lockf is a simplified interface to fcntl's locking facilities.  */
+
+#ifdef __NR_fcntl64
+extern int __syscall_fcntl64 (int __fd, int __cmd, ...);
+
+int __have_no_fcntl64;
+#endif
+
+int
+__libc_fcntl (int fd, int cmd, ...)
+{
+  void *arg;
+  va_list ap;
+
+  /* XXX: Shall we do this only for F_GETLK, F_SETLK, F_SETLK64?  */
+  va_start (ap, cmd);
+  arg = va_arg (ap, void *);
+
+#ifdef __NR_fcntl64
+  if (! __have_no_fcntl64)
+    {
+      int result = INLINE_SYSCALL (fcntl64, fd, cmd, arg);
+      if (result >= 0 || errno != ENOSYS)
+	return result;
+
+      __have_no_fcntl64 = 1;
+    }
+#endif
+  switch (cmd)
+    {
+    case F_GETLK64:
+      /* Convert arg from flock64 to flock and back.  */
+      {
+	struct flock fl;
+	struct flock64 *fl64 = arg;
+	int res;
+
+	fl.l_start = (off_t)fl64->l_start;
+	/* Check if we can represent the values with the smaller type.  */
+	if ((off64_t)fl.l_start != fl64->l_start)
+	  {
+	    __set_errno (EOVERFLOW);
+	    return -1;
+	  }
+	fl.l_len = (off_t)fl64->l_len;
+	/* Check if we can represent the values with the smaller type.  */
+	if ((off64_t)fl.l_len != fl64->l_len)
+	  {
+	    __set_errno (EOVERFLOW);
+	    return -1;
+	  }
+	fl.l_type = fl64->l_type;
+	fl.l_whence = fl64->l_whence;
+	fl.l_pid = fl64->l_pid;
+
+	res = INLINE_SYSCALL (fcntl, 3, fd, cmd, &fl);
+	if (res  != 0)
+	  return res;
+	/* Everything ok, convert back.  */
+	fl64->l_type = fl.l_type;
+	fl64->l_whence = fl.l_whence;
+	fl64->l_start = fl.l_start;
+	fl64->l_len = fl.l_len;
+	fl64->l_pid = fl.l_pid;
+
+	return 0;
+      }
+    case F_SETLK64:
+    case F_SETLKW64:
+      /* Try to convert arg from flock64 to flock.  */
+      {
+	struct flock fl;
+	struct flock64 *fl64 = arg;
+	fl.l_start = (off_t)fl64->l_start;
+	/* Check if we can represent the values with the smaller type.  */
+	if ((off64_t)fl.l_start != fl64->l_start)
+	  {
+	    __set_errno (EOVERFLOW);
+	    return -1;
+	  }
+	fl.l_len = (off_t)fl64->l_len;
+	/* Check if we can represent the values with the smaller type.  */
+	if ((off64_t)fl.l_len != fl64->l_len)
+	  {
+	    __set_errno (EOVERFLOW);
+	    return -1;
+	  }
+	fl.l_type = fl64->l_type;
+	fl.l_whence = fl64->l_whence;
+	fl.l_pid = fl64->l_pid;
+	return INLINE_SYSCALL (fcntl, 3, fd, cmd, &fl);
+      }
+    default:
+      return INLINE_SYSCALL (fcntl, 3, fd, cmd, arg);
+    }
+  return -1;
+}
+strong_alias (__libc_fcntl, __fcntl)
+weak_alias (__libc_fcntl, fcntl)
============================================================
Index: sysdeps/unix/sysv/linux/sparc/sparc32/fcntl.c
--- sysdeps/unix/sysv/linux/sparc/sparc32/fcntl.c	created
+++ sysdeps/unix/sysv/linux/sparc/sparc32/fcntl.c	Tue May  9 16:50:51 2000	1.1
@@ -0,0 +1 @@
+#include <sysdeps/unix/sysv/linux/i386/fcntl.c>
============================================================
Index: sysdeps/unix/sysv/linux/sparc/sparc32/lockf64.c
--- sysdeps/unix/sysv/linux/sparc/sparc32/lockf64.c	created
+++ sysdeps/unix/sysv/linux/sparc/sparc32/lockf64.c	Tue May  9 16:51:16 2000	1.1
@@ -0,0 +1 @@
+#include <sysdeps/unix/sysv/linux/i386/lockf64.c>
     
-- 
 Andreas Jaeger
  SuSE Labs aj@suse.de
   private aj@arthur.rhein-neckar.de

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]