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;
}

Attachment: signature.asc
Description: OpenPGP digital signature

Reply via email to