aboutsummaryrefslogtreecommitdiff
path: root/winsup
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2012-10-13 12:34:18 +0000
committerCorinna Vinschen <corinna@vinschen.de>2012-10-13 12:34:18 +0000
commitdb8224e8be2d72a00e828a4af6db5cbd1853cebf (patch)
treeb194832d0893c11dcb8dabb39279cffff002566b /winsup
parent93c9cdc1b0cf91b83c31e9bc52a2e94f07a79ad5 (diff)
downloadnewlib-db8224e8be2d72a00e828a4af6db5cbd1853cebf.zip
newlib-db8224e8be2d72a00e828a4af6db5cbd1853cebf.tar.gz
newlib-db8224e8be2d72a00e828a4af6db5cbd1853cebf.tar.bz2
* 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.
Diffstat (limited to 'winsup')
-rw-r--r--winsup/cygwin/ChangeLog33
-rw-r--r--winsup/cygwin/fhandler.h3
-rw-r--r--winsup/cygwin/fhandler_floppy.cc208
-rw-r--r--winsup/cygwin/fhandler_raw.cc29
-rw-r--r--winsup/cygwin/fhandler_tape.cc4
-rw-r--r--winsup/cygwin/include/cygwin/fs.h12
6 files changed, 209 insertions, 80 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index c98eb0c..a745d72 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -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
diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index 3b7f05b..e2db959 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -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
{
diff --git a/winsup/cygwin/fhandler_floppy.cc b/winsup/cygwin/fhandler_floppy.cc
index 0caca96..b0d0930 100644
--- a/winsup/cygwin/fhandler_floppy.cc
+++ b/winsup/cygwin/fhandler_floppy.cc
@@ -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;
+ }
+
+ /* 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);
}
- return bytes_written;
+ 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;
}
diff --git a/winsup/cygwin/fhandler_raw.cc b/winsup/cygwin/fhandler_raw.cc
index a03f7aa..3054bc3 100644
--- a/winsup/cygwin/fhandler_raw.cc
+++ b/winsup/cygwin/fhandler_raw.cc
@@ -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;
diff --git a/winsup/cygwin/fhandler_tape.cc b/winsup/cygwin/fhandler_tape.cc
index 5d1a7f9..67d6f5c 100644
--- a/winsup/cygwin/fhandler_tape.cc
+++ b/winsup/cygwin/fhandler_tape.cc
@@ -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);
diff --git a/winsup/cygwin/include/cygwin/fs.h b/winsup/cygwin/include/cygwin/fs.h
index eb8c7e3..509b9c5 100644
--- a/winsup/cygwin/include/cygwin/fs.h
+++ b/winsup/cygwin/include/cygwin/fs.h
@@ -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