On 18.01.2017 11:48, Fam Zheng wrote: > On Fri, 12/02 03:58, Max Reitz wrote: >> On 31.10.2016 16:38, Fam Zheng wrote: >>> This implements open flag sensible image locking for local file >>> and host device protocol. >>> >>> virtlockd in libvirt locks the first byte, so we start looking at the >>> file bytes from 1. >>> >>> Quoting what was proposed by Kevin Wolf <kw...@redhat.com>, there are >>> four locking modes by combining two bits (BDRV_O_RDWR and >>> BDRV_O_SHARE_RW), and implemented by taking two locks: >>> >>> Lock bytes: >>> >>> * byte 1: I can't allow other processes to write to the image >>> * byte 2: I am writing to the image >>> >>> Lock modes: >>> >>> * shared writer (BDRV_O_RDWR | BDRV_O_SHARE_RW): Take shared lock on >>> byte 2. Test whether byte 1 is locked using an exclusive lock, and >>> fail if so. >> >> Testing whether something is locked would be easier by using F_OFD_GETLK >> instead of actually creating an exclusive lock and then releasing it. > > My attempt to do this shows it doesn't work: fcntl forces the tested lock type > to read lock for some unknown reason, so it cannot be used to test other > shared > lockers.
Do you have a reproducer? The attached quick and dirty test case works for me (compile test.c to test and test2.c to test2), producing the following output (when running ./test): set rd lock: 0, Success get lock: 0, Success; read lock in place set wr lock: -1, Resource temporarily unavailable unset lock: 0, Resource temporarily unavailable === unset lock: 0, Success get lock: 0, Success; unlocked set wr lock: 0, Success unset lock: 0, Success === set wr lock: 0, Success get lock: 0, Success; write lock in place set wr lock: -1, Resource temporarily unavailable unset lock: 0, Resource temporarily unavailable So the l_type field is correctly set after every F_OFD_GETLK query call. Max
#define _GNU_SOURCE #include <errno.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> int main(void) { system("touch foo"); int fd = open("foo", O_RDWR); int ret = fcntl(fd, F_OFD_SETLK, &(struct flock){ .l_type = F_RDLCK }); printf("set rd lock: %i, %s\n", ret, strerror(errno)); system("./test2"); printf("===\n"); ret = fcntl(fd, F_OFD_SETLK, &(struct flock){ .l_type = F_UNLCK }); printf("unset lock: %i, %s\n", ret, strerror(errno)); system("./test2"); printf("===\n"); ret = fcntl(fd, F_OFD_SETLK, &(struct flock){ .l_type = F_WRLCK }); printf("set wr lock: %i, %s\n", ret, strerror(errno)); system("./test2"); close(fd); return 0; }
#define _GNU_SOURCE #include <errno.h> #include <fcntl.h> #include <stdio.h> #include <string.h> #include <unistd.h> static const char *lock_names[] = { [F_UNLCK] = "unlocked", [F_RDLCK] = "read lock in place", [F_WRLCK] = "write lock in place", }; int main(void) { int fd = open("foo", O_RDWR); struct flock fl = { .l_type = F_WRLCK }; int ret = fcntl(fd, F_OFD_GETLK, &fl); printf("get lock: %i, %s; %s\n", ret, strerror(errno), lock_names[fl.l_type]); ret = fcntl(fd, F_OFD_SETLK, &(struct flock){ .l_type = F_WRLCK }); printf("set wr lock: %i, %s\n", ret, strerror(errno)); close(fd); return 0; }
signature.asc
Description: OpenPGP digital signature