]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - fs/gfs2/bmap.c
Merge tag 'acpi-5.4-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
[linux.git] / fs / gfs2 / bmap.c
index 4f8b5fd6c81fdeafccff2ffbf4409ada329b7d00..f63df54a08c6c3eb3a4c75aa946936929ce203a3 100644 (file)
@@ -1065,54 +1065,38 @@ static int gfs2_iomap_begin_write(struct inode *inode, loff_t pos,
 {
        struct gfs2_inode *ip = GFS2_I(inode);
        struct gfs2_sbd *sdp = GFS2_SB(inode);
-       unsigned int data_blocks = 0, ind_blocks = 0, rblocks;
-       bool unstuff, alloc_required;
+       bool unstuff;
        int ret;
 
-       ret = gfs2_write_lock(inode);
-       if (ret)
-               return ret;
-
        unstuff = gfs2_is_stuffed(ip) &&
                  pos + length > gfs2_max_stuffed_size(ip);
 
-       ret = gfs2_iomap_get(inode, pos, length, flags, iomap, mp);
-       if (ret)
-               goto out_unlock;
-
-       alloc_required = unstuff || iomap->type == IOMAP_HOLE;
+       if (unstuff || iomap->type == IOMAP_HOLE) {
+               unsigned int data_blocks, ind_blocks;
+               struct gfs2_alloc_parms ap = {};
+               unsigned int rblocks;
+               struct gfs2_trans *tr;
 
-       if (alloc_required || gfs2_is_jdata(ip))
                gfs2_write_calc_reserv(ip, iomap->length, &data_blocks,
                                       &ind_blocks);
-
-       if (alloc_required) {
-               struct gfs2_alloc_parms ap = {
-                       .target = data_blocks + ind_blocks
-               };
-
+               ap.target = data_blocks + ind_blocks;
                ret = gfs2_quota_lock_check(ip, &ap);
                if (ret)
-                       goto out_unlock;
+                       return ret;
 
                ret = gfs2_inplace_reserve(ip, &ap);
                if (ret)
                        goto out_qunlock;
-       }
 
-       rblocks = RES_DINODE + ind_blocks;
-       if (gfs2_is_jdata(ip))
-               rblocks += data_blocks;
-       if (ind_blocks || data_blocks)
-               rblocks += RES_STATFS + RES_QUOTA;
-       if (inode == sdp->sd_rindex)
-               rblocks += 2 * RES_STATFS;
-       if (alloc_required)
+               rblocks = RES_DINODE + ind_blocks;
+               if (gfs2_is_jdata(ip))
+                       rblocks += data_blocks;
+               if (ind_blocks || data_blocks)
+                       rblocks += RES_STATFS + RES_QUOTA;
+               if (inode == sdp->sd_rindex)
+                       rblocks += 2 * RES_STATFS;
                rblocks += gfs2_rg_blocks(ip, data_blocks + ind_blocks);
 
-       if (unstuff || iomap->type == IOMAP_HOLE) {
-               struct gfs2_trans *tr;
-
                ret = gfs2_trans_begin(sdp, rblocks,
                                       iomap->length >> inode->i_blkbits);
                if (ret)
@@ -1153,16 +1137,17 @@ static int gfs2_iomap_begin_write(struct inode *inode, loff_t pos,
 out_trans_end:
        gfs2_trans_end(sdp);
 out_trans_fail:
-       if (alloc_required)
-               gfs2_inplace_release(ip);
+       gfs2_inplace_release(ip);
 out_qunlock:
-       if (alloc_required)
-               gfs2_quota_unlock(ip);
-out_unlock:
-       gfs2_write_unlock(inode);
+       gfs2_quota_unlock(ip);
        return ret;
 }
 
+static inline bool gfs2_iomap_need_write_lock(unsigned flags)
+{
+       return (flags & IOMAP_WRITE) && !(flags & IOMAP_DIRECT);
+}
+
 static int gfs2_iomap_begin(struct inode *inode, loff_t pos, loff_t length,
                            unsigned flags, struct iomap *iomap)
 {
@@ -1173,20 +1158,43 @@ static int gfs2_iomap_begin(struct inode *inode, loff_t pos, loff_t length,
        iomap->flags |= IOMAP_F_BUFFER_HEAD;
 
        trace_gfs2_iomap_start(ip, pos, length, flags);
-       if ((flags & IOMAP_WRITE) && !(flags & IOMAP_DIRECT)) {
-               ret = gfs2_iomap_begin_write(inode, pos, length, flags, iomap, &mp);
-       } else {
-               ret = gfs2_iomap_get(inode, pos, length, flags, iomap, &mp);
+       if (gfs2_iomap_need_write_lock(flags)) {
+               ret = gfs2_write_lock(inode);
+               if (ret)
+                       goto out;
+       }
 
-               /*
-                * Silently fall back to buffered I/O for stuffed files or if
-                * we've hot a hole (see gfs2_file_direct_write).
-                */
-               if ((flags & IOMAP_WRITE) && (flags & IOMAP_DIRECT) &&
-                   iomap->type != IOMAP_MAPPED)
-                       ret = -ENOTBLK;
+       ret = gfs2_iomap_get(inode, pos, length, flags, iomap, &mp);
+       if (ret)
+               goto out_unlock;
+
+       switch(flags & (IOMAP_WRITE | IOMAP_ZERO)) {
+       case IOMAP_WRITE:
+               if (flags & IOMAP_DIRECT) {
+                       /*
+                        * Silently fall back to buffered I/O for stuffed files
+                        * or if we've got a hole (see gfs2_file_direct_write).
+                        */
+                       if (iomap->type != IOMAP_MAPPED)
+                               ret = -ENOTBLK;
+                       goto out_unlock;
+               }
+               break;
+       case IOMAP_ZERO:
+               if (iomap->type == IOMAP_HOLE)
+                       goto out_unlock;
+               break;
+       default:
+               goto out_unlock;
        }
+
+       ret = gfs2_iomap_begin_write(inode, pos, length, flags, iomap, &mp);
+
+out_unlock:
+       if (ret && gfs2_iomap_need_write_lock(flags))
+               gfs2_write_unlock(inode);
        release_metapath(&mp);
+out:
        trace_gfs2_iomap_end(ip, iomap, ret);
        return ret;
 }
@@ -1197,8 +1205,18 @@ static int gfs2_iomap_end(struct inode *inode, loff_t pos, loff_t length,
        struct gfs2_inode *ip = GFS2_I(inode);
        struct gfs2_sbd *sdp = GFS2_SB(inode);
 
-       if ((flags & (IOMAP_WRITE | IOMAP_DIRECT)) != IOMAP_WRITE)
-               goto out;
+       switch (flags & (IOMAP_WRITE | IOMAP_ZERO)) {
+       case IOMAP_WRITE:
+               if (flags & IOMAP_DIRECT)
+                       return 0;
+               break;
+       case IOMAP_ZERO:
+                if (iomap->type == IOMAP_HOLE)
+                        return 0;
+                break;
+       default:
+                return 0;
+       }
 
        if (!gfs2_is_stuffed(ip))
                gfs2_ordered_add_inode(ip);
@@ -1231,8 +1249,8 @@ static int gfs2_iomap_end(struct inode *inode, loff_t pos, loff_t length,
        set_bit(GLF_DIRTY, &ip->i_gl->gl_flags);
 
 out_unlock:
-       gfs2_write_unlock(inode);
-out:
+       if (gfs2_iomap_need_write_lock(flags))
+               gfs2_write_unlock(inode);
        return 0;
 }
 
@@ -1330,76 +1348,10 @@ int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsi
        return ret;
 }
 
-/**
- * gfs2_block_zero_range - Deal with zeroing out data
- *
- * This is partly borrowed from ext3.
- */
 static int gfs2_block_zero_range(struct inode *inode, loff_t from,
                                 unsigned int length)
 {
-       struct address_space *mapping = inode->i_mapping;
-       struct gfs2_inode *ip = GFS2_I(inode);
-       unsigned long index = from >> PAGE_SHIFT;
-       unsigned offset = from & (PAGE_SIZE-1);
-       unsigned blocksize, iblock, pos;
-       struct buffer_head *bh;
-       struct page *page;
-       int err;
-
-       page = find_or_create_page(mapping, index, GFP_NOFS);
-       if (!page)
-               return 0;
-
-       blocksize = inode->i_sb->s_blocksize;
-       iblock = index << (PAGE_SHIFT - inode->i_sb->s_blocksize_bits);
-
-       if (!page_has_buffers(page))
-               create_empty_buffers(page, blocksize, 0);
-
-       /* Find the buffer that contains "offset" */
-       bh = page_buffers(page);
-       pos = blocksize;
-       while (offset >= pos) {
-               bh = bh->b_this_page;
-               iblock++;
-               pos += blocksize;
-       }
-
-       err = 0;
-
-       if (!buffer_mapped(bh)) {
-               gfs2_block_map(inode, iblock, bh, 0);
-               /* unmapped? It's a hole - nothing to do */
-               if (!buffer_mapped(bh))
-                       goto unlock;
-       }
-
-       /* Ok, it's mapped. Make sure it's up-to-date */
-       if (PageUptodate(page))
-               set_buffer_uptodate(bh);
-
-       if (!buffer_uptodate(bh)) {
-               err = -EIO;
-               ll_rw_block(REQ_OP_READ, 0, 1, &bh);
-               wait_on_buffer(bh);
-               /* Uhhuh. Read error. Complain and punt. */
-               if (!buffer_uptodate(bh))
-                       goto unlock;
-               err = 0;
-       }
-
-       if (gfs2_is_jdata(ip))
-               gfs2_trans_add_data(ip->i_gl, bh);
-       else
-               gfs2_ordered_add_inode(ip);
-
-       zero_user(page, offset, length);
-       mark_buffer_dirty(bh);
-unlock:
-       unlock_page(page);
-       put_page(page);
-       return err;
+       return iomap_zero_range(inode, from, length, NULL, &gfs2_iomap_ops);
 }
 
 #define GFS2_JTRUNC_REVOKES 8192
@@ -1680,6 +1632,7 @@ static int sweep_bh_for_rgrps(struct gfs2_inode *ip, struct gfs2_holder *rd_gh,
                        brelse(dibh);
                        up_write(&ip->i_rw_mutex);
                        gfs2_trans_end(sdp);
+                       buf_in_tr = false;
                }
                gfs2_glock_dq_uninit(rd_gh);
                cond_resched();
@@ -2187,7 +2140,7 @@ static int do_grow(struct inode *inode, u64 size)
        if (error)
                goto do_end_trans;
 
-       i_size_write(inode, size);
+       truncate_setsize(inode, size);
        ip->i_inode.i_mtime = ip->i_inode.i_ctime = current_time(&ip->i_inode);
        gfs2_trans_add_meta(ip->i_gl, dibh);
        gfs2_dinode_out(ip, dibh->b_data);