]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - fs/xfs/xfs_bmap.c
[PATCH] knfsd: nfs4: hold filp while reading or writing
[karo-tx-linux.git] / fs / xfs / xfs_bmap.c
index de316241866305c988f186730948f0fe2753e5b7..6f5d283888aa2b9ab243d93f8df1fe25c4e8cc34 100644 (file)
@@ -301,6 +301,19 @@ xfs_bmap_search_extents(
        xfs_bmbt_irec_t *gotp,          /* out: extent entry found */
        xfs_bmbt_irec_t *prevp);        /* out: previous extent entry found */
 
+/*
+ * Check the last inode extent to determine whether this allocation will result
+ * in blocks being allocated at the end of the file. When we allocate new data
+ * blocks at the end of the file which do not start at the previous data block,
+ * we will try to align the new blocks at stripe unit boundaries.
+ */
+STATIC int                             /* error */
+xfs_bmap_isaeof(
+       xfs_inode_t     *ip,            /* incore inode pointer */
+       xfs_fileoff_t   off,            /* file offset in fsblocks */
+       int             whichfork,      /* data or attribute fork */
+       char            *aeof);         /* return value */
+
 #ifdef XFS_BMAP_TRACE
 /*
  * Add a bmap trace buffer entry.  Base routine for the others.
@@ -4532,18 +4545,17 @@ xfs_bmapi(
        xfs_extlen_t    alen;           /* allocated extent length */
        xfs_fileoff_t   aoff;           /* allocated file offset */
        xfs_bmalloca_t  bma;            /* args for xfs_bmap_alloc */
-       char            contig;         /* allocation must be one extent */
        xfs_btree_cur_t *cur;           /* bmap btree cursor */
-       char            delay;          /* this request is for delayed alloc */
        xfs_fileoff_t   end;            /* end of mapped file region */
        int             eof;            /* we've hit the end of extent list */
+       char            contig;         /* allocation must be one extent */
+       char            delay;          /* this request is for delayed alloc */
+       char            exact;          /* don't do all of wasdelayed extent */
        xfs_bmbt_rec_t  *ep;            /* extent list entry pointer */
        int             error;          /* error return */
-       char            exact;          /* don't do all of wasdelayed extent */
        xfs_bmbt_irec_t got;            /* current extent list record */
        xfs_ifork_t     *ifp;           /* inode fork pointer */
        xfs_extlen_t    indlen;         /* indirect blocks length */
-       char            inhole;         /* current location is hole in file */
        xfs_extnum_t    lastx;          /* last useful extent number */
        int             logflags;       /* flags for transaction logging */
        xfs_extlen_t    minleft;        /* min blocks left after allocation */
@@ -4554,13 +4566,15 @@ xfs_bmapi(
        xfs_extnum_t    nextents;       /* number of extents in file */
        xfs_fileoff_t   obno;           /* old block number (offset) */
        xfs_bmbt_irec_t prev;           /* previous extent list record */
-       char            stateless;      /* ignore state flag set */
        int             tmp_logflags;   /* temp flags holder */
+       int             whichfork;      /* data or attr fork */
+       char            inhole;         /* current location is hole in file */
+       char            stateless;      /* ignore state flag set */
        char            trim;           /* output trimmed to match range */
        char            userdata;       /* allocating non-metadata */
        char            wasdelay;       /* old extent was delayed */
-       int             whichfork;      /* data or attr fork */
        char            wr;             /* this is a write request */
+       char            rt;             /* this is a realtime file */
        char            rsvd;           /* OK to allocate reserved blocks */
 #ifdef DEBUG
        xfs_fileoff_t   orig_bno;       /* original block number value */
@@ -4590,6 +4604,7 @@ xfs_bmapi(
        }
        if (XFS_FORCED_SHUTDOWN(mp))
                return XFS_ERROR(EIO);
+       rt = XFS_IS_REALTIME_INODE(ip);
        ifp = XFS_IFORK_PTR(ip, whichfork);
        ASSERT(ifp->if_ext_max ==
               XFS_IFORK_SIZE(ip, whichfork) / (uint)sizeof(xfs_bmbt_rec_t));
@@ -4694,9 +4709,16 @@ xfs_bmapi(
                        }
                        minlen = contig ? alen : 1;
                        if (delay) {
-                               indlen = (xfs_extlen_t)
-                                       xfs_bmap_worst_indlen(ip, alen);
-                               ASSERT(indlen > 0);
+                               xfs_extlen_t    extsz = 0;
+
+                               /* Figure out the extent size, adjust alen */
+                               if (rt) {
+                                       if (!(extsz = ip->i_d.di_extsize))
+                                               extsz = mp->m_sb.sb_rextsize;
+                                       alen = roundup(alen, extsz);
+                                       extsz = alen / mp->m_sb.sb_rextsize;
+                               }
+
                                /*
                                 * Make a transaction-less quota reservation for
                                 * delayed allocation blocks. This number gets
@@ -4704,8 +4726,10 @@ xfs_bmapi(
                                 * We return EDQUOT if we haven't allocated
                                 * blks already inside this loop;
                                 */
-                               if (XFS_TRANS_RESERVE_BLKQUOTA(
-                                               mp, NULL, ip, (long)alen)) {
+                               if (XFS_TRANS_RESERVE_QUOTA_NBLKS(
+                                               mp, NULL, ip, (long)alen, 0,
+                                               rt ? XFS_QMOPT_RES_RTBLKS :
+                                                    XFS_QMOPT_RES_REGBLKS)) {
                                        if (n == 0) {
                                                *nmap = 0;
                                                ASSERT(cur == NULL);
@@ -4718,40 +4742,34 @@ xfs_bmapi(
                                 * Split changing sb for alen and indlen since
                                 * they could be coming from different places.
                                 */
-                               if (ip->i_d.di_flags & XFS_DIFLAG_REALTIME) {
-                                       xfs_extlen_t    extsz;
-                                       xfs_extlen_t    ralen;
-                                       if (!(extsz = ip->i_d.di_extsize))
-                                               extsz = mp->m_sb.sb_rextsize;
-                                       ralen = roundup(alen, extsz);
-                                       ralen = ralen / mp->m_sb.sb_rextsize;
-                                       if (xfs_mod_incore_sb(mp,
-                                               XFS_SBS_FREXTENTS,
-                                               -(ralen), rsvd)) {
-                                               if (XFS_IS_QUOTA_ON(ip->i_mount))
-                                                       XFS_TRANS_UNRESERVE_BLKQUOTA(
-                                                               mp, NULL, ip,
-                                                               (long)alen);
-                                               break;
-                                       }
-                               } else {
-                                       if (xfs_mod_incore_sb(mp,
-                                                             XFS_SBS_FDBLOCKS,
-                                                             -(alen), rsvd)) {
-                                               if (XFS_IS_QUOTA_ON(ip->i_mount))
-                                                       XFS_TRANS_UNRESERVE_BLKQUOTA(
-                                                               mp, NULL, ip,
-                                                               (long)alen);
-                                               break;
-                                       }
-                               }
+                               indlen = (xfs_extlen_t)
+                                       xfs_bmap_worst_indlen(ip, alen);
+                               ASSERT(indlen > 0);
 
-                               if (xfs_mod_incore_sb(mp, XFS_SBS_FDBLOCKS,
-                                               -(indlen), rsvd)) {
-                                       XFS_TRANS_UNRESERVE_BLKQUOTA(
-                                               mp, NULL, ip, (long)alen);
+                               if (rt)
+                                       error = xfs_mod_incore_sb(mp,
+                                                       XFS_SBS_FREXTENTS,
+                                                       -(extsz), rsvd);
+                               else
+                                       error = xfs_mod_incore_sb(mp,
+                                                       XFS_SBS_FDBLOCKS,
+                                                       -(alen), rsvd);
+                               if (!error)
+                                       error = xfs_mod_incore_sb(mp,
+                                                       XFS_SBS_FDBLOCKS,
+                                                       -(indlen), rsvd);
+
+                               if (error) {
+                                       if (XFS_IS_QUOTA_ON(ip->i_mount))
+                                               /* unreserve the blocks now */
+                                               XFS_TRANS_UNRESERVE_QUOTA_NBLKS(
+                                                       mp, NULL, ip,
+                                                       (long)alen, 0, rt ?
+                                                       XFS_QMOPT_RES_RTBLKS :
+                                                       XFS_QMOPT_RES_REGBLKS);
                                        break;
                                }
+
                                ip->i_delayed_blks += alen;
                                abno = NULLSTARTBLOCK(indlen);
                        } else {
@@ -5376,13 +5394,24 @@ xfs_bunmapi(
                }
                if (wasdel) {
                        ASSERT(STARTBLOCKVAL(del.br_startblock) > 0);
-                       xfs_mod_incore_sb(mp, XFS_SBS_FDBLOCKS,
-                               (int)del.br_blockcount, rsvd);
-                       /* Unreserve our quota space */
-                       XFS_TRANS_RESERVE_QUOTA_NBLKS(
-                               mp, NULL, ip, -((long)del.br_blockcount), 0,
-                               isrt ?  XFS_QMOPT_RES_RTBLKS :
+                       /* Update realtim/data freespace, unreserve quota */
+                       if (isrt) {
+                               xfs_filblks_t rtexts;
+
+                               rtexts = XFS_FSB_TO_B(mp, del.br_blockcount);
+                               do_div(rtexts, mp->m_sb.sb_rextsize);
+                               xfs_mod_incore_sb(mp, XFS_SBS_FREXTENTS,
+                                               (int)rtexts, rsvd);
+                               XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, NULL, ip,
+                                       -((long)del.br_blockcount), 0,
+                                       XFS_QMOPT_RES_RTBLKS);
+                       } else {
+                               xfs_mod_incore_sb(mp, XFS_SBS_FDBLOCKS,
+                                               (int)del.br_blockcount, rsvd);
+                               XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, NULL, ip,
+                                       -((long)del.br_blockcount), 0,
                                        XFS_QMOPT_RES_REGBLKS);
+                       }
                        ip->i_delayed_blks -= del.br_blockcount;
                        if (cur)
                                cur->bc_private.b.flags |=
@@ -5714,7 +5743,7 @@ unlock_and_return:
  * blocks at the end of the file which do not start at the previous data block,
  * we will try to align the new blocks at stripe unit boundaries.
  */
-int                                    /* error */
+STATIC int                             /* error */
 xfs_bmap_isaeof(
        xfs_inode_t     *ip,            /* incore inode pointer */
        xfs_fileoff_t   off,            /* file offset in fsblocks */