Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:13.1:Update
s390-tools
s390-tools-sles11sp2-cmsfs-fuse_pread_pwrite.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File s390-tools-sles11sp2-cmsfs-fuse_pread_pwrite.patch of Package s390-tools
Description: cmsfs-fuse: Use pread/pwrite if mmap'ing the whole disk fails Symptom: Trying to mount a disk fails with -ENOMEM. Problem: On mounting a disk cmsfs-fuse tries to mmap the whole disk. This can fail for very large disks or if the virtual memory is limited. Solution: Add a fall back to pread and pwrite in case the mmap system call fails. Problem-ID: 79223 --- cmsfs-fuse/cmsfs-fuse.c | 102 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 80 insertions(+), 22 deletions(-) --- a/cmsfs-fuse/cmsfs-fuse.c +++ b/cmsfs-fuse/cmsfs-fuse.c @@ -171,6 +171,13 @@ struct file_operations { static struct file_operations fops_fixed; static struct file_operations fops_variable; +struct io_operations { + int (*read) (void *buf, size_t size, off_t addr); + int (*write) (const void *buf, size_t size, off_t addr); +}; + +struct io_operations io_ops; + struct write_state { int block_state; /* number of free bytes in the current block */ @@ -310,28 +317,65 @@ static inline struct file *get_fobj(stru return (struct file *) fi->fh; } -int _read(void *buf, size_t size, off_t addr) +static int access_ok(size_t size, off_t addr) { if (((addr + (off_t) size - 1) & ~DATA_BLOCK_MASK) > (addr & ~DATA_BLOCK_MASK)) - DIE("read: crossing blocks addr: %lx size: %ld\n", - addr, size); - if (addr < cmsfs.label || addr > cmsfs.size) - return -EIO; + DIE("crossing disk blocks, addr: %x size: %d\n", + (int) addr, (int) size); + + if ((unsigned long long) addr < (unsigned long long) cmsfs.label + || addr > cmsfs.size) + return 0; + return 1; +} +int read_memory(void *buf, size_t size, off_t addr) +{ memcpy(buf, cmsfs.map + addr, size); return 0; } -int _write(const void *buf, size_t size, off_t addr) +int read_syscall(void *buf, size_t size, off_t addr) { - if (((addr + (off_t) size - 1) & ~DATA_BLOCK_MASK) > - (addr & ~DATA_BLOCK_MASK)) - DIE("write: crossing blocks addr: %x size: %d\n", - (int)addr, (int)size); - if (addr < cmsfs.label || addr > cmsfs.size) + int rc; + + rc = pread(cmsfs.fd, buf, size, addr); + if (rc < 0) + perror("pread failed"); + return rc; +} + +int _read(void *buf, size_t size, off_t addr) +{ + if (!access_ok(size, addr)) return -EIO; + return io_ops.read(buf, size, addr); +} + +int write_syscall(const void *buf, size_t size, off_t addr) +{ + char *zbuf; + int rc; + + if (buf == NULL) { + zbuf = malloc(size); + if (zbuf == NULL) + return -ENOMEM; + memset(zbuf, 0, size); + rc = pwrite(cmsfs.fd, zbuf, size, addr); + free(zbuf); + } else + rc = pwrite(cmsfs.fd, buf, size, addr); + + if (rc < 0) + perror("pwrite failed"); + return rc; +} + +int write_memory(const void *buf, size_t size, off_t addr) +{ if (buf == NULL) memset(cmsfs.map + addr, 0, size); else @@ -339,6 +383,14 @@ int _write(const void *buf, size_t size, return 0; } +int _write(const void *buf, size_t size, off_t addr) +{ + if (!access_ok(size, addr)) + return -EIO; + + return io_ops.write(buf, size, addr); +} + int _zero(off_t addr, size_t size) { return _write(NULL, size, addr); @@ -4459,29 +4511,36 @@ static int cmsfs_process_args(void *data } } -static void map_device(int fd) +static void init_io(int fd) { int prot; - /* fstat on block device says st_size = 0... */ - lseek(fd, 0, SEEK_SET); - cmsfs.size = lseek(fd, 0, SEEK_END); - DEBUG("mmap size: %lu", cmsfs.size); + DEBUG("read-only: %d", cmsfs.readonly); + cmsfs.fd = fd; + cmsfs.size = (off_t) cmsfs.total_blocks * cmsfs.blksize; + DEBUG(" mmap size: %lu", cmsfs.size); - /* map the whole block device for speeding-up access */ + /* try to map the whole block device for speeding-up access */ if (cmsfs.readonly) prot = PROT_READ; else prot = PROT_READ | PROT_WRITE; + cmsfs.map = mmap(NULL, cmsfs.size, prot, MAP_SHARED, fd, 0); - if (cmsfs.map == MAP_FAILED) - DIE_PERROR("mmap failed"); - DEBUG(" addr: %p read-only: %d\n", cmsfs.map, cmsfs.readonly); + if (cmsfs.map == MAP_FAILED) { + DEBUG("\nmmap failed, using pread/write for disk I/O.\n"); + io_ops.read = &read_syscall; + io_ops.write = &write_syscall; + } else { + DEBUG(" addr: %p\n", cmsfs.map); + io_ops.read = &read_memory; + io_ops.write = &write_memory; + } } static void cmsfs_init(int fd) { - map_device(fd); + init_io(fd); /* calculate blocksize dependent values */ cmsfs.data_block_mask = cmsfs.blksize - 1; @@ -4550,7 +4609,6 @@ int main(int argc, char *argv[]) free(fsname); cmsfs_init(fd); - cmsfs.fd = fd; if (cmsfs.readonly) fuse_opt_add_arg(&args, "-oro");
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor