--- original/fs/reiser4/plugin/item/extent_file_ops.c 2007-04-06 08:00:28.000000000 +0400 +++ current/fs/reiser4/plugin/item/extent_file_ops.c 2007-04-06 09:23:45.000000000 +0400 @@ -941,15 +941,15 @@ * reiser4_write_extent - write method of extent item plugin * @file: file to write to * @buf: address of user-space buffer - * @write_amount: number of bytes to write - * @off: position in file to write to + * @count: number of bytes to write + * @pos: position in file to write to * */ ssize_t reiser4_write_extent(struct file *file, const char __user *buf, size_t count, loff_t *pos) { int have_to_update_extent; - int nr_pages; + int nr_pages, nr_dirty; struct page *page; jnode *jnodes[WRITE_GRANULARITY + 1]; struct inode *inode; @@ -958,7 +958,7 @@ int i; int to_page, page_off; size_t left, written; - int result; + int result = 0; inode = file->f_dentry->d_inode; if (write_extent_reserve_space(inode)) @@ -972,10 +972,12 @@ BUG_ON(get_current_context()->trans->atom != NULL); + left = count; index = *pos >> PAGE_CACHE_SHIFT; /* calculate number of pages which are to be written */ end = ((*pos + count - 1) >> PAGE_CACHE_SHIFT); nr_pages = end - index + 1; + nr_dirty = 0; assert("", nr_pages <= WRITE_GRANULARITY + 1); /* get pages and jnodes */ @@ -983,22 +985,18 @@ page = find_or_create_page(inode->i_mapping, index + i, reiser4_ctx_gfp_mask_get()); if (page == NULL) { - while(i --) { - unlock_page(jnode_page(jnodes[i])); - page_cache_release(jnode_page(jnodes[i])); - } - return RETERR(-ENOMEM); + nr_pages = i; + result = RETERR(-ENOMEM); + goto out; } jnodes[i] = jnode_of_page(page); if (IS_ERR(jnodes[i])) { unlock_page(page); page_cache_release(page); - while (i --) { - jput(jnodes[i]); - page_cache_release(jnode_page(jnodes[i])); - } - return RETERR(-ENOMEM); + nr_pages = i; + result = RETERR(-ENOMEM); + goto out; } /* prevent jnode and page from disconnecting */ JF_SET(jnodes[i], JNODE_WRITE_PREPARED); @@ -1009,7 +1007,6 @@ have_to_update_extent = 0; - left = count; page_off = (*pos & (PAGE_CACHE_SIZE - 1)); for (i = 0; i < nr_pages; i ++) { to_page = PAGE_CACHE_SIZE - page_off; @@ -1052,12 +1049,19 @@ } written = filemap_copy_from_user(page, page_off, buf, to_page); + if (unlikely(written != to_page)) { + unlock_page(page); + result = RETERR(-EFAULT); + break; + } + flush_dcache_page(page); reiser4_set_page_dirty_internal(page); unlock_page(page); + nr_dirty++; + mark_page_accessed(page); SetPageUptodate(page); - page_cache_release(page); if (jnodes[i]->blocknr == 0) have_to_update_extent ++; @@ -1069,25 +1073,29 @@ } if (have_to_update_extent) { - update_extents(file, jnodes, nr_pages, *pos); + update_extents(file, jnodes, nr_dirty, *pos); } else { - for (i = 0; i < nr_pages; i ++) { + for (i = 0; i < nr_dirty; i ++) { + int ret; spin_lock_jnode(jnodes[i]); - result = reiser4_try_capture(jnodes[i], + ret = reiser4_try_capture(jnodes[i], ZNODE_WRITE_LOCK, 0); - BUG_ON(result != 0); + BUG_ON(ret != 0); jnode_make_dirty_locked(jnodes[i]); spin_unlock_jnode(jnodes[i]); } } - +out: for (i = 0; i < nr_pages; i ++) { + page_cache_release(jnode_page(jnodes[i])); JF_CLR(jnodes[i], JNODE_WRITE_PREPARED); jput(jnodes[i]); } - /* the only error handled so far is EFAULT on copy_from_user */ - return (count - left) ? (count - left) : -EFAULT; + /* the only errors handled so far is ENOMEM and + EFAULT on copy_from_user */ + + return (count - left) ? (count - left) : result; } static inline void zero_page(struct page *page)