From patchwork Thu Mar 3 19:31:54 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bob Peterson X-Patchwork-Id: 8495731 Return-Path: X-Original-To: patchwork-linux-fsdevel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 81AC19F38C for ; Thu, 3 Mar 2016 19:32:07 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 876E02012E for ; Thu, 3 Mar 2016 19:32:06 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 72E3220121 for ; Thu, 3 Mar 2016 19:32:04 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755439AbcCCTcB (ORCPT ); Thu, 3 Mar 2016 14:32:01 -0500 Received: from mx1.redhat.com ([209.132.183.28]:49550 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753797AbcCCTb6 (ORCPT ); Thu, 3 Mar 2016 14:31:58 -0500 Received: from int-mx11.intmail.prod.int.phx2.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.24]) by mx1.redhat.com (Postfix) with ESMTPS id 917211837; Thu, 3 Mar 2016 19:31:58 +0000 (UTC) Received: from loki.redhat.com (ovpn-113-172.phx2.redhat.com [10.3.113.172]) by int-mx11.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id u23JVtmK007287; Thu, 3 Mar 2016 14:31:58 -0500 From: Bob Peterson To: Cc: Jan Kara , Al Viro , Dave Chinner Subject: [vfs PATCH v2 3/4] GFS2: Add function __gfs2_io_map Date: Thu, 3 Mar 2016 14:31:54 -0500 Message-Id: <1457033515-7521-4-git-send-email-rpeterso@redhat.com> In-Reply-To: <1457033515-7521-1-git-send-email-rpeterso@redhat.com> References: <1457033515-7521-1-git-send-email-rpeterso@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.24 Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This patch adds a generic io_map interface to GFS2 for block mapping. Signed-off-by: Bob Peterson --- fs/gfs2/bmap.c | 160 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ fs/gfs2/bmap.h | 2 + 2 files changed, 162 insertions(+) diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 61296ec..7979a54 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "gfs2.h" #include "incore.h" @@ -587,6 +588,165 @@ static int gfs2_bmap_alloc(struct inode *inode, const sector_t lblock, } /** + * hole_size - figure out the size of a hole + * @ip: The inode + * @lblock: The logical starting block number + * @mp: The metapath + * + * Returns: The hole size in bytes + * + */ +static u64 hole_size(struct inode *inode, sector_t lblock, struct metapath *mp) +{ + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_sbd *sdp = GFS2_SB(inode); + struct metapath mp_eof; + unsigned int end_of_metadata = ip->i_height - 1; + u64 factor = 1; + int hgt = end_of_metadata; + u64 holesz = 0, holestep; + const __be64 *first, *end, *ptr; + const struct buffer_head *bh; + u64 isize = i_size_read(inode); + int zeroptrs; + bool done = false; + + /* Get another metapath, to the very last byte */ + find_metapath(sdp, (isize - 1) >> inode->i_blkbits, &mp_eof, + ip->i_height); + for (hgt = end_of_metadata; hgt >= 0 && !done; hgt--) { + bh = mp->mp_bh[hgt]; + if (bh) { + zeroptrs = 0; + first = metapointer(hgt, mp); + end = (const __be64 *)(bh->b_data + bh->b_size); + + for (ptr = first; ptr < end; ptr++) { + if (*ptr) { + done = true; + break; + } else { + zeroptrs++; + } + } + } else { + zeroptrs = sdp->sd_inptrs; + } + holestep = min(factor * zeroptrs, + isize - (lblock + (zeroptrs * holesz))); + holesz += holestep; + if (lblock + holesz >= isize) + return holesz << inode->i_blkbits; + + factor *= sdp->sd_inptrs; + if (hgt && (mp->mp_list[hgt - 1] < mp_eof.mp_list[hgt - 1])) + (mp->mp_list[hgt - 1])++; + } + return holesz << inode->i_blkbits; +} + +/** + * __gfs2_io_map - Map blocks from an inode to disk blocks + * @mapping: The address space + * @pos: Starting position in bytes + * @length: Length to map, in bytes + * @iomap: The iomap structure + * @flags: The iomap RW flags + * + * Returns: errno + */ + +int gfs2_iomap(struct address_space *mapping, loff_t pos, ssize_t length, + struct iomap *iomap, unsigned int flags) +{ + struct inode *inode = mapping->host; + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); + unsigned int bsize = sdp->sd_sb.sb_bsize; + const u64 *arr = sdp->sd_heightsize; + __be64 *ptr; + sector_t lblock = pos >> sdp->sd_sb.sb_bsize_shift; + u64 size; + struct metapath mp; + int ret, eob; + unsigned int len; + struct buffer_head *bh; + u8 height; + loff_t isize = i_size_read(inode); + + if (length == 0) + return -EINVAL; + + iomap->offset = pos; + iomap->blkno = 0; + iomap->type = IOMAP_HOLE; + iomap->length = length; + + if (pos >= isize) + return 0; + + memset(mp.mp_bh, 0, sizeof(mp.mp_bh)); + bmap_lock(ip, (flags & IOMAP_MODE_RDWR)); + if (gfs2_is_dir(ip)) { + bsize = sdp->sd_jbsize; + arr = sdp->sd_jheightsize; + } + + ret = gfs2_meta_inode_buffer(ip, &mp.mp_bh[0]); + if (ret) + goto out_release; + + height = ip->i_height; + size = (lblock + 1) * bsize; + while (size > arr[height]) + height++; + find_metapath(sdp, lblock, &mp, height); + ret = 1; + if (height > ip->i_height || gfs2_is_stuffed(ip)) + goto do_alloc; + ret = lookup_metapath(ip, &mp); + if (ret < 0) + goto out_release; + + if (ret != ip->i_height) { + if (flags & IOMAP_MODE_RDWR) + goto do_alloc; + iomap->length = hole_size(inode, lblock, &mp); + goto out_meta_hole; + } + + ptr = metapointer(ip->i_height - 1, &mp); + iomap->blkno = be64_to_cpu(*ptr); + if (*ptr) { + iomap->type = IOMAP_MAPPED; + } else { + if (flags & IOMAP_MODE_RDWR) + goto do_alloc; + iomap->type = IOMAP_HOLE; + } + bh = mp.mp_bh[ip->i_height - 1]; + len = gfs2_extent_length(bh->b_data, bh->b_size, ptr, + length >> inode->i_blkbits, &eob); + iomap->length = len << sdp->sd_sb.sb_bsize_shift; + /* If we go past eof, round up to the nearest block */ + if (iomap->offset + iomap->length >= isize) + iomap->length = (((isize - iomap->offset) + (bsize - 1)) & + ~(bsize - 1)); + +out_meta_hole: + ret = 0; +out_release: + release_metapath(&mp); + bmap_unlock(ip, (flags & IOMAP_MODE_RDWR)); + return ret; + +do_alloc: + /* Todo: Code an allocation path */ + ret = -EINVAL; + goto out_release; +} + +/** * gfs2_block_map - Map a block from an inode to a disk block * @inode: The inode * @lblock: The logical block number diff --git a/fs/gfs2/bmap.h b/fs/gfs2/bmap.h index 81ded5e..873f23c 100644 --- a/fs/gfs2/bmap.h +++ b/fs/gfs2/bmap.h @@ -47,6 +47,8 @@ static inline void gfs2_write_calc_reserv(const struct gfs2_inode *ip, extern int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page); extern int gfs2_block_map(struct inode *inode, sector_t lblock, struct buffer_head *bh, int create); +extern int gfs2_iomap(struct address_space *mapping, loff_t pos, + ssize_t length, struct iomap *iomap, unsigned int flags); extern int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsigned *extlen); extern int gfs2_setattr_size(struct inode *inode, u64 size);