Here's the relevant part of the diff for mm/file:
--- linux-source-2.6.22-2.6.22.orig/mm/filemap.c
+++ linux-source-2.6.22-2.6.22/mm/filemap.c
@@ -2146,22 +2146,9 @@
}
status = a_ops->prepare_write(file, page, offset, offset+bytes);
- if (unlikely(status)) {
- loff_t isize = i_size_read(inode);
+ if (unlikely(status))
+ goto fs_write_aop_error;
- if (status != AOP_TRUNCATED_PAGE)
- unlock_page(page);
- page_cache_release(page);
- if (status == AOP_TRUNCATED_PAGE)
- continue;
- /*
- * prepare_write() may have instantiated a few blocks
- * outside i_size. Trim these off again.
- */
- if (pos + bytes > isize)
- vmtruncate(inode, isize);
- break;
- }
if (likely(nr_segs == 1)) copied = filemap_copy_from_user(page, offset, buf, bytes);
@@ -2170,41 +2157,54 @@ cur_iov, iov_base, bytes); flush_dcache_page(page); status = a_ops->commit_write(file, page, offset, offset+bytes);
- if (status == AOP_TRUNCATED_PAGE) {
- page_cache_release(page);
- continue;
+ if (unlikely(status < 0 || status == AOP_TRUNCATED_PAGE))
+ goto fs_write_aop_error;
+ if (unlikely(copied != bytes)) {
+ status = -EFAULT;
+ goto fs_write_aop_error;
}
zero_length_segment:
- if (likely(copied >= 0)) {
- if (!status)
- status = copied;
-
- if (status >= 0) {
- written += status;
- count -= status;
- pos += status;
- buf += status;
- if (unlikely(nr_segs > 1)) {
- filemap_set_next_iovec(&cur_iov,
- &iov_base, status);
- if (count)
- buf = cur_iov->iov_base +
- iov_base;
- } else {
- iov_base += status;
- }
+ if (unlikely(status > 0)) /* filesystem did partial write */
+ copied = status;
+
+ if (likely(copied > 0)) {
+ written += copied;
+ count -= copied;
+ pos += copied;
+ buf += copied;
+ if (unlikely(nr_segs > 1)) {
+ filemap_set_next_iovec(&cur_iov,
+ &iov_base, copied);
+ if (count)
+ buf = cur_iov->iov_base + iov_base;
+ } else {
+ iov_base += copied; }
}
- if (unlikely(copied != bytes))
- if (status >= 0)
- status = -EFAULT; unlock_page(page); mark_page_accessed(page); page_cache_release(page);
- if (status < 0)
- break; balance_dirty_pages_ratelimited(mapping); cond_resched();
+ continue;
+
+fs_write_aop_error:
+ if (status != AOP_TRUNCATED_PAGE)
+ unlock_page(page);
+ page_cache_release(page);
+
+ /*
+ * prepare_write() may have instantiated a few blocks
+ * outside i_size. Trim these off again. Don't need
+ * i_size_read because we hold i_mutex.
+ */
+ if (pos + bytes > inode->i_size)
+ vmtruncate(inode, inode->i_size);
+ if (status == AOP_TRUNCATED_PAGE)
+ continue;
+ else
+ break;
+
} while (count);
*ppos = pos;
I think bug #249340 may be related to this one.
I've just run the same version of localedef on 2.6.22-14-generic, where it runs fine, and on 2.6.22-15-generic, where it hangs.
Here's the output of "strace localedef" immediately before it hung:
1218150691.384821 creat(" /usr/lib/ locale/ en_NZ.utf8/ LC_CTYPE" , 0666) = 3 x11\x03\ x20\x58\ x00\x00\ x00", 8}, {"\x68\ x01\x00\ x00\x68\ x04\x00\ x00\x68\ x0a\x00\ x00\x68\ x0a"... , 352}, {"\x00\ x00\x00\ x00\x00\ x00\x00\ x00\x00\ x00\x00\ x00\x00\ x00"... , 768}, {"\x80\ x00\x00\ x00\x81\ x00\x00\ x00\x82\ x00\x00\ x00\x83\ x00"... , 1536}, {NULL, 0}, {"\x80\ x00\x00\ x00\x81\ x00\x00\ x00\x82\ x00\x00\ x00\x83\ x00"... , 1536}, {NULL, 0}, {"\x00\ x00\x02\ x00\x00\ x00\x02\ x00\x00\ x00\x02\ x00\x00\ x00"... , 1024}, {NULL, 0}, {NULL, 0}, {NULL, 0}, {NULL, 0}, {"\x75\ x70\x70\ x65\x72\ x00", 6}, {"\x6c\ x6f\x77\ x65\x72\ x00", 6}, {"\x61\ x6c\x70\ x68\x61\ x00", 6}, {"\x64\ x69\x67\ x69\x74\ x00", 6}, {"\x78\ x64\x69\ x67\x69\ x74\x00" , 7}, {"\x73\ x70\x61\ x63\x65\ x00", 6}, {"\x70\ x72\x69\ x6e\x74\ x00", 6}, {"\x67\ x72\x61\ x70\x68\ x00", 6}, {"\x62\ x6c\x61\ x6e\x6b\ x00", 6}, {"\x63\ x6e\x74\ x72\x6c\ x00", 6}, {"\x70\ x75\x6e\ x63\x74\ x00", 6}, {"\x61\ x6c\x6e\ x75\x6d\ x00", 6}, {"\x63\ x6f\x6d\ x62\x69\ x6e\x69\ x6e\x67\ x00", 10}, {"\x63\ x6f\x6d\ x62\x69\ x6e\x69\ x6e\x67\ x5f\x6c\ x65\x76\ x65"... , 17}, {"\x00\ x00\x00\ x00", 4}, {"\x74\ x6f\x75\ x70\x70\ x65\x72\ x00", 8}, {"\x74\ x6f\x6c\ x6f\x77\ x65\x72\ x00", 8}, {"\x74\ x6f\x74\ x69\x74\ x6c\x65\ x00", 8}, {"\x00\ x00\x00\ x00", 4}, {"\x10\ x00\x00\ x00\x11\ x00\x00\ x00\x07\ x00\x00\ x00\xff\ x01"... , 25560}, ...], 125
1218150691.403450 writev(3, [{"\x15\
(Note the "{NULL, 0}" elements.)
Here's the relevant part of the diff for mm/file: 2.6.22- 2.6.22. orig/mm/ filemap. c 2.6.22- 2.6.22/ mm/filemap. c
--- linux-source-
+++ linux-source-
@@ -2146,22 +2146,9 @@
}
- if (unlikely(status)) {
- loff_t isize = i_size_read(inode);
+ if (unlikely(status))
+ goto fs_write_aop_error;
- if (status != AOP_TRUNCATED_PAGE) release( page);
copied = filemap_ copy_from_ user(page, offset,
buf, bytes);
cur_ iov, iov_base, bytes);
flush_ dcache_ page(page) ;
status = a_ops-> commit_ write(file, page, offset, offset+bytes); release( page); PAGE)) segment: set_next_ iovec(& cur_iov, set_next_ iovec(& cur_iov,
}
unlock_ page(page) ;
mark_ page_accessed( page);
page_ cache_release( page);
balance_ dirty_pages_ ratelimited( mapping) ;
cond_ resched( ); aop_error: release( page);
- unlock_page(page);
- page_cache_
- if (status == AOP_TRUNCATED_PAGE)
- continue;
- /*
- * prepare_write() may have instantiated a few blocks
- * outside i_size. Trim these off again.
- */
- if (pos + bytes > isize)
- vmtruncate(inode, isize);
- break;
- }
if (likely(nr_segs == 1))
@@ -2170,41 +2157,54 @@
- if (status == AOP_TRUNCATED_PAGE) {
- page_cache_
- continue;
+ if (unlikely(status < 0 || status == AOP_TRUNCATED_
+ goto fs_write_aop_error;
+ if (unlikely(copied != bytes)) {
+ status = -EFAULT;
+ goto fs_write_aop_error;
}
zero_length_
- if (likely(copied >= 0)) {
- if (!status)
- status = copied;
-
- if (status >= 0) {
- written += status;
- count -= status;
- pos += status;
- buf += status;
- if (unlikely(nr_segs > 1)) {
- filemap_
- &iov_base, status);
- if (count)
- buf = cur_iov->iov_base +
- iov_base;
- } else {
- iov_base += status;
- }
+ if (unlikely(status > 0)) /* filesystem did partial write */
+ copied = status;
+
+ if (likely(copied > 0)) {
+ written += copied;
+ count -= copied;
+ pos += copied;
+ buf += copied;
+ if (unlikely(nr_segs > 1)) {
+ filemap_
+ &iov_base, copied);
+ if (count)
+ buf = cur_iov->iov_base + iov_base;
+ } else {
+ iov_base += copied;
}
- if (unlikely(copied != bytes))
- if (status >= 0)
- status = -EFAULT;
- if (status < 0)
- break;
+ continue;
+
+fs_write_
+ if (status != AOP_TRUNCATED_PAGE)
+ unlock_page(page);
+ page_cache_
+
+ /*
+ * prepare_write() may have instantiated a few blocks
+ * outside i_size. Trim these off again. Don't need
+ * i_size_read because we hold i_mutex.
+ */
+ if (pos + bytes > inode->i_size)
+ vmtruncate(inode, inode->i_size);
+ if (status == AOP_TRUNCATED_PAGE)
+ continue;
+ else
+ break;
+
} while (count);
*ppos = pos;
@@ -2269,7 +2269,7 @@
goto out;
if (count == 0)
- err = remove_ suid(file- >f_path. dentry) ; suid(&file- >f_path) ;
goto out;
+ err = remove_
if (err)