Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:12.2
s390-tools
s390-tools-sles11sp2-cmsfs-fuse_cont_write.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File s390-tools-sles11sp2-cmsfs-fuse_cont_write.patch of Package s390-tools
Description: cmsfs-fuse: Multiple write requests for fixed record format files Symptom: Writing to a fixed record format file may fail. Problem: If multiple write requests are performed on a fixed record format file cmsfs-fuse looks at the record information to detect the current write position. That can be wrong if a write request on a fixed record format file is not issued on record boundaries. Solution: Maintain a write pointer as long as the file is open and use this write pointer for contiguous writes to a file. Problem-ID: 75939 --- cmsfs-fuse/cmsfs-fuse.c | 105 ++++++++++++++++++++++++++++++------------------ 1 file changed, 67 insertions(+), 38 deletions(-) --- a/cmsfs-fuse/cmsfs-fuse.c +++ b/cmsfs-fuse/cmsfs-fuse.c @@ -116,6 +116,7 @@ static char CODEPAGE_LINUX[] = "ISO-8859 #define RWS_RECORD_INCOMPLETE 0x4 #define RWS_RECORD_COMPLETE 0x8 +#define BWS_BLOCK_NOT_INIT 0x0 #define BWS_BLOCK_NEW 0x1 #define BWS_BLOCK_USED 0x2 @@ -172,6 +173,15 @@ struct file_operations { static struct file_operations fops_fixed; static struct file_operations fops_variable; +struct write_state { + int block_state; + /* number of free bytes in the current block */ + int block_free; + int var_record_state; + /* remaining record bytes for a write request */ + int var_record_len; +}; + /* * File object for operations that follow open */ @@ -204,8 +214,8 @@ struct file { int pad_bytes; /* old levels value, needed to rewrite pointers */ int old_levels; - /* record write state for variable headers */ - struct var_record_state *vrstate; + /* state information needed for a write request */ + struct write_state *wstate; /* path name for open and unlink */ char path[MAX_FNAME + 1]; /* counter for pseudo null length records */ @@ -232,12 +242,6 @@ struct file { int unlinked; }; -struct var_record_state { - int rlen; - int record_state; - int block_state; -}; - struct xattr { char name[20]; size_t size; @@ -3388,6 +3392,12 @@ static int examine_last_block(struct fil if (!f->fst->nr_blocks || !f->fst->nr_records) return 0; + /* + * For subsequent writes we know how much is left on the current block. + * */ + if (f->wstate->block_state != BWS_BLOCK_NOT_INIT) + return f->wstate->block_free; + last_bnr = f->fst->nr_blocks - 1; rec = &f->rlist[f->fst->nr_records - 1]; @@ -3454,6 +3464,16 @@ static off_t disk_end(struct file *f) if (!f->fst->nr_records) return 0; + /* + * Only the first write on a newly opened file should set the write_ptr + * according to what is on the disk. Subsequent writes should use the + * actual write_ptr. This avoids the problem for fixed records that + * for a record that is not yet completely written the calculated + * write_ptr would be wrong. + */ + if (f->wstate->block_state != BWS_BLOCK_NOT_INIT) + return f->write_ptr; + rec = &f->rlist[f->fst->nr_records - 1]; if (rec->ext == NULL) { if (rec->disk_start == NULL_BLOCK) @@ -3481,7 +3501,7 @@ static off_t disk_end(struct file *f) void store_displacement(struct file *f, int disp) { f->blist[f->fst->nr_blocks - 1].disp = disp; - f->vrstate->block_state = BWS_BLOCK_USED; + f->wstate->block_state = BWS_BLOCK_USED; } /* @@ -3537,13 +3557,12 @@ static int write_prepare_block(struct fi } if (new_block) { - if (f->fst->record_format == RECORD_LEN_VARIABLE) - f->vrstate->block_state = BWS_BLOCK_NEW; + f->wstate->block_state = BWS_BLOCK_NEW; f->blist[f->fst->nr_blocks].disk_addr = f->write_ptr; if (!f->write_ptr && f->fst->record_format == RECORD_LEN_FIXED) f->nr_null_blocks++; - + f->wstate->block_free = cmsfs.blksize; f->fst->nr_blocks++; } return len; @@ -3557,23 +3576,24 @@ static int write_var_header(struct file u8 half_vheader; int rc; - if (f->vrstate->record_state == RWS_HEADER_COMPLETE || - f->vrstate->record_state == RWS_RECORD_INCOMPLETE) + if (f->wstate->var_record_state == RWS_HEADER_COMPLETE || + f->wstate->var_record_state == RWS_RECORD_INCOMPLETE) return 0; - if (f->vrstate->record_state == RWS_HEADER_STARTED) { + if (f->wstate->var_record_state == RWS_HEADER_STARTED) { /* write secord header byte */ half_vheader = vheader & 0xff; rc = _write(&half_vheader, 1, f->write_ptr); if (rc < 0) return rc; f->write_ptr++; - f->vrstate->record_state = RWS_HEADER_COMPLETE; + f->wstate->block_free--; + f->wstate->var_record_state = RWS_HEADER_COMPLETE; return 1; } /* block cannot be spanned if a header starts on it */ - if (f->vrstate->block_state == BWS_BLOCK_NEW) + if (f->wstate->block_state == BWS_BLOCK_NEW) store_displacement(f, f->write_ptr & DATA_BLOCK_MASK); if (len >= 2) { @@ -3581,8 +3601,9 @@ static int write_var_header(struct file if (rc < 0) return rc; f->write_ptr += 2; - f->vrstate->rlen = vheader; - f->vrstate->record_state = RWS_HEADER_COMPLETE; + f->wstate->block_free -= 2; + f->wstate->var_record_len = vheader; + f->wstate->var_record_state = RWS_HEADER_COMPLETE; return 2; } else { /* len = 1, write first header byte */ @@ -3591,8 +3612,9 @@ static int write_var_header(struct file if (rc < 0) return rc; f->write_ptr++; - f->vrstate->rlen = vheader; - f->vrstate->record_state = RWS_HEADER_STARTED; + f->wstate->block_free--; + f->wstate->var_record_len = vheader; + f->wstate->var_record_state = RWS_HEADER_STARTED; return 1; } } @@ -3611,6 +3633,7 @@ static int extend_block_fixed(struct fil if (rc < 0) return rc; f->write_ptr += len; + f->wstate->block_free -= len; } return len; } @@ -3638,15 +3661,16 @@ static int extend_block_variable(struct if (len < rlen) rlen = len; /* remaining record data less than block len */ - if (f->vrstate->rlen < rlen) - rlen = f->vrstate->rlen; + if (f->wstate->var_record_len < rlen) + rlen = f->wstate->var_record_len; rc = _write(buf, rlen, f->write_ptr); if (rc < 0) return rc; f->write_ptr += rlen; + f->wstate->block_free -= rlen; - if (f->vrstate->block_state == BWS_BLOCK_NEW) { + if (f->wstate->block_state == BWS_BLOCK_NEW) { /* * If the second byte of a split header was written * (blocksize - 1) is enough to make the block spanned. @@ -3663,11 +3687,11 @@ static int extend_block_variable(struct copied += rlen; size -= rlen; len -= rlen; - f->vrstate->rlen -= rlen; + f->wstate->var_record_len -= rlen; - BUG(f->vrstate->rlen < 0); - if (!f->vrstate->rlen) { - f->vrstate->record_state = RWS_RECORD_COMPLETE; + BUG(f->wstate->var_record_len < 0); + if (!f->wstate->var_record_len) { + f->wstate->var_record_state = RWS_RECORD_COMPLETE; /* reset rlen for the next record */ rlen = get_record_len(f, size); } @@ -3678,7 +3702,7 @@ static int extend_block_variable(struct } /* record is not yet finished */ - f->vrstate->record_state = RWS_RECORD_INCOMPLETE; + f->wstate->var_record_state = RWS_RECORD_INCOMPLETE; return copied; } @@ -3923,6 +3947,12 @@ static int update_last_block_vptr(struct return update_last_block_vptr(f, ABS(vptr->next), level, vptr); } +static void reset_write_state(struct file *f) +{ + f->wstate->var_record_state = RWS_RECORD_COMPLETE; + f->wstate->var_record_len = 0; +} + /* * Append records at current file end. If buf is NULL write zero bytes. */ @@ -3950,8 +3980,7 @@ static int write_append(struct file *f, if (f->fst->nr_blocks + nblocks > 1) reserve_meta_blocks(f, f->fst->nr_blocks, nblocks, 1); - if (f->fst->record_format == RECORD_LEN_VARIABLE) - f->vrstate->record_state = RWS_RECORD_COMPLETE; + reset_write_state(f); /* first use existing last block */ if (last) { @@ -4286,10 +4315,10 @@ static struct file *create_file_object(s else f->ptr_per_block = cmsfs.var_ptrs_per_block; - f->vrstate = malloc(sizeof(*f->vrstate)); - if (f->vrstate == NULL) + f->wstate = malloc(sizeof(*f->wstate)); + if (f->wstate == NULL) goto oom_fst; - memset(f->vrstate, 0, sizeof(*f->vrstate)); + memset(f->wstate, 0, sizeof(*f->wstate)); /* * Prevent calloc for zero records since it returns a pointer != NULL @@ -4300,7 +4329,7 @@ static struct file *create_file_object(s f->rlist = calloc(f->fst->nr_records, sizeof(struct record)); if (f->rlist == NULL) - goto oom_vrstate; + goto oom_wstate; f->blist = calloc(f->fst->nr_blocks, sizeof(struct block)); if (f->blist == NULL) @@ -4316,8 +4345,8 @@ error: *rc = -ENOMEM; oom_rlist: free(f->rlist); -oom_vrstate: - free(f->vrstate); +oom_wstate: + free(f->wstate); oom_fst: free(f->fst); oom_f: @@ -4333,7 +4362,7 @@ static void destroy_file_object(struct f int i; free(f->wcache); - free(f->vrstate); + free(f->wstate); for (i = 0; i < f->fst->nr_records; i++) { rec = &f->rlist[i];
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