Implemented lock mechanism for hard disk images (fixes SF bug #605).

- Create a file with image name plus extension ".lock" if an image is opened
  in read/write mode. This file will be deleted after closing the image.
- Check for a lock file before opening an image and fail if it exists.
- Check for a lock file before creating a undoable/volatile redolog file and
  fail if it exists.
This commit is contained in:
Volker Ruppert 2017-01-30 19:08:37 +00:00
parent 124f521797
commit 7fd9194d81
6 changed files with 88 additions and 32 deletions

View File

@ -178,12 +178,30 @@ int bx_write_image(int fd, Bit64s offset, void *buf, int count)
return write(fd, buf, count);
}
int bx_close_image(int fd, const char *pathname)
{
#ifndef BXIMAGE
char lockfn[BX_PATHNAME_LEN];
sprintf(lockfn, "%s.lock", pathname);
if (access(lockfn, F_OK) == 0) {
unlink(lockfn);
}
#endif
return ::close(fd);
}
#ifndef WIN32
int hdimage_open_file(const char *pathname, int flags, Bit64u *fsize, time_t *mtime)
#else
int hdimage_open_file(const char *pathname, int flags, Bit64u *fsize, FILETIME *mtime)
#endif
{
#ifndef BXIMAGE
char lockfn[BX_PATHNAME_LEN];
int lockfd;
#endif
#ifdef WIN32
if (fsize != NULL) {
HANDLE hFile = CreateFile(pathname, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, NULL);
@ -205,6 +223,17 @@ int hdimage_open_file(const char *pathname, int flags, Bit64u *fsize, FILETIME *
}
#endif
#ifndef BXIMAGE
sprintf(lockfn, "%s.lock", pathname);
lockfd = ::open(lockfn, O_RDONLY);
if (lockfd >= 0) {
// Opening image must fail if lock file exists.
::close(lockfd);
BX_ERROR(("image locked: '%s'", pathname));
return -1;
}
#endif
int fd = ::open(pathname, flags
#ifdef O_BINARY
| O_BINARY
@ -235,6 +264,19 @@ int hdimage_open_file(const char *pathname, int flags, Bit64u *fsize, FILETIME *
*mtime = stat_buf.st_mtime;
}
}
#endif
#ifndef BXIMAGE
if ((flags & O_ACCMODE) != O_RDONLY) {
lockfd = ::open(lockfn, O_CREAT | O_RDWR
#ifdef O_BINARY
| O_BINARY
#endif
, S_IWUSR | S_IRUSR | S_IRGRP | S_IWGRP);
if (lockfd >= 0) {
// lock this image
::close(lockfd);
}
}
#endif
return fd;
}
@ -488,7 +530,7 @@ int flat_image_t::open(const char* _pathname, int flags)
void flat_image_t::close()
{
if (fd > -1) {
::close(fd);
bx_close_image(fd, pathname);
}
}
@ -569,11 +611,11 @@ int concat_image_t::open(const char* _pathname0, int flags)
{
UNUSED(flags);
pathname0 = _pathname0;
char *pathname = strdup(pathname0);
char *pathname1 = strdup(pathname0);
BX_DEBUG(("concat_image_t::open"));
Bit64s start_offset = 0;
for (int i=0; i<BX_CONCAT_MAX_IMAGES; i++) {
fd_table[i] = hdimage_open_file(pathname, flags, &length_table[i], NULL);
fd_table[i] = hdimage_open_file(pathname1, flags, &length_table[i], NULL);
if (fd_table[i] < 0) {
// open failed.
// if no FD was opened successfully, return -1 (fail).
@ -583,7 +625,7 @@ int concat_image_t::open(const char* _pathname0, int flags)
maxfd = i;
break;
}
BX_INFO(("concat_image: open image #%d: '%s', (" FMT_LL "u bytes)", i, pathname, length_table[i]));
BX_INFO(("concat_image: open image #%d: '%s', (" FMT_LL "u bytes)", i, pathname1, length_table[i]));
struct stat stat_buf;
int ret = fstat(fd_table[i], &stat_buf);
if (ret) {
@ -599,9 +641,9 @@ int concat_image_t::open(const char* _pathname0, int flags)
}
start_offset_table[i] = start_offset;
start_offset += length_table[i];
increment_string(pathname);
increment_string(pathname1);
}
free(pathname);
free(pathname1);
// start up with first image selected
total_offset = 0;
index = 0;
@ -616,11 +658,14 @@ int concat_image_t::open(const char* _pathname0, int flags)
void concat_image_t::close()
{
BX_DEBUG(("concat_image_t.close"));
char *pathname1 = strdup(pathname0);
for (int index = 0; index < maxfd; index++) {
if (fd_table[index] > -1) {
::close(fd_table[index]);
bx_close_image(fd_table[index], pathname1);
}
increment_string(pathname1);
}
free(pathname1);
}
Bit64s concat_image_t::lseek(Bit64s offset, int whence)
@ -914,13 +959,8 @@ int sparse_image_t::open(const char* pathname0, int flags)
void sparse_image_t::close()
{
BX_DEBUG(("concat_image_t.close"));
if (pathname != NULL)
{
free(pathname);
}
#ifdef _POSIX_MAPPED_FILES
if (mmap_header != NULL)
{
if (mmap_header != NULL) {
int ret = munmap(mmap_header, mmap_length);
if (ret != 0)
BX_INFO(("failed to un-memory map sparse disk file"));
@ -928,14 +968,15 @@ void sparse_image_t::close()
pagetable = NULL; // We didn't malloc it
#endif
if (fd > -1) {
::close(fd);
bx_close_image(fd, pathname);
}
if (pagetable != NULL)
{
if (pathname != NULL) {
free(pathname);
}
if (pagetable != NULL) {
delete [] pagetable;
}
if (parent_image != NULL)
{
if (parent_image != NULL) {
delete parent_image;
}
}
@ -1492,6 +1533,15 @@ int redolog_t::make_header(const char* type, Bit64u size)
int redolog_t::create(const char* filename, const char* type, Bit64u size)
{
#ifndef BXIMAGE
char lockfn[BX_PATHNAME_LEN];
sprintf(lockfn, "%s.lock", filename);
if (access(lockfn, F_OK) == 0) {
return -1;
}
#endif
BX_INFO(("redolog : creating redolog %s", filename));
int filedes = ::open(filename, O_RDWR | O_CREAT | O_TRUNC
@ -1541,6 +1591,7 @@ int redolog_t::open(const char* filename, const char *type, int flags)
FILETIME mtime;
#endif
pathname = strdup(filename);
fd = hdimage_open_file(filename, flags, &imgsize, &mtime);
if (fd < 0) {
BX_INFO(("redolog : could not open image %s", filename));
@ -1624,7 +1675,10 @@ int redolog_t::open(const char* filename, const char *type, int flags)
void redolog_t::close()
{
if (fd >= 0)
::close(fd);
bx_close_image(fd, pathname);
if (pathname != NULL)
free(pathname);
if (catalog != NULL)
free(catalog);

View File

@ -2,7 +2,7 @@
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2005-2015 The Bochs Project
// Copyright (C) 2005-2017 The Bochs Project
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
@ -143,6 +143,7 @@ class redolog_t;
int bx_read_image(int fd, Bit64s offset, void *buf, int count);
int bx_write_image(int fd, Bit64s offset, void *buf, int count);
int bx_close_image(int fd, const char *pathname);
#ifndef WIN32
int hdimage_open_file(const char *pathname, int flags, Bit64u *fsize, time_t *mtime);
#else
@ -452,6 +453,7 @@ class redolog_t
private:
void print_header();
char *pathname;
int fd;
redolog_header_t header; // Header is kept in x86 (little) endianness
Bit32u *catalog;

View File

@ -10,7 +10,7 @@
* Contact: fys [at] fysnet [dot] net
*
* Copyright (C) 2015 Benjamin D Lunt.
* Copyright (C) 2006-2016 The Bochs Project
* Copyright (C) 2006-2017 The Bochs Project
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -167,7 +167,7 @@ void vbox_image_t::close()
delete [] mtlb; mtlb = 0;
delete [] block_data; block_data = 0;
::close(file_descriptor);
bx_close_image(file_descriptor, pathname);
file_descriptor = -1;
}

View File

@ -10,7 +10,7 @@
* Contact: snrrrub@yahoo.com
*
* Copyright (C) 2003 Net Integration Technologies, Inc.
* Copyright (C) 2003-2015 The Bochs Project
* Copyright (C) 2003-2017 The Bochs Project
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -224,7 +224,7 @@ int vmware3_image_t::open(const char* _pathname, int flags)
return -1;
}
::close(file);
bx_close_image(file, pathname);
tlb_size = header.tlb_size_sectors * 512;
slb_count = (1 << FL_SHIFT) / tlb_size;

View File

@ -10,7 +10,7 @@
* Contact: snrrrub@gmail.com
*
* Copyright (C) 2006 Sharvil Nanavati.
* Copyright (C) 2006-2016 The Bochs Project
* Copyright (C) 2006-2017 The Bochs Project
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -112,7 +112,7 @@ void vmware4_image_t::close()
flush();
delete [] tlb; tlb = 0;
::close(file_descriptor);
bx_close_image(file_descriptor, pathname);
file_descriptor = -1;
}

View File

@ -6,7 +6,7 @@
//
// Copyright (c) 2005 Alex Beregszaszi
// Copyright (c) 2009 Kevin Wolf <kwolf@suse.de>
// Copyright (C) 2012-2013 The Bochs Project
// Copyright (C) 2012-2017 The Bochs Project
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@ -138,20 +138,20 @@ int vpc_image_t::open(const char* _pathname, int flags)
hd_size = sector_count * 512;
if (sector_count >= 65535 * 16 * 255) {
::close(fd);
bx_close_image(fd, pathname);
return -EFBIG;
}
if (disk_type == VHD_DYNAMIC) {
if (bx_read_image(fd, be64_to_cpu(footer->data_offset), buf, HEADER_SIZE) != HEADER_SIZE) {
::close(fd);
bx_close_image(fd, pathname);
return -1;
}
dyndisk_header = (vhd_dyndisk_header_t*)buf;
if (strncmp((char*)dyndisk_header->magic, "cxsparse", 8)) {
::close(fd);
bx_close_image(fd, pathname);
return -1;
}
@ -163,7 +163,7 @@ int vpc_image_t::open(const char* _pathname, int flags)
bat_offset = be64_to_cpu(dyndisk_header->table_offset);
if (bx_read_image(fd, bat_offset, (void*)pagetable, max_table_entries * 4) != (max_table_entries * 4)) {
::close(fd);
bx_close_image(fd, pathname);
return -1;
}
@ -193,7 +193,7 @@ void vpc_image_t::close(void)
{
if (fd > -1) {
delete [] pagetable;
::close(fd);
bx_close_image(fd, pathname);
}
}