---
---
block.c | 41 +++++++++++++++++++++++++++++++++++
block.h | 8 ++++++
block/raw-posix.c | 63
++++++++++++++++++++++++++++++++++++++++++++++++++++++
block/raw-win32.c | 52 ++++++++++++++++++++++++++++++++++++++++++++
block_int.h | 4 +++
5 files changed, 168 insertions(+)
Index: qemu-git/block.c
===================================================================
--- qemu-git.orig/block.c
+++ qemu-git/block.c
@@ -521,6 +521,8 @@ static int bdrv_open_common(BlockDriverS
goto free_and_fail;
}
+ drv->num_locks = 0;
+
bs->keep_read_only = bs->read_only = !(open_flags& BDRV_O_RDWR);
ret = refresh_total_sectors(bs, bs->total_sectors);
@@ -1316,6 +1318,45 @@ void bdrv_get_geometry(BlockDriverState
*nb_sectors_ptr = length;
}
+/* file locking */
+static int bdrv_lock_common(BlockDriverState *bs, BDRVLockType lock_type)
+{
+ BlockDriver *drv = bs->drv;
+
+ if (!drv) {
+ return -ENOMEDIUM;
+ }
+
+ if (bs->file) {
+ drv = bs->file->drv;
+ if (drv->bdrv_lock) {
+ return drv->bdrv_lock(bs->file, lock_type);
+ }
+ }
+
+ if (drv->bdrv_lock) {
+ return drv->bdrv_lock(bs, lock_type);
+ }
+
+ return -ENOTSUP;
+}
+
+
+int bdrv_lock(BlockDriverState *bs)
+{
+ if (bdrv_is_read_only(bs)) {
+ return bdrv_lock_common(bs, BDRV_F_RDLCK);
+ }
+
+ return bdrv_lock_common(bs, BDRV_F_WRLCK);
+}
+
+void bdrv_unlock(BlockDriverState *bs)
+{
+ bdrv_lock_common(bs, BDRV_F_UNLCK);
+}
+
+
struct partition {
uint8_t boot_ind; /* 0x80 - active */
uint8_t head; /* starting head */
Index: qemu-git/block.h
===================================================================
--- qemu-git.orig/block.h
+++ qemu-git/block.h
@@ -43,6 +43,12 @@ typedef struct QEMUSnapshotInfo {
#define BDRV_SECTOR_MASK ~(BDRV_SECTOR_SIZE - 1)
typedef enum {
+ BDRV_F_UNLCK,
+ BDRV_F_RDLCK,
+ BDRV_F_WRLCK,
+} BDRVLockType;
+
+typedef enum {
BLOCK_ERR_REPORT, BLOCK_ERR_IGNORE, BLOCK_ERR_STOP_ENOSPC,
BLOCK_ERR_STOP_ANY
} BlockErrorAction;
@@ -100,6 +106,8 @@ int bdrv_commit(BlockDriverState *bs);
void bdrv_commit_all(void);
int bdrv_change_backing_file(BlockDriverState *bs,
const char *backing_file, const char *backing_fmt);
+int bdrv_lock(BlockDriverState *bs);
+void bdrv_unlock(BlockDriverState *bs);
void bdrv_register(BlockDriver *bdrv);
Index: qemu-git/block/raw-posix.c
===================================================================
--- qemu-git.orig/block/raw-posix.c
+++ qemu-git/block/raw-posix.c
@@ -803,6 +803,67 @@ static int64_t raw_get_allocated_file_si
return (int64_t)st.st_blocks * 512;
}
+static int raw_lock(BlockDriverState *bs, BDRVLockType lock_type)
+{
+ BlockDriver *drv = bs->drv;
+ BDRVRawState *s = bs->opaque;
+ struct flock flock = {
+ .l_whence = SEEK_SET,
+ .l_start = 0,
+ .l_len = 0,
+ };
+ int n;
+
+ switch (lock_type) {
+ case BDRV_F_RDLCK:
+ case BDRV_F_WRLCK:
+ if (drv->num_locks) {
+ drv->num_locks++;
+ return 0;
+ }
+ flock.l_type = (lock_type == BDRV_F_RDLCK) ? F_RDLCK : F_WRLCK;
+ break;
+
+ case BDRV_F_UNLCK:
+ if (--drv->num_locks> 0) {
+ return 0;
+ }
+
+ assert(drv->num_locks == 0);
+
+ flock.l_type = F_UNLCK;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ while (1) {
+ n = fcntl(s->fd, F_SETLKW,&flock);
+ if (n< 0) {
+ if (errno == EINTR) {
+ continue;
+ }
+ if (errno == EAGAIN) {
+ usleep(10000);
+ continue;
+ }
+ }
+ break;
+ }
+
+ if (n == 0&&
+ ((lock_type == BDRV_F_RDLCK) || (lock_type == BDRV_F_WRLCK))) {
+ drv->num_locks = 1;
+ }
+
+ if (n) {
+ return -errno;
+ }
+
+ return 0;
+}
+
static int raw_create(const char *filename, QEMUOptionParameter *options)
{
int fd;
@@ -901,6 +962,8 @@ static BlockDriver bdrv_file = {
.bdrv_get_allocated_file_size
= raw_get_allocated_file_size,
+ .bdrv_lock = raw_lock,
+
.create_options = raw_create_options,
};
Index: qemu-git/block_int.h
===================================================================
--- qemu-git.orig/block_int.h
+++ qemu-git/block_int.h
@@ -146,6 +146,10 @@ struct BlockDriver {
*/
int (*bdrv_has_zero_init)(BlockDriverState *bs);
+ /* File locking */
+ int num_locks;
+ int (*bdrv_lock)(BlockDriverState *bs, BDRVLockType lock_type);
+
QLIST_ENTRY(BlockDriver) list;
};
Index: qemu-git/block/raw-win32.c
===================================================================
--- qemu-git.orig/block/raw-win32.c
+++ qemu-git/block/raw-win32.c
@@ -242,6 +242,57 @@ static int64_t raw_get_allocated_file_si
return st.st_size;
}
+static int raw_lock(BlockDriverState *bs, int lock_type)
+{
+ BlockDriver *drv = bs->drv;
+ BDRVRawState *s = bs->opaque;
+ OVERLAPPED ov;
+ BOOL res;
+ DWORD num_bytes;
+
+ switch (lock_type) {
+ case BDRV_F_RDLCK:
+ case BDRV_F_WRLCK:
+ if (drv->num_locks) {
+ drv->num_locks++;
+ return 0;
+ }
+
+ memset(&ov, 0, sizeof(ov));
+
+ res = LockFileEx(s->hfile, LOCKFILE_EXCLUSIVE_LOCK, 0, ~0, ~0,&ov);
+
+ if (res == FALSE) {
+ res = GetOverlappedResult(s->hfile,&ov,&num_bytes, TRUE);
+ }
+
+ if (res == TRUE) {
+ drv->num_locks = 1;
+ }
+
+ break;
+
+ case BDRV_F_UNLCK:
+ if (--drv->num_locks> 0) {
+ return 0;
+ }
+
+ assert(drv->num_locks>= 0);
+
+ res = UnlockFile(s->hfile, 0, 0, ~0, ~0);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ if (res == FALSE) {
+ return -EIO;
+ }
+
+ return 0;
+}
+
static int raw_create(const char *filename, QEMUOptionParameter *options)
{
int fd;
@@ -289,6 +340,7 @@ static BlockDriver bdrv_file = {
.bdrv_get_allocated_file_size
= raw_get_allocated_file_size,
+ .bdrv_lock = raw_lock,
.create_options = raw_create_options,
};