* fhandler.h (class fhandler_dev_raw): Add members devbufalloc and

devbufalign.
	(class fhandler_dev_floppy): Remove member bytes_per_sector;
	* fhandler_floppy.cc (bytes_per_sector): Define as devbufalign.
	(fhandler_dev_floppy::open): Set devbufalign to a multiple of the
	sector size and handle devbuf allocation and alignment in !O_DIRECT
	case here.  Change comment accordingly.
	Call FSCTL_ALLOW_EXTENDED_DASD_IO for partitions as well.
	(fhandler_dev_floppy::raw_write): Fix comment.  Rewrite and fix
	writing behaviour when application uses read and lseek.
	(fhandler_dev_floppy::lseek): Use rounddown macro.  Call
	SetFilePointerEx rather than the old SetFilePointer.
	(fhandler_dev_floppy::ioctl): Reformat switch.  Call
	IOCTL_DISK_UPDATE_PROPERTIES rather than IOCTL_DISK_UPDATE_DRIVE_SIZE
	in BLKRRPART case.  Support BLKIOMIN, BLKIOOPT, BLKPBSZGET and
	BLKALIGNOFF.
	* fhandler_raw.cc (fhandler_dev_raw::fhandler_dev_raw): Initialize
	all devbuf-related members.
	(fhandler_dev_raw::~fhandler_dev_raw): Delete devbufalloc rather than
	devbuf.
	(fhandler_dev_raw::open): Drop allocating devbuf.
	(fhandler_dev_raw::dup): Allocate devbufalloc and set devbuf to support
	new sector-aligned devbuf handling.
	(fhandler_dev_raw::fixup_after_exec): Ditto.
	* fhandler_tape.cc (fhandler_dev_tape::open): Ditto, set devbufalign
	to 1.
	* include/cygwin/fs.h (BLKIOMIN): Define.
	(BLKIOOPT): Define.
	(BLKALIGNOFF): Define.
	(BLKPBSZGET): Define.
This commit is contained in:
Corinna Vinschen 2012-10-13 12:34:18 +00:00
parent 93c9cdc1b0
commit db8224e8be
6 changed files with 209 additions and 80 deletions

View File

@ -1,3 +1,36 @@
2012-10-13 Corinna Vinschen <corinna@vinschen.de>
* fhandler.h (class fhandler_dev_raw): Add members devbufalloc and
devbufalign.
(class fhandler_dev_floppy): Remove member bytes_per_sector;
* fhandler_floppy.cc (bytes_per_sector): Define as devbufalign.
(fhandler_dev_floppy::open): Set devbufalign to a multiple of the
sector size and handle devbuf allocation and alignment in !O_DIRECT
case here. Change comment accordingly.
Call FSCTL_ALLOW_EXTENDED_DASD_IO for partitions as well.
(fhandler_dev_floppy::raw_write): Fix comment. Rewrite and fix
writing behaviour when application uses read and lseek.
(fhandler_dev_floppy::lseek): Use rounddown macro. Call
SetFilePointerEx rather than the old SetFilePointer.
(fhandler_dev_floppy::ioctl): Reformat switch. Call
IOCTL_DISK_UPDATE_PROPERTIES rather than IOCTL_DISK_UPDATE_DRIVE_SIZE
in BLKRRPART case. Support BLKIOMIN, BLKIOOPT, BLKPBSZGET and
BLKALIGNOFF.
* fhandler_raw.cc (fhandler_dev_raw::fhandler_dev_raw): Initialize
all devbuf-related members.
(fhandler_dev_raw::~fhandler_dev_raw): Delete devbufalloc rather than
devbuf.
(fhandler_dev_raw::open): Drop allocating devbuf.
(fhandler_dev_raw::dup): Allocate devbufalloc and set devbuf to support
new sector-aligned devbuf handling.
(fhandler_dev_raw::fixup_after_exec): Ditto.
* fhandler_tape.cc (fhandler_dev_tape::open): Ditto, set devbufalign
to 1.
* include/cygwin/fs.h (BLKIOMIN): Define.
(BLKIOOPT): Define.
(BLKALIGNOFF): Define.
(BLKPBSZGET): Define.
2012-10-12 Corinna Vinschen <corinna@vinschen.de>
* fhandler_raw.cc (fhandler_dev_raw::open): Allow O_EXCL flag, as on

View File

@ -798,7 +798,9 @@ class fhandler_mailslot : public fhandler_base_overlapped
class fhandler_dev_raw: public fhandler_base
{
protected:
char *devbufalloc;
char *devbuf;
size_t devbufalign;
size_t devbufsiz;
size_t devbufstart;
size_t devbufend;
@ -856,7 +858,6 @@ class fhandler_dev_floppy: public fhandler_dev_raw
{
private:
_off64_t drive_size;
unsigned long bytes_per_sector;
part_t *partitions;
struct status_flags
{

View File

@ -28,6 +28,8 @@ details. */
|| (err) == ERROR_SEEK \
|| (err) == ERROR_SECTOR_NOT_FOUND)
#define bytes_per_sector devbufalign
/**********************************************************************/
/* fhandler_dev_floppy */
@ -355,16 +357,6 @@ fhandler_dev_floppy::write_file (const void *buf, DWORD to_write,
int
fhandler_dev_floppy::open (int flags, mode_t)
{
/* The correct size of the buffer would be 512 bytes, which is the atomic
size, supported by WinNT. Unfortunately, the performance is worse than
access to file system on same device! Setting buffer size to a
relatively big value increases performance by means. The new ioctl call
with 'rdevio.h' header file supports changing this value.
As default buffer size, we're using some value which is a multiple of
the typical tar and cpio buffer sizes, Except O_DIRECT is set, in which
case we're not buffering at all. */
devbufsiz = (flags & O_DIRECT) ? 0L : 61440L;
int ret = fhandler_dev_raw::open (flags);
if (ret)
@ -376,11 +368,22 @@ fhandler_dev_floppy::open (int flags, mode_t)
close ();
return 0;
}
if (!(flags & O_DIRECT))
{
/* Create sector-aligned buffer. As default buffer size, we're using
some big, sector-aligned value. Since direct blockdev IO is
usually non-buffered and non-cached, the performance without
buffering is worse than access to a file system on same device.
Whoever uses O_DIRECT has my condolences. */
devbufsiz = MAX (16 * bytes_per_sector, 65536);
devbufalloc = new char [devbufsiz + devbufalign];
devbuf = (char *) roundup2 ((uintptr_t) devbufalloc, devbufalign);
}
/* If we're trying to access a CD/DVD drive, or an entire disk,
make sure we're actually allowed to read *all* of the device.
This is actually documented in the MSDN CreateFile man page. */
if (get_major () != DEV_FLOPPY_MAJOR
&& (get_major () == DEV_CDROM_MAJOR || get_minor () % 16 == 0)
&& !DeviceIoControl (get_handle (), FSCTL_ALLOW_EXTENDED_DASD_IO,
NULL, 0, NULL, 0, &bytes_read, NULL))
debug_printf ("DeviceIoControl (FSCTL_ALLOW_EXTENDED_DASD_IO) "
@ -562,34 +565,103 @@ fhandler_dev_floppy::raw_write (const void *ptr, size_t len)
char *p = (char *) ptr;
int ret;
/* Checking a previous end of media on tape */
/* Checking a previous end of media */
if (eom_detected ())
{
set_errno (ENOSPC);
return -1;
}
/* Invalidate buffer. */
devbufstart = devbufend = 0;
if (!len)
return 0;
if (len > 0)
if (devbuf)
{
if (!write_file (p, len, &bytes_written, &ret))
{
if (!IS_EOM (ret))
DWORD cplen, written;
/* First check if we have an active read buffer. If so, try to fit in
the start of the input buffer and write out the entire result.
This also covers the situation after lseek since lseek fills the read
buffer in case we seek to an address which is not sector aligned. */
if (devbufend && devbufstart < devbufend)
{
_off64_t current_pos = get_current_position ();
cplen = MIN (len, devbufend - devbufstart);
memcpy (devbuf + devbufstart, p, cplen);
LARGE_INTEGER off = { QuadPart:current_pos - devbufend };
if (!SetFilePointerEx (get_handle (), off, NULL, FILE_BEGIN))
{
devbufstart = devbufend = 0;
__seterrno ();
return -1;
}
eom_detected (true);
if (!bytes_written)
if (!write_file (devbuf, devbufend, &written, &ret))
{
set_errno (ENOSPC);
return -1;
devbufstart = devbufend = 0;
goto err;
}
/* Align pointers, lengths, etc. */
cplen = MIN (cplen, written);
devbufstart += cplen;
p += cplen;
len -= cplen;
bytes_written += cplen;
if (len)
devbufstart = devbufend = 0;
}
/* As long as there's still something left in the input buffer ... */
while (len)
{
/* Compute the length to write. The problem is that the underlying
driver may require sector aligned read/write. So we copy the data
over to devbuf, which is guaranteed to be sector aligned. */
cplen = MIN (len, devbufsiz);
if (cplen >= bytes_per_sector)
/* If the remaining len is >= sector size, write out the maximum
possible multiple of the sector size which fits into devbuf. */
cplen = rounddown (cplen, bytes_per_sector);
else
{
/* If len < sector size, read in the next sector, seek back,
and just copy the new data over the old one before writing. */
LARGE_INTEGER off = { QuadPart:get_current_position () };
if (!read_file (devbuf, bytes_per_sector, &written, &ret))
goto err;
if (!SetFilePointerEx (get_handle (), off, NULL, FILE_BEGIN))
{
__seterrno ();
return -1;
}
}
memcpy (devbuf, p, cplen);
if (!write_file (devbuf, MAX (cplen, bytes_per_sector), &written,
&ret))
{
bytes_written += MIN (cplen, written);
goto err;
}
cplen = MIN (cplen, written);
p += cplen;
len -= cplen;
bytes_written += cplen;
}
return bytes_written;
}
return bytes_written;
/* In O_DIRECT case, just write. */
if (write_file (p, len, &bytes_written, &ret))
return bytes_written;
err:
if (IS_EOM (ret))
{
eom_detected (true);
if (!bytes_written)
set_errno (ENOSPC);
}
else if (!bytes_written)
__seterrno ();
return bytes_written ?: -1;
}
_off64_t
@ -631,20 +703,14 @@ fhandler_dev_floppy::lseek (_off64_t offset, int whence)
}
}
sector_aligned_offset.QuadPart = (lloffset / bytes_per_sector)
* bytes_per_sector;
sector_aligned_offset.QuadPart = rounddown (lloffset, bytes_per_sector);
bytes_left = lloffset - sector_aligned_offset.QuadPart;
/* Invalidate buffer. */
devbufstart = devbufend = 0;
sector_aligned_offset.LowPart =
SetFilePointer (get_handle (),
sector_aligned_offset.LowPart,
&sector_aligned_offset.HighPart,
FILE_BEGIN);
if (sector_aligned_offset.LowPart == INVALID_SET_FILE_POINTER
&& GetLastError ())
if (!SetFilePointerEx (get_handle (), sector_aligned_offset, NULL,
FILE_BEGIN))
{
__seterrno ();
return -1;
@ -665,59 +731,69 @@ fhandler_dev_floppy::lseek (_off64_t offset, int whence)
int
fhandler_dev_floppy::ioctl (unsigned int cmd, void *buf)
{
DISK_GEOMETRY di;
int ret = 0;
DWORD bytes_read;
switch (cmd)
{
case HDIO_GETGEO:
{
debug_printf ("HDIO_GETGEO");
return get_drive_info ((struct hd_geometry *) buf);
}
debug_printf ("HDIO_GETGEO");
ret = get_drive_info ((struct hd_geometry *) buf);
break;
case BLKGETSIZE:
case BLKGETSIZE64:
{
debug_printf ("BLKGETSIZE");
if (cmd == BLKGETSIZE)
*(long *)buf = drive_size >> 9UL;
else
*(_off64_t *)buf = drive_size;
return 0;
}
debug_printf ("BLKGETSIZE");
if (cmd == BLKGETSIZE)
*(long *)buf = drive_size >> 9UL;
else
*(_off64_t *)buf = drive_size;
break;
case BLKRRPART:
{
debug_printf ("BLKRRPART");
if (!DeviceIoControl (get_handle (),
IOCTL_DISK_UPDATE_DRIVE_SIZE,
NULL, 0,
&di, sizeof (di),
&bytes_read, NULL))
{
__seterrno ();
return -1;
}
debug_printf ("BLKRRPART");
if (!DeviceIoControl (get_handle (), IOCTL_DISK_UPDATE_PROPERTIES,
NULL, 0, NULL, 0, &bytes_read, NULL))
{
__seterrno ();
ret = -1;
}
else
get_drive_info (NULL);
return 0;
}
break;
case BLKSSZGET:
{
debug_printf ("BLKSSZGET");
*(int *)buf = bytes_per_sector;
return 0;
}
debug_printf ("BLKSSZGET");
*(int *)buf = bytes_per_sector;
break;
case BLKIOMIN:
debug_printf ("BLKIOMIN");
*(int *)buf = bytes_per_sector;
break;
case BLKIOOPT:
debug_printf ("BLKIOOPT");
*(int *)buf = bytes_per_sector;
break;
case BLKPBSZGET:
debug_printf ("BLKPBSZGET");
*(int *)buf = bytes_per_sector;
break;
case BLKALIGNOFF:
debug_printf ("BLKALIGNOFF");
*(int *)buf = 0;
break;
case RDSETBLK:
/* Just check the restriction that blocksize must be a multiple
of the sector size of the underlying volume sector size,
then fall through to fhandler_dev_raw::ioctl. */
debug_printf ("RDSETBLK");
if (((struct rdop *) buf)->rd_parm % bytes_per_sector)
{
SetLastError (ERROR_INVALID_PARAMETER);
__seterrno ();
set_errno (EINVAL);
return -1;
}
/*FALLTHRU*/
default:
return fhandler_dev_raw::ioctl (cmd, buf);
ret = fhandler_dev_raw::ioctl (cmd, buf);
break;
}
return ret;
}

View File

@ -13,6 +13,7 @@
#include <cygwin/rdevio.h>
#include <sys/mtio.h>
#include <sys/param.h>
#include "cygerrno.h"
#include "path.h"
#include "fhandler.h"
@ -21,7 +22,14 @@
/* fhandler_dev_raw */
fhandler_dev_raw::fhandler_dev_raw ()
: fhandler_base (), status ()
: fhandler_base (),
devbufalloc (NULL),
devbuf (NULL),
devbufalign (0),
devbufsiz (0),
devbufstart (0),
devbufend (0),
status ()
{
need_fork_fixup (true);
}
@ -29,7 +37,7 @@ fhandler_dev_raw::fhandler_dev_raw ()
fhandler_dev_raw::~fhandler_dev_raw ()
{
if (devbufsiz > 1L)
delete [] devbuf;
delete [] devbufalloc;
}
int __stdcall
@ -74,8 +82,6 @@ fhandler_dev_raw::open (int flags, mode_t)
flags = ((flags & ~O_WRONLY) | O_RDWR);
int res = fhandler_base::open (flags, 0);
if (res && devbufsiz > 1L)
devbuf = new char [devbufsiz];
return res;
}
@ -90,7 +96,12 @@ fhandler_dev_raw::dup (fhandler_base *child, int flags)
fhandler_dev_raw *fhc = (fhandler_dev_raw *) child;
if (devbufsiz > 1L)
fhc->devbuf = new char [devbufsiz];
{
/* Create sector-aligned buffer */
fhc->devbufalloc = new char [devbufsiz + devbufalign];
fhc->devbuf = (char *) roundup2 ((uintptr_t) fhc->devbufalloc,
devbufalign);
}
fhc->devbufstart = 0;
fhc->devbufend = 0;
fhc->lastblk_to_read (false);
@ -112,7 +123,11 @@ fhandler_dev_raw::fixup_after_exec ()
if (!close_on_exec ())
{
if (devbufsiz > 1L)
devbuf = new char [devbufsiz];
{
/* Create sector-aligned buffer */
devbufalloc = new char [devbufsiz + devbufalign];
devbuf = (char *) roundup2 ((uintptr_t) devbufalloc, devbufalign);
}
devbufstart = 0;
devbufend = 0;
lastblk_to_read (false);
@ -167,7 +182,7 @@ fhandler_dev_raw::ioctl (unsigned int cmd, void *buf)
devbufend = 0;
if (devbufsiz > 1L)
delete [] devbuf;
delete [] devbufalloc;
devbufstart = 0;
devbuf = buf;

View File

@ -1214,9 +1214,9 @@ fhandler_dev_tape::open (int flags, mode_t)
if (!(flags & O_DIRECT))
{
devbufsiz = mt.drive (driveno ())->dp ()->MaximumBlockSize;
devbuf = new char [devbufsiz];
devbufalign = 1;
devbufalloc = devbuf = new char [devbufsiz];
}
devbufstart = devbufend = 0;
}
else
ReleaseMutex (mt_mtx);

View File

@ -1,6 +1,6 @@
/* cygwin/fs.h
Copyright 2002, 2003 Red Hat Inc.
Copyright 2002, 2003, 2012 Red Hat Inc.
Written by Chris January <chris@atomice.net>
This file is part of Cygwin.
@ -12,9 +12,13 @@ details. */
#ifndef _CYGWIN_FS_H_
#define _CYGWIN_FS_H_
#define BLKRRPART 0x0000125f
#define BLKGETSIZE 0x00001260
#define BLKSSZGET 0x00001268
#define BLKRRPART 0x0000125f
#define BLKGETSIZE 0x00001260
#define BLKSSZGET 0x00001268
#define BLKIOMIN 0x00001278
#define BLKIOOPT 0x00001279
#define BLKALIGNOFF 0x0000127a
#define BLKPBSZGET 0x0000127b
#define BLKGETSIZE64 0x00041268
#endif