Date: Mon, 17 Apr 1995 18:31:35 +1000 From: Stephen McKay <syssgm@devetir.qld.gov.au> To: current@FreeBSD.org Cc: syssgm@devetir.qld.gov.au Subject: fcntl F_SETLK backward compatibility kludge Message-ID: <199504170831.SAA27341@orion.devetir.qld.gov.au>
next in thread | raw e-mail | index | archive | help
Between 1.1.5 and 2.0, the format of one of the parameters to the fcntl() system call changed, but neither the system call number nor the command codes passed to it were updated to reflect this. This causes some 1.1.5 binaries to fail when run on 2.0 systems. This is a proposal which should almost totally heal this minor wart. Old struct flock from Freebsd 1.1.5 and earlier: type whence start length pid junk (because of padding) +-----+-----+-----------+-----------+-----+ - - + | 16 | 16 | 32 | 32 | 16 | | +-----+-----+-----------+-----------+-----+ - - + New struct flock from Freebsd 2.0 and later: start length pid type whence +-----------------------+-----------------------+-----------+-----+-----+ | 64 | 64 | 32 | 16 | 16 | +-----------------------+-----------------------+-----------+-----+-----+ I propose that fcntl() command codes 7, 8, 9 be reserved for the backward compatible locking calls, and new values 10, 11, 12 be allocated for use in FreeBSD 2.1 as F_GETLK, F_SETLK and F_SETLKW. Code bracketed by #ifdef COMPAT_43 should be added to fcntl() in kern_descrip.c to handle the old case in the following way: Using the fact that "type" must be 1, 2 or 3, and "whence" must be 0, 1 or 2, an educated guess can be made as to which of the two forms is being used by the currently executing binary. The two possible cases of confusion are when an old style struct flock is followed in memory by data that just happens to contain 1, 2 or 3 and 0, 1 or 2 in the right place, or when a new style struct flock specifies a start offset with a low 32 bits of 0x00000001, 0x00000002, 0x00000003, 0x00010001, 0x00010002, 0x00010003, 0x00020001, 0x00020002, or 0x00020003. In these cases, the old style should be assumed, possibly logging a kernel warning message. The assumption here is that the 2.0 binary is newer and thus more easily recompiled to use the unambiguous 2.1 fcntl() call. I have scanned the 2.0 source code for uses of fcntl() locking and have found four cases. "amd", "vi", and "sendmail" use fcntl() locking to simulate flock() locking if that is unavailable. "at" uses fcntl() locking, but only with full file locking (whence = 0, start = 0, end = 0) which is correctly detected by the above scheme. It seems likely that most uses of fcntl() locking are to simulate flock(), and will be correctly handled. If added complication is desired :-) a number of other checks can be done. It seems very unlikely that any program in this transitional situation is going to be using files >= 2^32 bytes, and so the high 32 bits of a new style "start" and "length" must be 0 or -1. Thus an old style flock with a "start" field not 0 or -1 will not be mistaken for a new style flock. Similarly, the "pid" field and padding of an old style struct flock can contain garbage, and be an unmistakable marker since it overlaps the high half of a new style "length" field. There are also some constraints on what values "start" and "length" can have for various values of "whence". If guessing for each call is not your idea of determinism, there are a few spare bits in u_pcb.pcb_flags in the user struct. A value could be determined on the first call, and stored here to remove future guesswork. So, how far should we go to support a few old binaries using a system call that the man page bags so heavily? My second favourite proposal after this one, is to convert the old calls to simply log a kernel error message, and return a failure code to the program. Old binaries will then be detected and hopefully upgraded. I am available to implement and test either of these solutions as I currently have both 1.1.5 and 2.0 at home. Stephen.
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199504170831.SAA27341>