diff options
Diffstat (limited to 'linux-2.4.x/fs/jffs2/file.c')
-rw-r--r-- | linux-2.4.x/fs/jffs2/file.c | 521 |
1 files changed, 124 insertions, 397 deletions
diff --git a/linux-2.4.x/fs/jffs2/file.c b/linux-2.4.x/fs/jffs2/file.c index b12c0f4..61effa9 100644 --- a/linux-2.4.x/fs/jffs2/file.c +++ b/linux-2.4.x/fs/jffs2/file.c @@ -1,383 +1,171 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2001 Red Hat, Inc. + * Copyright (C) 2001-2003 Red Hat, Inc. * - * Created by David Woodhouse <dwmw2@cambridge.redhat.com> + * Created by David Woodhouse <dwmw2@infradead.org> * - * The original JFFS, from which the design for JFFS2 was derived, - * was designed and implemented by Axis Communications AB. + * For licensing information, see the file 'LICENCE' in this directory. * - * The contents of this file are subject to the Red Hat eCos Public - * License Version 1.1 (the "Licence"); you may not use this file - * except in compliance with the Licence. You may obtain a copy of - * the Licence at http://www.redhat.com/ - * - * Software distributed under the Licence is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. - * See the Licence for the specific language governing rights and - * limitations under the Licence. - * - * The Original Code is JFFS2 - Journalling Flash File System, version 2 - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the RHEPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the RHEPL or the GPL. - * - * $Id: file.c,v 1.58.2.6 2002/11/12 13:17:01 dwmw2 Exp $ + * $Id: file.c,v 1.106 2005/11/07 11:14:39 gleixner Exp $ * */ #include <linux/kernel.h> -#include <linux/mtd/compatmac.h> /* for min() */ #include <linux/slab.h> #include <linux/fs.h> +#include <linux/time.h> #include <linux/pagemap.h> +#include <linux/highmem.h> +#include <linux/crc32.h> #include <linux/jffs2.h> #include "nodelist.h" -#include "crc32.h" - -extern int generic_file_open(struct inode *, struct file *) __attribute__((weak)); -extern loff_t generic_file_llseek(struct file *file, loff_t offset, int origin) __attribute__((weak)); +static int jffs2_commit_write (struct file *filp, struct page *pg, + unsigned start, unsigned end); +static int jffs2_prepare_write (struct file *filp, struct page *pg, + unsigned start, unsigned end); +static int jffs2_readpage (struct file *filp, struct page *pg); -int jffs2_null_fsync(struct file *filp, struct dentry *dentry, int datasync) +int jffs2_fsync(struct file *filp, struct dentry *dentry, int datasync) { - /* Move along. Nothing to see here */ + struct inode *inode = dentry->d_inode; + struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); + + /* Trigger GC to flush any pending writes for this inode */ + jffs2_flush_wbuf_gc(c, inode->i_ino); + return 0; } struct file_operations jffs2_file_operations = { - llseek: generic_file_llseek, - open: generic_file_open, - read: generic_file_read, - write: generic_file_write, - ioctl: jffs2_ioctl, - mmap: generic_file_mmap, - fsync: jffs2_null_fsync + .llseek = generic_file_llseek, + .open = generic_file_open, + .read = generic_file_read, + .write = generic_file_write, + .ioctl = jffs2_ioctl, + .mmap = generic_file_readonly_mmap, + .fsync = jffs2_fsync, + .sendfile = generic_file_sendfile }; /* jffs2_file_inode_operations */ struct inode_operations jffs2_file_inode_operations = { - setattr: jffs2_setattr + .setattr = jffs2_setattr }; struct address_space_operations jffs2_file_address_operations = { - readpage: jffs2_readpage, - prepare_write: jffs2_prepare_write, - commit_write: jffs2_commit_write + .readpage = jffs2_readpage, + .prepare_write =jffs2_prepare_write, + .commit_write = jffs2_commit_write }; -int jffs2_setattr (struct dentry *dentry, struct iattr *iattr) -{ - struct jffs2_full_dnode *old_metadata, *new_metadata; - struct inode *inode = dentry->d_inode; - struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); - struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); - struct jffs2_raw_inode *ri; - unsigned short dev; - unsigned char *mdata = NULL; - int mdatalen = 0; - unsigned int ivalid; - __u32 phys_ofs, alloclen; - int ret; - D1(printk(KERN_DEBUG "jffs2_setattr(): ino #%lu\n", inode->i_ino)); - ret = inode_change_ok(inode, iattr); - if (ret) - return ret; - - /* Special cases - we don't want more than one data node - for these types on the medium at any time. So setattr - must read the original data associated with the node - (i.e. the device numbers or the target name) and write - it out again with the appropriate data attached */ - if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) { - /* For these, we don't actually need to read the old node */ - dev = (MAJOR(to_kdev_t(dentry->d_inode->i_rdev)) << 8) | - MINOR(to_kdev_t(dentry->d_inode->i_rdev)); - mdata = (char *)&dev; - mdatalen = sizeof(dev); - D1(printk(KERN_DEBUG "jffs2_setattr(): Writing %d bytes of kdev_t\n", mdatalen)); - } else if (S_ISLNK(inode->i_mode)) { - mdatalen = f->metadata->size; - mdata = kmalloc(f->metadata->size, GFP_USER); - if (!mdata) - return -ENOMEM; - ret = jffs2_read_dnode(c, f->metadata, mdata, 0, mdatalen); - if (ret) { - kfree(mdata); - return ret; - } - D1(printk(KERN_DEBUG "jffs2_setattr(): Writing %d bytes of symlink target\n", mdatalen)); - } - - ri = jffs2_alloc_raw_inode(); - if (!ri) { - if (S_ISLNK(inode->i_mode)) - kfree(mdata); - return -ENOMEM; - } - - ret = jffs2_reserve_space(c, sizeof(*ri) + mdatalen, &phys_ofs, &alloclen, ALLOC_NORMAL); - if (ret) { - jffs2_free_raw_inode(ri); - if (S_ISLNK(inode->i_mode)) - kfree(mdata); - return ret; - } - down(&f->sem); - ivalid = iattr->ia_valid; - - ri->magic = JFFS2_MAGIC_BITMASK; - ri->nodetype = JFFS2_NODETYPE_INODE; - ri->totlen = sizeof(*ri) + mdatalen; - ri->hdr_crc = crc32(0, ri, sizeof(struct jffs2_unknown_node)-4); - - ri->ino = inode->i_ino; - ri->version = ++f->highest_version; - - ri->mode = (ivalid & ATTR_MODE)?iattr->ia_mode:inode->i_mode; - ri->uid = (ivalid & ATTR_UID)?iattr->ia_uid:inode->i_uid; - ri->gid = (ivalid & ATTR_GID)?iattr->ia_gid:inode->i_gid; - - if (ivalid & ATTR_MODE && ri->mode & S_ISGID && - !in_group_p(ri->gid) && !capable(CAP_FSETID)) - ri->mode &= ~S_ISGID; - - ri->isize = (ivalid & ATTR_SIZE)?iattr->ia_size:inode->i_size; - ri->atime = (ivalid & ATTR_ATIME)?iattr->ia_atime:inode->i_atime; - ri->mtime = (ivalid & ATTR_MTIME)?iattr->ia_mtime:inode->i_mtime; - ri->ctime = (ivalid & ATTR_CTIME)?iattr->ia_ctime:inode->i_ctime; - - ri->offset = 0; - ri->csize = ri->dsize = mdatalen; - ri->compr = JFFS2_COMPR_NONE; - if (inode->i_size < ri->isize) { - /* It's an extension. Make it a hole node */ - ri->compr = JFFS2_COMPR_ZERO; - ri->dsize = ri->isize - inode->i_size; - ri->offset = inode->i_size; - } - ri->node_crc = crc32(0, ri, sizeof(*ri)-8); - if (mdatalen) - ri->data_crc = crc32(0, mdata, mdatalen); - else - ri->data_crc = 0; - - new_metadata = jffs2_write_dnode(inode, ri, mdata, mdatalen, phys_ofs, NULL); - if (S_ISLNK(inode->i_mode)) - kfree(mdata); - - jffs2_complete_reservation(c); - - if (IS_ERR(new_metadata)) { - jffs2_free_raw_inode(ri); - up(&f->sem); - return PTR_ERR(new_metadata); - } - /* It worked. Update the inode */ - inode->i_atime = ri->atime; - inode->i_ctime = ri->ctime; - inode->i_mtime = ri->mtime; - inode->i_mode = ri->mode; - inode->i_uid = ri->uid; - inode->i_gid = ri->gid; - - - old_metadata = f->metadata; - - if (inode->i_size > ri->isize) { - vmtruncate(inode, ri->isize); - jffs2_truncate_fraglist (c, &f->fraglist, ri->isize); - } - - if (inode->i_size < ri->isize) { - jffs2_add_full_dnode_to_inode(c, f, new_metadata); - inode->i_size = ri->isize; - f->metadata = NULL; - } else { - f->metadata = new_metadata; - } - if (old_metadata) { - jffs2_mark_node_obsolete(c, old_metadata->raw); - jffs2_free_full_dnode(old_metadata); - } - jffs2_free_raw_inode(ri); - up(&f->sem); - return 0; -} - -int jffs2_do_readpage_nolock (struct inode *inode, struct page *pg) +static int jffs2_do_readpage_nolock (struct inode *inode, struct page *pg) { struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); - struct jffs2_node_frag *frag = f->fraglist; - __u32 offset = pg->index << PAGE_CACHE_SHIFT; - __u32 end = offset + PAGE_CACHE_SIZE; unsigned char *pg_buf; int ret; - D1(printk(KERN_DEBUG "jffs2_do_readpage_nolock(): ino #%lu, page at offset 0x%x\n", inode->i_ino, offset)); - - if (!PageLocked(pg)) - PAGE_BUG(pg); + D2(printk(KERN_DEBUG "jffs2_do_readpage_nolock(): ino #%lu, page at offset 0x%lx\n", inode->i_ino, pg->index << PAGE_CACHE_SHIFT)); - while(frag && frag->ofs + frag->size <= offset) { - // D1(printk(KERN_DEBUG "skipping frag %d-%d; before the region we care about\n", frag->ofs, frag->ofs + frag->size)); - frag = frag->next; - } + BUG_ON(!PageLocked(pg)); pg_buf = kmap(pg); + /* FIXME: Can kmap fail? */ - /* XXX FIXME: Where a single physical node actually shows up in two - frags, we read it twice. Don't do that. */ - /* Now we're pointing at the first frag which overlaps our page */ - while(offset < end) { - D2(printk(KERN_DEBUG "jffs2_readpage: offset %d, end %d\n", offset, end)); - if (!frag || frag->ofs > offset) { - __u32 holesize = end - offset; - if (frag) { - D1(printk(KERN_NOTICE "Eep. Hole in ino %ld fraglist. frag->ofs = 0x%08x, offset = 0x%08x\n", inode->i_ino, frag->ofs, offset)); - holesize = min(holesize, frag->ofs - offset); - D1(jffs2_print_frag_list(f)); - } - D1(printk(KERN_DEBUG "Filling non-frag hole from %d-%d\n", offset, offset+holesize)); - memset(pg_buf, 0, holesize); - pg_buf += holesize; - offset += holesize; - continue; - } else if (frag->ofs < offset && (offset & (PAGE_CACHE_SIZE-1)) != 0) { - D1(printk(KERN_NOTICE "Eep. Overlap in ino #%ld fraglist. frag->ofs = 0x%08x, offset = 0x%08x\n", - inode->i_ino, frag->ofs, offset)); - D1(jffs2_print_frag_list(f)); - memset(pg_buf, 0, end - offset); - ClearPageUptodate(pg); - SetPageError(pg); - kunmap(pg); - return -EIO; - } else if (!frag->node) { - __u32 holeend = min(end, frag->ofs + frag->size); - D1(printk(KERN_DEBUG "Filling frag hole from %d-%d (frag 0x%x 0x%x)\n", offset, holeend, frag->ofs, frag->ofs + frag->size)); - memset(pg_buf, 0, holeend - offset); - pg_buf += holeend - offset; - offset = holeend; - frag = frag->next; - continue; - } else { - __u32 readlen; - __u32 fragofs; /* offset within the frag to start reading */ - - fragofs = offset - frag->ofs; - readlen = min(frag->size - fragofs, end - offset); - D1(printk(KERN_DEBUG "Reading %d-%d from node at 0x%x\n", frag->ofs+fragofs, - fragofs+frag->ofs+readlen, frag->node->raw->flash_offset & ~3)); - ret = jffs2_read_dnode(c, frag->node, pg_buf, fragofs + frag->ofs - frag->node->ofs, readlen); - D2(printk(KERN_DEBUG "node read done\n")); - if (ret) { - D1(printk(KERN_DEBUG"jffs2_readpage error %d\n",ret)); - memset(pg_buf, 0, readlen); - ClearPageUptodate(pg); - SetPageError(pg); - kunmap(pg); - return ret; - } - - pg_buf += readlen; - offset += readlen; - frag = frag->next; - D2(printk(KERN_DEBUG "node read was OK. Looping\n")); - } + ret = jffs2_read_inode_range(c, f, pg_buf, pg->index << PAGE_CACHE_SHIFT, PAGE_CACHE_SIZE); + + if (ret) { + ClearPageUptodate(pg); + SetPageError(pg); + } else { + SetPageUptodate(pg); + ClearPageError(pg); } - D2(printk(KERN_DEBUG "readpage finishing\n")); - SetPageUptodate(pg); - ClearPageError(pg); flush_dcache_page(pg); - kunmap(pg); - D1(printk(KERN_DEBUG "readpage finished\n")); + + D2(printk(KERN_DEBUG "readpage finished\n")); return 0; } int jffs2_do_readpage_unlock(struct inode *inode, struct page *pg) { int ret = jffs2_do_readpage_nolock(inode, pg); - UnlockPage(pg); + unlock_page(pg); return ret; } -int jffs2_readpage (struct file *filp, struct page *pg) +static int jffs2_readpage (struct file *filp, struct page *pg) { struct jffs2_inode_info *f = JFFS2_INODE_INFO(pg->mapping->host); int ret; - + down(&f->sem); ret = jffs2_do_readpage_unlock(pg->mapping->host, pg); up(&f->sem); return ret; } -int jffs2_prepare_write (struct file *filp, struct page *pg, unsigned start, unsigned end) +static int jffs2_prepare_write (struct file *filp, struct page *pg, + unsigned start, unsigned end) { struct inode *inode = pg->mapping->host; struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); - __u32 pageofs = pg->index << PAGE_CACHE_SHIFT; + uint32_t pageofs = pg->index << PAGE_CACHE_SHIFT; int ret = 0; - D1(printk(KERN_DEBUG "jffs2_prepare_write() nrpages %ld\n", inode->i_mapping->nrpages)); + D1(printk(KERN_DEBUG "jffs2_prepare_write()\n")); if (pageofs > inode->i_size) { /* Make new hole frag from old EOF to new page */ struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); struct jffs2_raw_inode ri; struct jffs2_full_dnode *fn; - __u32 phys_ofs, alloc_len; - + uint32_t phys_ofs, alloc_len; + D1(printk(KERN_DEBUG "Writing new hole frag 0x%x-0x%x between current EOF and new page\n", (unsigned int)inode->i_size, pageofs)); - ret = jffs2_reserve_space(c, sizeof(ri), &phys_ofs, &alloc_len, ALLOC_NORMAL); + ret = jffs2_reserve_space(c, sizeof(ri), &phys_ofs, &alloc_len, + ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE); if (ret) return ret; down(&f->sem); memset(&ri, 0, sizeof(ri)); - ri.magic = JFFS2_MAGIC_BITMASK; - ri.nodetype = JFFS2_NODETYPE_INODE; - ri.totlen = sizeof(ri); - ri.hdr_crc = crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4); - - ri.ino = f->inocache->ino; - ri.version = ++f->highest_version; - ri.mode = inode->i_mode; - ri.uid = inode->i_uid; - ri.gid = inode->i_gid; - ri.isize = max((__u32)inode->i_size, pageofs); - ri.atime = ri.ctime = ri.mtime = CURRENT_TIME; - ri.offset = inode->i_size; - ri.dsize = pageofs - inode->i_size; - ri.csize = 0; + ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); + ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); + ri.totlen = cpu_to_je32(sizeof(ri)); + ri.hdr_crc = cpu_to_je32(crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4)); + + ri.ino = cpu_to_je32(f->inocache->ino); + ri.version = cpu_to_je32(++f->highest_version); + ri.mode = cpu_to_jemode(inode->i_mode); + ri.uid = cpu_to_je16(inode->i_uid); + ri.gid = cpu_to_je16(inode->i_gid); + ri.isize = cpu_to_je32(max((uint32_t)inode->i_size, pageofs)); + ri.atime = ri.ctime = ri.mtime = cpu_to_je32(get_seconds()); + ri.offset = cpu_to_je32(inode->i_size); + ri.dsize = cpu_to_je32(pageofs - inode->i_size); + ri.csize = cpu_to_je32(0); ri.compr = JFFS2_COMPR_ZERO; - ri.node_crc = crc32(0, &ri, sizeof(ri)-8); - ri.data_crc = 0; - - fn = jffs2_write_dnode(inode, &ri, NULL, 0, phys_ofs, NULL); - jffs2_complete_reservation(c); + ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8)); + ri.data_crc = cpu_to_je32(0); + + fn = jffs2_write_dnode(c, f, &ri, NULL, 0, phys_ofs, ALLOC_NORMAL); + if (IS_ERR(fn)) { ret = PTR_ERR(fn); + jffs2_complete_reservation(c); up(&f->sem); return ret; } @@ -391,16 +179,17 @@ int jffs2_prepare_write (struct file *filp, struct page *pg, unsigned start, uns D1(printk(KERN_DEBUG "Eep. add_full_dnode_to_inode() failed in prepare_write, returned %d\n", ret)); jffs2_mark_node_obsolete(c, fn->raw); jffs2_free_full_dnode(fn); + jffs2_complete_reservation(c); up(&f->sem); return ret; } + jffs2_complete_reservation(c); inode->i_size = pageofs; up(&f->sem); } - /* Read in the page if it wasn't already present, unless it's a whole page */ - if (!Page_Uptodate(pg) && (start || end < PAGE_CACHE_SIZE)) { + if (!PageUptodate(pg) && (start || end < PAGE_CACHE_SIZE)) { down(&f->sem); ret = jffs2_do_readpage_nolock(inode, pg); up(&f->sem); @@ -409,7 +198,8 @@ int jffs2_prepare_write (struct file *filp, struct page *pg, unsigned start, uns return ret; } -int jffs2_commit_write (struct file *filp, struct page *pg, unsigned start, unsigned end) +static int jffs2_commit_write (struct file *filp, struct page *pg, + unsigned start, unsigned end) { /* Actually commit the write from the page cache page we're looking at. * For now, we write the full page out each time. It sucks, but it's simple @@ -417,141 +207,78 @@ int jffs2_commit_write (struct file *filp, struct page *pg, unsigned start, unsi struct inode *inode = pg->mapping->host; struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); - __u32 newsize = max_t(__u32, filp->f_dentry->d_inode->i_size, (pg->index << PAGE_CACHE_SHIFT) + end); - __u32 file_ofs = (pg->index << PAGE_CACHE_SHIFT); - __u32 writelen = min((__u32)PAGE_CACHE_SIZE, newsize - file_ofs); struct jffs2_raw_inode *ri; + unsigned aligned_start = start & ~3; int ret = 0; - ssize_t writtenlen = 0; + uint32_t writtenlen = 0; - D1(printk(KERN_DEBUG "jffs2_commit_write(): ino #%lu, page at 0x%lx, range %d-%d, flags %lx\n", inode->i_ino, pg->index << PAGE_CACHE_SHIFT, start, end, pg->flags)); + D1(printk(KERN_DEBUG "jffs2_commit_write(): ino #%lu, page at 0x%lx, range %d-%d, flags %lx\n", + inode->i_ino, pg->index << PAGE_CACHE_SHIFT, start, end, pg->flags)); if (!start && end == PAGE_CACHE_SIZE) { /* We need to avoid deadlock with page_cache_read() in jffs2_garbage_collect_pass(). So we have to mark the - page up to date, to prevent page_cache_read() from + page up to date, to prevent page_cache_read() from trying to re-lock it. */ SetPageUptodate(pg); } ri = jffs2_alloc_raw_inode(); - if (!ri) + + if (!ri) { + D1(printk(KERN_DEBUG "jffs2_commit_write(): Allocation of raw inode failed\n")); return -ENOMEM; + } - while(writelen) { - struct jffs2_full_dnode *fn; - unsigned char *comprbuf = NULL; - unsigned char comprtype = JFFS2_COMPR_NONE; - __u32 phys_ofs, alloclen; - __u32 datalen, cdatalen; + /* Set the fields that the generic jffs2_write_inode_range() code can't find */ + ri->ino = cpu_to_je32(inode->i_ino); + ri->mode = cpu_to_jemode(inode->i_mode); + ri->uid = cpu_to_je16(inode->i_uid); + ri->gid = cpu_to_je16(inode->i_gid); + ri->isize = cpu_to_je32((uint32_t)inode->i_size); + ri->atime = ri->ctime = ri->mtime = cpu_to_je32(get_seconds()); - D2(printk(KERN_DEBUG "jffs2_commit_write() loop: 0x%x to write to 0x%x\n", writelen, file_ofs)); + /* In 2.4, it was already kmapped by generic_file_write(). Doesn't + hurt to do it again. The alternative is ifdefs, which are ugly. */ + kmap(pg); - ret = jffs2_reserve_space(c, sizeof(*ri) + JFFS2_MIN_DATA_LEN, &phys_ofs, &alloclen, ALLOC_NORMAL); - if (ret) { - SetPageError(pg); - D1(printk(KERN_DEBUG "jffs2_reserve_space returned %d\n", ret)); - break; - } - down(&f->sem); - datalen = writelen; - cdatalen = min(alloclen - sizeof(*ri), writelen); + ret = jffs2_write_inode_range(c, f, ri, page_address(pg) + aligned_start, + (pg->index << PAGE_CACHE_SHIFT) + aligned_start, + end - aligned_start, &writtenlen); - comprbuf = kmalloc(cdatalen, GFP_KERNEL); - if (comprbuf) { - comprtype = jffs2_compress(page_address(pg)+ (file_ofs & (PAGE_CACHE_SIZE-1)), comprbuf, &datalen, &cdatalen); - } - if (comprtype == JFFS2_COMPR_NONE) { - /* Either compression failed, or the allocation of comprbuf failed */ - if (comprbuf) - kfree(comprbuf); - comprbuf = page_address(pg) + (file_ofs & (PAGE_CACHE_SIZE -1)); - datalen = cdatalen; - } - /* Now comprbuf points to the data to be written, be it compressed or not. - comprtype holds the compression type, and comprtype == JFFS2_COMPR_NONE means - that the comprbuf doesn't need to be kfree()d. - */ - - ri->magic = JFFS2_MAGIC_BITMASK; - ri->nodetype = JFFS2_NODETYPE_INODE; - ri->totlen = sizeof(*ri) + cdatalen; - ri->hdr_crc = crc32(0, ri, sizeof(struct jffs2_unknown_node)-4); - - ri->ino = inode->i_ino; - ri->version = ++f->highest_version; - ri->mode = inode->i_mode; - ri->uid = inode->i_uid; - ri->gid = inode->i_gid; - ri->isize = max((__u32)inode->i_size, file_ofs + datalen); - ri->atime = ri->ctime = ri->mtime = CURRENT_TIME; - ri->offset = file_ofs; - ri->csize = cdatalen; - ri->dsize = datalen; - ri->compr = comprtype; - ri->node_crc = crc32(0, ri, sizeof(*ri)-8); - ri->data_crc = crc32(0, comprbuf, cdatalen); - - fn = jffs2_write_dnode(inode, ri, comprbuf, cdatalen, phys_ofs, NULL); + kunmap(pg); - jffs2_complete_reservation(c); + if (ret) { + /* There was an error writing. */ + SetPageError(pg); + } - if (comprtype != JFFS2_COMPR_NONE) - kfree(comprbuf); + /* Adjust writtenlen for the padding we did, so we don't confuse our caller */ + if (writtenlen < (start&3)) + writtenlen = 0; + else + writtenlen -= (start&3); - if (IS_ERR(fn)) { - ret = PTR_ERR(fn); - up(&f->sem); - SetPageError(pg); - break; - } - ret = jffs2_add_full_dnode_to_inode(c, f, fn); - if (f->metadata) { - jffs2_mark_node_obsolete(c, f->metadata->raw); - jffs2_free_full_dnode(f->metadata); - f->metadata = NULL; - } - up(&f->sem); - if (ret) { - /* Eep */ - D1(printk(KERN_DEBUG "Eep. add_full_dnode_to_inode() failed in commit_write, returned %d\n", ret)); - jffs2_mark_node_obsolete(c, fn->raw); - jffs2_free_full_dnode(fn); - SetPageError(pg); - break; - } - inode->i_size = ri->isize; - inode->i_blocks = (inode->i_size + 511) >> 9; - inode->i_ctime = inode->i_mtime = ri->ctime; - if (!datalen) { - printk(KERN_WARNING "Eep. We didn't actually write any bloody data\n"); - ret = -EIO; - SetPageError(pg); - break; + if (writtenlen) { + if (inode->i_size < (pg->index << PAGE_CACHE_SHIFT) + start + writtenlen) { + inode->i_size = (pg->index << PAGE_CACHE_SHIFT) + start + writtenlen; + inode->i_blocks = (inode->i_size + 511) >> 9; + + inode->i_ctime = inode->i_mtime = ITIME(je32_to_cpu(ri->ctime)); } - D1(printk(KERN_DEBUG "increasing writtenlen by %d\n", datalen)); - writtenlen += datalen; - file_ofs += datalen; - writelen -= datalen; } jffs2_free_raw_inode(ri); - if (writtenlen < end) { + if (start+writtenlen < end) { /* generic_file_write has written more to the page cache than we've - actually written to the medium. Mark the page !Uptodate so that + actually written to the medium. Mark the page !Uptodate so that it gets reread */ D1(printk(KERN_DEBUG "jffs2_commit_write(): Not all bytes written. Marking page !uptodate\n")); SetPageError(pg); ClearPageUptodate(pg); } - if (writtenlen <= start) { - /* We didn't even get to the start of the affected part */ - ret = ret?ret:-ENOSPC; - D1(printk(KERN_DEBUG "jffs2_commit_write(): Only %x bytes written to page. start (%x) not reached, returning %d\n", writtenlen, start, ret)); - } - writtenlen = min(end-start, writtenlen-start); - D1(printk(KERN_DEBUG "jffs2_commit_write() returning %d. nrpages is %ld\n",writtenlen?writtenlen:ret, inode->i_mapping->nrpages)); - return writtenlen?writtenlen:ret; + D1(printk(KERN_DEBUG "jffs2_commit_write() returning %d\n",start+writtenlen==end?0:ret)); + return start+writtenlen==end?0:ret; } |