xfs
[Top] [All Lists]

[PATCH] XFS: Let the broken fiemap work in query mode.

To: linux-kernel@xxxxxxxxxxxxxxx
Subject: [PATCH] XFS: Let the broken fiemap work in query mode.
From: Tao Ma <tao.ma@xxxxxxxxxx>
Date: Tue, 27 Apr 2010 14:17:45 +0800
Cc: Tao Ma <tao.ma@xxxxxxxxxx>, xfs@xxxxxxxxxxx, Eric Sandeen <sandeen@xxxxxxxxxx>, Christoph Hellwig <hch@xxxxxx>, Alex Elder <aelder@xxxxxxx>
According to Documentation/filesystems/fiemap.txt, If fm_extent_count
is zero, then the fm_extents[] array is ignored (no extents will be
returned), and the fm_mapped_extents count will hold the number of
extents needed.

But as the commit 97db39a1f6f69e906e98118392400de5217aa33a has changed
bmv_count to the caller's input buffer, this number query function can't
work any more. As this commit is written to change bmv_count from
MAXEXTNUM because of ENOMEM, we can't find a really suitable number to
set bmv_count now in xfs_vn_fiemap. Since we really have no idea of how
much extents the file has, a big number may cause ENOMEM, while a small
one will mask the real extent no.

So this patch try to resolve this problem by adding a temporary getbmapx
in xfs_getbmap. If the caller didn't give bmv_count, we don't allocate
the "out" either. Instead, every time we want to use 'out', use '&tmp'
instead.

I know this solution is a bit ugly, but I can't find a way to resolve
this issue while not changing the codes too much. So any good suggestion
is welcomed.

Cc: Eric Sandeen <sandeen@xxxxxxxxxx>
Cc: Christoph Hellwig <hch@xxxxxx>
Cc: Alex Elder <aelder@xxxxxxx>
Signed-off-by: Tao Ma <tao.ma@xxxxxxxxxx>
---
 fs/xfs/xfs_bmap.c |   47 +++++++++++++++++++++++++++++------------------
 1 files changed, 29 insertions(+), 18 deletions(-)

diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c
index 98251cd..654d9cf 100644
--- a/fs/xfs/xfs_bmap.c
+++ b/fs/xfs/xfs_bmap.c
@@ -5557,13 +5557,14 @@ xfs_getbmap(
        int                     nexleft;        /* # of user extents left */
        int                     subnex;         /* # of bmapi's can do */
        int                     nmap;           /* number of map entries */
-       struct getbmapx         *out;           /* output structure */
+       struct getbmapx         *out = NULL;    /* output structure */
        int                     whichfork;      /* data or attr fork */
        int                     prealloced;     /* this is a file with
                                                 * preallocated data space */
        int                     iflags;         /* interface flags */
        int                     bmapi_flags;    /* flags for xfs_bmapi */
        int                     cur_ext = 0;
+       struct getbmapx         tmp, *bmap;
 
        mp = ip->i_mount;
        iflags = bmv->bmv_iflags;
@@ -5635,16 +5636,20 @@ xfs_getbmap(
        }
 
        nex = bmv->bmv_count - 1;
-       if (nex <= 0)
+       if (nex < 0)
                return XFS_ERROR(EINVAL);
        bmvend = bmv->bmv_offset + bmv->bmv_length;
 
 
        if (bmv->bmv_count > ULONG_MAX / sizeof(struct getbmapx))
                return XFS_ERROR(ENOMEM);
-       out = kmem_zalloc(bmv->bmv_count * sizeof(struct getbmapx), KM_MAYFAIL);
-       if (!out)
-               return XFS_ERROR(ENOMEM);
+       if (nex) {
+               out = kmem_zalloc(bmv->bmv_count * sizeof(struct getbmapx),
+                                 KM_MAYFAIL);
+               if (!out)
+                       return XFS_ERROR(ENOMEM);
+       } else
+               nex = MAXEXTNUM;
 
        xfs_ilock(ip, XFS_IOLOCK_SHARED);
        if (whichfork == XFS_DATA_FORK && !(iflags & BMV_IF_DELALLOC)) {
@@ -5700,35 +5705,37 @@ xfs_getbmap(
                ASSERT(nmap <= subnex);
 
                for (i = 0; i < nmap && nexleft && bmv->bmv_length; i++) {
-                       out[cur_ext].bmv_oflags = 0;
+                       if (out)
+                               bmap = &out[cur_ext];
+                       else
+                               bmap = &tmp;
+                       bmap->bmv_oflags = 0;
                        if (map[i].br_state == XFS_EXT_UNWRITTEN)
-                               out[cur_ext].bmv_oflags |= BMV_OF_PREALLOC;
+                               bmap->bmv_oflags |= BMV_OF_PREALLOC;
                        else if (map[i].br_startblock == DELAYSTARTBLOCK)
-                               out[cur_ext].bmv_oflags |= BMV_OF_DELALLOC;
-                       out[cur_ext].bmv_offset =
+                               bmap->bmv_oflags |= BMV_OF_DELALLOC;
+                       bmap->bmv_offset =
                                XFS_FSB_TO_BB(mp, map[i].br_startoff);
-                       out[cur_ext].bmv_length =
+                       bmap->bmv_length =
                                XFS_FSB_TO_BB(mp, map[i].br_blockcount);
-                       out[cur_ext].bmv_unused1 = 0;
-                       out[cur_ext].bmv_unused2 = 0;
+                       bmap->bmv_unused1 = 0;
+                       bmap->bmv_unused2 = 0;
                        ASSERT(((iflags & BMV_IF_DELALLOC) != 0) ||
                              (map[i].br_startblock != DELAYSTARTBLOCK));
                         if (map[i].br_startblock == HOLESTARTBLOCK &&
                            whichfork == XFS_ATTR_FORK) {
                                /* came to the end of attribute fork */
-                               out[cur_ext].bmv_oflags |= BMV_OF_LAST;
+                               bmap->bmv_oflags |= BMV_OF_LAST;
                                goto out_free_map;
                        }
 
-                       if (!xfs_getbmapx_fix_eof_hole(ip, &out[cur_ext],
+                       if (!xfs_getbmapx_fix_eof_hole(ip, bmap,
                                        prealloced, bmvend,
                                        map[i].br_startblock))
                                goto out_free_map;
 
                        nexleft--;
-                       bmv->bmv_offset =
-                               out[cur_ext].bmv_offset +
-                               out[cur_ext].bmv_length;
+                       bmv->bmv_offset = bmap->bmv_offset + bmap->bmv_length;
                        bmv->bmv_length =
                                max_t(__int64_t, 0, bmvend - bmv->bmv_offset);
                        bmv->bmv_entries++;
@@ -5746,8 +5753,12 @@ xfs_getbmap(
        for (i = 0; i < cur_ext; i++) {
                int full = 0;   /* user array is full */
 
+               if (out)
+                       bmap = &out[i];
+               else
+                       bmap = &tmp;
                /* format results & advance arg */
-               error = formatter(&arg, &out[i], &full);
+               error = formatter(&arg, bmap, &full);
                if (error || full)
                        break;
        }
-- 
1.6.3.3.334.g916e1.dirty

<Prev in Thread] Current Thread [Next in Thread>