Issue5396
This issue tracker has been migrated to GitHub,
and is currently read-only.
For more information,
see the GitHub FAQs in the Python's Developer Guide.
Created on 2009-02-28 19:02 by aguiar, last changed 2022-04-11 14:56 by admin. This issue is now closed.
Messages (10) | |||
---|---|---|---|
msg82938 - (view) | Author: Eduardo Aguiar (aguiar) | Date: 2009-02-28 19:02 | |
At posixmodule.c (line 6306) static PyObject * posix_read(PyObject *self, PyObject *args) { int fd, size, n; PyObject *buffer; if (!PyArg_ParseTuple(args, "ii:read", &fd, &size)) return NULL; if (size < 0) { errno = EINVAL; return posix_error(); } buffer = PyString_FromStringAndSize((char *)NULL, size); if (buffer == NULL) return NULL; Py_BEGIN_ALLOW_THREADS n = read(fd, PyString_AsString(buffer), size); Py_END_ALLOW_THREADS if (n < 0) { Py_DECREF(buffer); return posix_error(); } if (n != size) _PyString_Resize(&buffer, n); return buffer; } os.read does not work with O_DIRECT flag. It fails with errno = EINVAL. From read(2) man page: EINVAL fd is attached to an object which is unsuitable for reading; or the file was opened with the O_DIRECT flag, and either the address specified in buf, the value specified in count, or the current file offset is not suitably aligned. if os.open is called with O_DIRECT flag enabled, the buffer used in "read" must be page aligned and "size" must be multiple of pagesize also. |
|||
msg83541 - (view) | Author: Antoine Pitrou (pitrou) * | Date: 2009-03-13 23:02 | |
I don't think we will try to support O_DIRECT. First, it is a rather platform-specific flag. Second, Python's memory allocator doesn't allow specifying an arbitrary alignment value. Third, I don't even think O_DIRECT can make a positive difference in a Python program (the open() manpage actually warns against likely performance degradation when using O_DIRECT). So I'm closing this bug, sorry. |
|||
msg83638 - (view) | Author: Eduardo Aguiar (aguiar) | Date: 2009-03-15 15:52 | |
Hi, I think I have a few more issues you can consider: 1) to allocated an aligned buffer it is as simple as allocate 4096 + len (buffer) and truncate address to 4k boundary. 2) I wrote a floppy imager, and without O_DIRECT, it gives me 8 sectors (4k = kernel page) errors whenever one sector is bad. 3) There is os.O_DIRECT and os.open help page references it Best regards, Eduardo Aguiar |
|||
msg83639 - (view) | Author: Antoine Pitrou (pitrou) * | Date: 2009-03-15 16:05 | |
Hello Eduardo, > 1) to allocated an aligned buffer it is as simple as allocate 4096 + len > (buffer) and truncate address to 4k boundary. Yes, but it is wasteful, especially since the common case is not to use O_DIRECT. Also, os.read does not allocate a buffer, it allocates a whole string object, and there's no way in the current Python object allocator to choose a specific alignment boundary. > 2) I wrote a floppy imager, and without O_DIRECT, it gives me 8 sectors > (4k = kernel page) errors whenever one sector is bad. Well, sorry for that... I guess Python is not well adapted to this (very particular) use case. Or you could write a C extension to read() to a properly aligned buffer, or try to do it with ctypes. > 3) There is os.O_DIRECT and os.open help page references it I think the policy is to mirror all possible O_* constants, even if they are of no use in Python. For example, we also have os.O_DIRECTORY. Regards Antoine. |
|||
msg83778 - (view) | Author: Jean-Paul Calderone (exarkun) * | Date: 2009-03-18 21:18 | |
> I think the policy is to mirror all possible O_* constants, even if they > are of no use in Python. For example, we also have os.O_DIRECTORY. Not disagreeing with the conclusion of this ticket, but I would like to point out that os.O_DIRECTORY isn't useless in Python. You need it to use with os.open if you want to open a directory (which you may wish to do in order to use with os.fsync, for example). |
|||
msg276329 - (view) | Author: Michael Mol (Michael Mol) | Date: 2016-09-13 19:20 | |
I need to remember not to try to write quick programs in Python that need O_DIRECT. My use case: I'm attempting to write a program that forces the disk to seek to a particular place, as part of burning in the disk. My algorithm goes: 1. Seek to the beginning of the disk 2. Write to the disk 3. Seek to the end of the disk 4. Write to the disk 5. Seek to the beginning of the disk 6. Read from the disk 7. Seek to the end of the disk 8. Read from the disk It then repeats with offsets, leading the seek distance to shrink until the two positions overlap at the center of the disk, and then expand as the positions diverge to the opposite end of the disk from where they began. It's straightforward, and can be done using mmap and os.write as far as the writing side of things goes, but it does not work on the reading side, as even this workaround does not work: d = os.open(disk_file_path, os.O_RDWR | os.O_DIRECT | os.O_SYNC | os.O_DSYNC) readbuf = mmap.mmap(-1, 4096) os.lseek(d, 0, os.SEEK_SET) fo = os.fdopen(d, 'rb') fo.readinto(readbuf) ... I get errno 22 on the final line. Apparently, code similar to that used to work, but no longer does. |
|||
msg352213 - (view) | Author: Paul (yoyoyopcp) * | Date: 2019-09-12 16:24 | |
Michael, I ran into the same issue as you. I got it to work by changing the mmap size to 8K. d = os.open(disk_file_path, os.O_RDWR | os.O_DIRECT | os.O_SYNC | os.O_DSYNC) readbuf = mmap.mmap(-1, 8192) os.lseek(d, 0, os.SEEK_SET) fo = os.fdopen(d, 'rb') fo.readinto(readbuf) Should work. What's strange is that further multiples of 4K seem to work OK. readbuf = mmap.mmap(-1, 4096 * 3) Also works... So what's going on with 4K? |
|||
msg352359 - (view) | Author: Paul (yoyoyopcp) * | Date: 2019-09-13 16:40 | |
I've dug into stracing this python program in 2.7 vs. 3.7. directread.py import mmap import os fd = os.open('/dev/dm-2', os.O_DIRECT | os.O_RDWR) # mapped block device fo = os.fdopen(fd, 'rb+') m = mmap.mmap(-1, 4096) fo.readinto(m) Python 2.7 result: ... open("/dev/dm-2", O_RDWR|O_DIRECT) = 3 ... mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0) = 0x7f743db31000 ... read(0x3, 0x7f743db31000, 0x1000) = 0x1000 ... Python 3.7 result: ... open("/dev/dm-2", O_RDWR|O_DIRECT|O_CLOEXEC) = 3 ... mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0) = 0x7f5e087ee000 ... read(0x3, 0x256c8a0, 0x1000) = -1 (errno 22) Notice that Python 3 isn't using the mmap buffer for the read. Why is it using a stack buffer? |
|||
msg352392 - (view) | Author: Michael Mol (Michael Mol) | Date: 2019-09-13 20:34 | |
I wound up writing it in C++ instead, and my then-employer eventually opened my code. https://github.com/VirtualInterconnect/diskstress |
|||
msg357927 - (view) | Author: Logan Gunthorpe (logang) | Date: 2019-12-06 17:31 | |
Paul's solution works in 3.7 if you set the buffer size to zero when calling fdopen. fd = os.open("my_file", os.O_DIRECT | os.O_RDWR) f = os.fdopen(fd, "rb+", 0) m = mmap.mmap(-1, 4096) f.readinto(m) This is according to a comment in _pyio.py: # If remaining space in callers buffer is larger than # internal buffer, read directly into callers buffer So by simply disabling the buffer (which is what we'd want for O_DIRECT anyway) readinto() works as expected. However, based on this issue, I'm a little concerned this won't be fully supported by python going forward; so use with care. |
History | |||
---|---|---|---|
Date | User | Action | Args |
2022-04-11 14:56:46 | admin | set | github: 49646 |
2022-01-13 00:08:25 | jwilk | set | nosy:
+ jwilk |
2019-12-06 17:31:25 | logang | set | nosy:
+ logang messages: + msg357927 |
2019-09-13 20:34:32 | Michael Mol | set | messages: + msg352392 |
2019-09-13 16:40:28 | yoyoyopcp | set | messages: + msg352359 |
2019-09-12 16:24:30 | yoyoyopcp | set | nosy:
+ yoyoyopcp messages: + msg352213 |
2016-09-13 19:20:19 | Michael Mol | set | nosy:
+ Michael Mol messages: + msg276329 |
2009-03-18 21:18:12 | exarkun | set | nosy:
+ exarkun messages: + msg83778 |
2009-03-15 16:05:26 | pitrou | set | messages: + msg83639 |
2009-03-15 15:52:06 | aguiar | set | messages: + msg83638 |
2009-03-13 23:02:10 | pitrou | set | status: open -> closed nosy: + pitrou messages: + msg83541 resolution: wont fix |
2009-03-03 11:48:27 | pitrou | set | priority: normal type: behavior -> enhancement versions: + Python 3.1, Python 2.7, - Python 2.6 |
2009-02-28 19:02:30 | aguiar | create |