ext4: return non-zero st_blocks for inline data
[cascardo/linux.git] / fs / ext4 / inode.c
index c79fd7d..0757634 100644 (file)
@@ -2178,6 +2178,9 @@ static int mpage_map_one_extent(handle_t *handle, struct mpage_da_data *mpd)
  *
  * @handle - handle for journal operations
  * @mpd - extent to map
+ * @give_up_on_write - we set this to true iff there is a fatal error and there
+ *                     is no hope of writing the data. The caller should discard
+ *                     dirty pages to avoid infinite loops.
  *
  * The function maps extent starting at mpd->lblk of length mpd->len. If it is
  * delayed, blocks are allocated, if it is unwritten, we may need to convert
@@ -2295,6 +2298,7 @@ static int mpage_prepare_extent_to_map(struct mpage_da_data *mpd)
        struct address_space *mapping = mpd->inode->i_mapping;
        struct pagevec pvec;
        unsigned int nr_pages;
+       long left = mpd->wbc->nr_to_write;
        pgoff_t index = mpd->first_page;
        pgoff_t end = mpd->last_page;
        int tag;
@@ -2330,6 +2334,17 @@ static int mpage_prepare_extent_to_map(struct mpage_da_data *mpd)
                        if (page->index > end)
                                goto out;
 
+                       /*
+                        * Accumulated enough dirty pages? This doesn't apply
+                        * to WB_SYNC_ALL mode. For integrity sync we have to
+                        * keep going because someone may be concurrently
+                        * dirtying pages, and we might have synced a lot of
+                        * newly appeared dirty pages, but have not synced all
+                        * of the old dirty pages.
+                        */
+                       if (mpd->wbc->sync_mode == WB_SYNC_NONE && left <= 0)
+                               goto out;
+
                        /* If we can't merge this page, we are done. */
                        if (mpd->map.m_len > 0 && mpd->next_page != page->index)
                                goto out;
@@ -2364,19 +2379,7 @@ static int mpage_prepare_extent_to_map(struct mpage_da_data *mpd)
                        if (err <= 0)
                                goto out;
                        err = 0;
-
-                       /*
-                        * Accumulated enough dirty pages? This doesn't apply
-                        * to WB_SYNC_ALL mode. For integrity sync we have to
-                        * keep going because someone may be concurrently
-                        * dirtying pages, and we might have synced a lot of
-                        * newly appeared dirty pages, but have not synced all
-                        * of the old dirty pages.
-                        */
-                       if (mpd->wbc->sync_mode == WB_SYNC_NONE &&
-                           mpd->next_page - mpd->first_page >=
-                                                       mpd->wbc->nr_to_write)
-                               goto out;
+                       left--;
                }
                pagevec_release(&pvec);
                cond_resched();
@@ -2420,16 +2423,15 @@ static int ext4_writepages(struct address_space *mapping,
         * because that could violate lock ordering on umount
         */
        if (!mapping->nrpages || !mapping_tagged(mapping, PAGECACHE_TAG_DIRTY))
-               return 0;
+               goto out_writepages;
 
        if (ext4_should_journal_data(inode)) {
                struct blk_plug plug;
-               int ret;
 
                blk_start_plug(&plug);
                ret = write_cache_pages(mapping, wbc, __writepage, mapping);
                blk_finish_plug(&plug);
-               return ret;
+               goto out_writepages;
        }
 
        /*
@@ -2442,8 +2444,10 @@ static int ext4_writepages(struct address_space *mapping,
         * *never* be called, so if that ever happens, we would want
         * the stack trace.
         */
-       if (unlikely(sbi->s_mount_flags & EXT4_MF_FS_ABORTED))
-               return -EROFS;
+       if (unlikely(sbi->s_mount_flags & EXT4_MF_FS_ABORTED)) {
+               ret = -EROFS;
+               goto out_writepages;
+       }
 
        if (ext4_should_dioread_nolock(inode)) {
                /*
@@ -2563,7 +2567,7 @@ retry:
                        break;
        }
        blk_finish_plug(&plug);
-       if (!ret && !cycled) {
+       if (!ret && !cycled && wbc->nr_to_write > 0) {
                cycled = 1;
                mpd.last_page = writeback_index - 1;
                mpd.first_page = 0;
@@ -4587,7 +4591,6 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
 
        if (attr->ia_valid & ATTR_SIZE && attr->ia_size != inode->i_size) {
                handle_t *handle;
-               loff_t oldsize = inode->i_size;
 
                if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) {
                        struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
@@ -4650,7 +4653,7 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
                 * Truncate pagecache after we've waited for commit
                 * in data=journal mode to make pages freeable.
                 */
-               truncate_pagecache(inode, oldsize, inode->i_size);
+                       truncate_pagecache(inode, inode->i_size);
        }
        /*
         * We want to call ext4_truncate() even if attr->ia_size ==
@@ -4690,6 +4693,15 @@ int ext4_getattr(struct vfsmount *mnt, struct dentry *dentry,
        inode = dentry->d_inode;
        generic_fillattr(inode, stat);
 
+       /*
+        * If there is inline data in the inode, the inode will normally not
+        * have data blocks allocated (it may have an external xattr block).
+        * Report at least one sector for such files, so tools like tar, rsync,
+        * others doen't incorrectly think the file is completely sparse.
+        */
+       if (unlikely(ext4_has_inline_data(inode)))
+               stat->blocks += (stat->size + 511) >> 9;
+
        /*
         * We can't update i_blocks if the block allocation is delayed
         * otherwise in the case of system crash before the real block
@@ -4701,9 +4713,8 @@ int ext4_getattr(struct vfsmount *mnt, struct dentry *dentry,
         * blocks for this file.
         */
        delalloc_blocks = EXT4_C2B(EXT4_SB(inode->i_sb),
-                               EXT4_I(inode)->i_reserved_data_blocks);
-
-       stat->blocks += delalloc_blocks << (inode->i_sb->s_blocksize_bits-9);
+                                  EXT4_I(inode)->i_reserved_data_blocks);
+       stat->blocks += delalloc_blocks << (inode->i_sb->s_blocksize_bits - 9);
        return 0;
 }