Comment 15 for bug 231746

Revision history for this message
Martin Kealey (from-launchpad-kurahaupo) wrote :

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
1218150691.403450 writev(3, [{"\x15\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

(Note the "{NULL, 0}" elements.)

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;

@@ -2269,7 +2269,7 @@
        if (count == 0)
                goto out;

- err = remove_suid(file->f_path.dentry);
+ err = remove_suid(&file->f_path);
        if (err)
                goto out;