Skip to content

Commit f8571de

Browse files
committed
Fixed bug #7873 : IO error reading file, The parameter is incorrect.
1 parent 8789caf commit f8571de

File tree

7 files changed

+95
-21
lines changed

7 files changed

+95
-21
lines changed

src/common/os/os_utils.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@
6868
#define FLOCK flock
6969
#endif
7070

71+
const ULONG DEFAULT_SECTOR_SIZE = 4096;
72+
7173
namespace os_utils
7274
{
7375

@@ -88,6 +90,8 @@ namespace os_utils
8890
void setCloseOnExec(int fd); // posix only
8991
FILE* fopen(const char* pathname, const char* mode);
9092

93+
ULONG getPhysicalSectorSize(const Firebird::PathName& fileName);
94+
9195
// return a binary string that uniquely identifies the file
9296
#ifdef WIN_NT
9397
void getUniqueFileId(HANDLE fd, Firebird::UCharBuffer& id);

src/common/os/posix/os_utils.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,12 @@ FILE* fopen(const char* pathname, const char* mode)
399399
return f;
400400
}
401401

402+
ULONG getPhysicalSectorSize(const PathName& fileName)
403+
{
404+
// return safe value
405+
return DEFAULT_SECTOR_SIZE;
406+
}
407+
402408
static void makeUniqueFileId(const struct STAT& statistics, UCharBuffer& id)
403409
{
404410
const size_t len1 = sizeof(statistics.st_dev);

src/common/os/win32/os_utils.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050

5151
#include <aclapi.h>
5252
#include <Winsock2.h>
53+
#include <winioctl.h>
5354

5455
using namespace Firebird;
5556

@@ -408,6 +409,47 @@ FILE* fopen(const char* pathname, const char* mode)
408409
return ::fopen(pathname, mode);
409410
}
410411

412+
ULONG getPhysicalSectorSize(const PathName& fileName)
413+
{
414+
// Fallback to the safe value
415+
ULONG ret = DEFAULT_SECTOR_SIZE;
416+
417+
// Device name could be set as \\.\PhysicalDrive0 or as \\.\a:
418+
// The second form is used below for simplicity.
419+
420+
string deviceName = "\\\\.\\";
421+
deviceName.append(fileName.c_str(), 2);
422+
423+
HANDLE hDevice = CreateFile(deviceName.c_str(),
424+
0,
425+
FILE_SHARE_READ | FILE_SHARE_WRITE,
426+
NULL,
427+
OPEN_EXISTING,
428+
0, NULL);
429+
430+
if (hDevice != INVALID_HANDLE_VALUE)
431+
{
432+
STORAGE_PROPERTY_QUERY qry;
433+
STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR desc;
434+
DWORD readSize = 0;
435+
436+
qry.PropertyId = StorageAccessAlignmentProperty;
437+
qry.QueryType = PropertyStandardQuery;
438+
439+
if (DeviceIoControl(hDevice, IOCTL_STORAGE_QUERY_PROPERTY,
440+
&qry, sizeof(qry),
441+
&desc, sizeof(desc),
442+
&readSize, NULL))
443+
{
444+
ret = desc.BytesPerPhysicalSector;
445+
}
446+
447+
CloseHandle(hDevice);
448+
}
449+
450+
return ret;
451+
}
452+
411453
void getUniqueFileId(HANDLE fd, UCharBuffer& id)
412454
{
413455
entryLoader.init();

src/jrd/jrd.cpp

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7592,11 +7592,21 @@ static JAttachment* create_attachment(const PathName& alias_name,
75927592

75937593
static void check_single_maintenance(thread_db* tdbb)
75947594
{
7595-
UCHAR spare_memory[RAW_HEADER_SIZE + PAGE_ALIGNMENT];
7596-
UCHAR* header_page_buffer = FB_ALIGN(spare_memory, PAGE_ALIGNMENT);
7595+
Database* const dbb = tdbb->getDatabase();
7596+
7597+
const ULONG sectorSize = (dbb->dbb_flags & DBB_no_fs_cache) ?
7598+
os_utils::getPhysicalSectorSize(dbb->dbb_filename) :
7599+
PAGE_ALIGNMENT;
7600+
7601+
const ULONG headerSize = MAX(RAW_HEADER_SIZE, sectorSize);
7602+
7603+
HalfStaticArray<UCHAR, RAW_HEADER_SIZE + PAGE_ALIGNMENT> temp;
7604+
UCHAR* header_page_buffer = temp.getBuffer(headerSize + sectorSize);
7605+
7606+
header_page_buffer = FB_ALIGN(header_page_buffer, PAGE_ALIGNMENT);
75977607
Ods::header_page* const header_page = reinterpret_cast<Ods::header_page*>(header_page_buffer);
75987608

7599-
PIO_header(tdbb, header_page_buffer, RAW_HEADER_SIZE);
7609+
PIO_header(tdbb, header_page_buffer, headerSize);
76007610

76017611
if ((header_page->hdr_flags & Ods::hdr_shutdown_mask) == Ods::hdr_shutdown_single)
76027612
{

src/jrd/pag.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1261,10 +1261,17 @@ void PAG_header_init(thread_db* tdbb)
12611261
// and unit of transfer is a multiple of physical disk
12621262
// sector for raw disk access.
12631263

1264-
UCHAR temp_buffer[RAW_HEADER_SIZE + PAGE_ALIGNMENT];
1265-
UCHAR* const temp_page = FB_ALIGN(temp_buffer, PAGE_ALIGNMENT);
1264+
const ULONG sectorSize = (dbb->dbb_flags & DBB_no_fs_cache) ?
1265+
os_utils::getPhysicalSectorSize(dbb->dbb_filename) :
1266+
PAGE_ALIGNMENT;
12661267

1267-
PIO_header(tdbb, temp_page, RAW_HEADER_SIZE);
1268+
const ULONG headerSize = MAX(RAW_HEADER_SIZE, sectorSize);
1269+
1270+
HalfStaticArray<UCHAR, RAW_HEADER_SIZE + PAGE_ALIGNMENT> temp;
1271+
UCHAR* temp_buffer = temp.getBuffer(headerSize + sectorSize);
1272+
UCHAR* const temp_page = FB_ALIGN(temp_buffer, sectorSize);
1273+
1274+
PIO_header(tdbb, temp_page, headerSize);
12681275
const header_page* header = (header_page*) temp_page;
12691276

12701277
if (header->hdr_header.pag_type != pag_header || header->hdr_sequence)

src/utilities/gstat/dba.epp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -610,6 +610,10 @@ int gstat(Firebird::UtilSvc* uSvc)
610610
expandDatabaseName(fileName, tempStr, NULL);
611611
fileName = tempStr;
612612

613+
// If file will be opened with no buffering (direct IO), make sure that
614+
// temp buffer is aligned on the disk physical sector size and IO size
615+
// is multiply of sector size.
616+
613617
dba_fil* current = db_open(fileName.c_str(), fileName.length());
614618

615619
SCHAR temp[RAW_HEADER_SIZE];

src/utilities/nbackup/nbackup.cpp

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -79,12 +79,6 @@
7979
#define O_LARGEFILE 0
8080
#endif
8181

82-
// How much we align memory when reading database header.
83-
// Sector alignment of memory is necessary to use unbuffered IO on Windows.
84-
// Actually, sectors may be bigger than 1K, but let's be consistent with
85-
// JRD regarding the matter for the moment.
86-
const FB_SIZE_T SECTOR_ALIGNMENT = PAGE_ALIGNMENT;
87-
8882
using namespace Firebird;
8983

9084
namespace
@@ -1199,7 +1193,7 @@ void NBackup::backup_database(int level, Guid& guid, const PathName& fname)
11991193
ULONG prev_scn = 0;
12001194
char prev_guid[GUID_BUFF_SIZE] = "";
12011195
char str_guid[GUID_BUFF_SIZE] = "";
1202-
Ods::pag* page_buff = NULL;
1196+
12031197
attach_database();
12041198
ULONG page_writes = 0, page_reads = 0;
12051199

@@ -1339,12 +1333,18 @@ void NBackup::backup_database(int level, Guid& guid, const PathName& fname)
13391333
open_database_scan();
13401334

13411335
// Read database header
1342-
char unaligned_header_buffer[RAW_HEADER_SIZE + SECTOR_ALIGNMENT];
13431336

1344-
auto header = reinterpret_cast<Ods::header_page*>(
1345-
FB_ALIGN(unaligned_header_buffer, SECTOR_ALIGNMENT));
1337+
const ULONG sectorSize = os_utils::getPhysicalSectorSize(dbname);
1338+
const ULONG headerSize = MAX(RAW_HEADER_SIZE, sectorSize);
1339+
1340+
Array<UCHAR> unaligned_header_buffer;
1341+
Ods::header_page* header = nullptr;
1342+
{ // scope
1343+
UCHAR* buf = unaligned_header_buffer.getBuffer(headerSize + sectorSize);
1344+
header = reinterpret_cast<Ods::header_page*>(FB_ALIGN(buf, sectorSize));
1345+
} // end scope
13461346

1347-
if (read_file(dbase, header, RAW_HEADER_SIZE) != RAW_HEADER_SIZE)
1347+
if (read_file(dbase, header, headerSize) != headerSize)
13481348
status_exception::raise(Arg::Gds(isc_nbackup_err_eofhdrdb) << dbname.c_str() << Arg::Num(1));
13491349

13501350
if (!Ods::isSupported(header))
@@ -1361,9 +1361,10 @@ void NBackup::backup_database(int level, Guid& guid, const PathName& fname)
13611361
status_exception::raise(Arg::Gds(isc_nbackup_db_notlock) << Arg::Num(header->hdr_flags));
13621362

13631363
Array<UCHAR> unaligned_page_buffer;
1364+
Ods::pag* page_buff = nullptr;
13641365
{ // scope
1365-
UCHAR* buf = unaligned_page_buffer.getBuffer(header->hdr_page_size + SECTOR_ALIGNMENT);
1366-
page_buff = reinterpret_cast<Ods::pag*>(FB_ALIGN(buf, SECTOR_ALIGNMENT));
1366+
UCHAR* buf = unaligned_page_buffer.getBuffer(header->hdr_page_size + sectorSize);
1367+
page_buff = reinterpret_cast<Ods::pag*>(FB_ALIGN(buf, sectorSize));
13671368
} // end scope
13681369

13691370
ULONG db_size = db_size_pages;
@@ -1430,8 +1431,8 @@ void NBackup::backup_database(int level, Guid& guid, const PathName& fname)
14301431
Array<UCHAR> unaligned_scns_buffer;
14311432
Ods::scns_page* scns = NULL, *scns_buf = NULL;
14321433
{ // scope
1433-
UCHAR* buf = unaligned_scns_buffer.getBuffer(header->hdr_page_size + SECTOR_ALIGNMENT);
1434-
scns_buf = reinterpret_cast<Ods::scns_page*>(FB_ALIGN(buf, SECTOR_ALIGNMENT));
1434+
UCHAR* buf = unaligned_scns_buffer.getBuffer(header->hdr_page_size + sectorSize);
1435+
scns_buf = reinterpret_cast<Ods::scns_page*>(FB_ALIGN(buf, sectorSize));
14351436
}
14361437

14371438
while (true)

0 commit comments

Comments
 (0)