diff options
author | Corinna Vinschen <corinna@vinschen.de> | 2012-10-13 12:34:18 +0000 |
---|---|---|
committer | Corinna Vinschen <corinna@vinschen.de> | 2012-10-13 12:34:18 +0000 |
commit | db8224e8be2d72a00e828a4af6db5cbd1853cebf (patch) | |
tree | b194832d0893c11dcb8dabb39279cffff002566b /winsup | |
parent | 93c9cdc1b0cf91b83c31e9bc52a2e94f07a79ad5 (diff) | |
download | newlib-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/ChangeLog | 33 | ||||
-rw-r--r-- | winsup/cygwin/fhandler.h | 3 | ||||
-rw-r--r-- | winsup/cygwin/fhandler_floppy.cc | 208 | ||||
-rw-r--r-- | winsup/cygwin/fhandler_raw.cc | 29 | ||||
-rw-r--r-- | winsup/cygwin/fhandler_tape.cc | 4 | ||||
-rw-r--r-- | winsup/cygwin/include/cygwin/fs.h | 12 |
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, - §or_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 |