Merge branch 'xfs-misc-fixes-for-3.18-1' into for-next
authorDave Chinner <david@fromorbit.com>
Tue, 9 Sep 2014 03:25:31 +0000 (13:25 +1000)
committerDave Chinner <david@fromorbit.com>
Tue, 9 Sep 2014 03:25:31 +0000 (13:25 +1000)
19 files changed:
fs/xfs/libxfs/xfs_alloc.c
fs/xfs/libxfs/xfs_dir2.c
fs/xfs/libxfs/xfs_dir2.h
fs/xfs/libxfs/xfs_ialloc.c
fs/xfs/libxfs/xfs_rtbitmap.c
fs/xfs/libxfs/xfs_sb.c
fs/xfs/xfs_buf.c
fs/xfs/xfs_file.c
fs/xfs/xfs_globals.c
fs/xfs/xfs_inode.c
fs/xfs/xfs_log_recover.c
fs/xfs/xfs_mru_cache.c
fs/xfs/xfs_rtalloc.c
fs/xfs/xfs_rtalloc.h
fs/xfs/xfs_super.c
fs/xfs/xfs_symlink.c
fs/xfs/xfs_sysctl.h
fs/xfs/xfs_sysfs.c
fs/xfs/xfs_sysfs.h

index 4bffffe038a1a8ac329b9dc19e5a885878270088..eff34218f405a0d7473ccfa35221b1f9969f168d 100644 (file)
@@ -2209,6 +2209,10 @@ xfs_agf_verify(
              be32_to_cpu(agf->agf_flcount) <= XFS_AGFL_SIZE(mp)))
                return false;
 
+       if (be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]) > XFS_BTREE_MAXLEVELS ||
+           be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]) > XFS_BTREE_MAXLEVELS)
+               return false;
+
        /*
         * during growfs operations, the perag is not fully initialised,
         * so we can't use it for any useful checking. growfs ensures we can't
index 6cef22152fd6440d46581bc141b4267b34119aea..7075aaf131f4c5511fbc726ea7c10017b5966e54 100644 (file)
@@ -237,7 +237,8 @@ xfs_dir_init(
 }
 
 /*
-  Enter a name in a directory.
+ * Enter a name in a directory, or check for available space.
+ * If inum is 0, only the available space test is performed.
  */
 int
 xfs_dir_createname(
@@ -254,10 +255,12 @@ xfs_dir_createname(
        int                     v;              /* type-checking value */
 
        ASSERT(S_ISDIR(dp->i_d.di_mode));
-       rval = xfs_dir_ino_validate(tp->t_mountp, inum);
-       if (rval)
-               return rval;
-       XFS_STATS_INC(xs_dir_create);
+       if (inum) {
+               rval = xfs_dir_ino_validate(tp->t_mountp, inum);
+               if (rval)
+                       return rval;
+               XFS_STATS_INC(xs_dir_create);
+       }
 
        args = kmem_zalloc(sizeof(*args), KM_SLEEP | KM_NOFS);
        if (!args)
@@ -276,6 +279,8 @@ xfs_dir_createname(
        args->whichfork = XFS_DATA_FORK;
        args->trans = tp;
        args->op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT;
+       if (!inum)
+               args->op_flags |= XFS_DA_OP_JUSTCHECK;
 
        if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) {
                rval = xfs_dir2_sf_addname(args);
@@ -535,62 +540,14 @@ out_free:
 
 /*
  * See if this entry can be added to the directory without allocating space.
- * First checks that the caller couldn't reserve enough space (resblks = 0).
  */
 int
 xfs_dir_canenter(
        xfs_trans_t     *tp,
        xfs_inode_t     *dp,
-       struct xfs_name *name,          /* name of entry to add */
-       uint            resblks)
+       struct xfs_name *name)          /* name of entry to add */
 {
-       struct xfs_da_args *args;
-       int             rval;
-       int             v;              /* type-checking value */
-
-       if (resblks)
-               return 0;
-
-       ASSERT(S_ISDIR(dp->i_d.di_mode));
-
-       args = kmem_zalloc(sizeof(*args), KM_SLEEP | KM_NOFS);
-       if (!args)
-               return -ENOMEM;
-
-       args->geo = dp->i_mount->m_dir_geo;
-       args->name = name->name;
-       args->namelen = name->len;
-       args->filetype = name->type;
-       args->hashval = dp->i_mount->m_dirnameops->hashname(name);
-       args->dp = dp;
-       args->whichfork = XFS_DATA_FORK;
-       args->trans = tp;
-       args->op_flags = XFS_DA_OP_JUSTCHECK | XFS_DA_OP_ADDNAME |
-                                                       XFS_DA_OP_OKNOENT;
-
-       if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) {
-               rval = xfs_dir2_sf_addname(args);
-               goto out_free;
-       }
-
-       rval = xfs_dir2_isblock(args, &v);
-       if (rval)
-               goto out_free;
-       if (v) {
-               rval = xfs_dir2_block_addname(args);
-               goto out_free;
-       }
-
-       rval = xfs_dir2_isleaf(args, &v);
-       if (rval)
-               goto out_free;
-       if (v)
-               rval = xfs_dir2_leaf_addname(args);
-       else
-               rval = xfs_dir2_node_addname(args);
-out_free:
-       kmem_free(args);
-       return rval;
+       return xfs_dir_createname(tp, dp, name, 0, NULL, NULL, 0);
 }
 
 /*
index c8e86b0b5e9954f64b271b7569a198fa5ab1425f..4dff261e6ed59ee8b9749c189554428115e8c4df 100644 (file)
@@ -136,7 +136,7 @@ extern int xfs_dir_replace(struct xfs_trans *tp, struct xfs_inode *dp,
                                xfs_fsblock_t *first,
                                struct xfs_bmap_free *flist, xfs_extlen_t tot);
 extern int xfs_dir_canenter(struct xfs_trans *tp, struct xfs_inode *dp,
-                               struct xfs_name *name, uint resblks);
+                               struct xfs_name *name);
 
 /*
  * Direct call from the bmap code, bypassing the generic directory layer.
index b62771f1f4b5b7028569b32af3b16bc806005132..d213a2eae95e0984ea5f4045c15f4dfd1e9d857f 100644 (file)
@@ -2051,6 +2051,8 @@ xfs_agi_verify(
        if (!XFS_AGI_GOOD_VERSION(be32_to_cpu(agi->agi_versionnum)))
                return false;
 
+       if (be32_to_cpu(agi->agi_level) > XFS_BTREE_MAXLEVELS)
+               return false;
        /*
         * during growfs operations, the perag is not fully initialised,
         * so we can't use it for any useful checking. growfs ensures we can't
index f4dd697cac08720f057b58c094bc4bfe3346ca5b..7c818f1e448416da6bcfae580a6aa898e5114bbb 100644 (file)
@@ -424,20 +424,24 @@ xfs_rtfind_forw(
 }
 
 /*
- * Read and modify the summary information for a given extent size,
+ * Read and/or modify the summary information for a given extent size,
  * bitmap block combination.
  * Keeps track of a current summary block, so we don't keep reading
  * it from the buffer cache.
+ *
+ * Summary information is returned in *sum if specified.
+ * If no delta is specified, returns summary only.
  */
 int
-xfs_rtmodify_summary(
-       xfs_mount_t     *mp,            /* file system mount point */
+xfs_rtmodify_summary_int(
+       xfs_mount_t     *mp,            /* file system mount structure */
        xfs_trans_t     *tp,            /* transaction pointer */
        int             log,            /* log2 of extent size */
        xfs_rtblock_t   bbno,           /* bitmap block number */
        int             delta,          /* change to make to summary info */
        xfs_buf_t       **rbpp,         /* in/out: summary block buffer */
-       xfs_fsblock_t   *rsb)           /* in/out: summary block number */
+       xfs_fsblock_t   *rsb,           /* in/out: summary block number */
+       xfs_suminfo_t   *sum)           /* out: summary info for this block */
 {
        xfs_buf_t       *bp;            /* buffer for the summary block */
        int             error;          /* error value */
@@ -456,7 +460,7 @@ xfs_rtmodify_summary(
        /*
         * If we have an old buffer, and the block number matches, use that.
         */
-       if (rbpp && *rbpp && *rsb == sb)
+       if (*rbpp && *rsb == sb)
                bp = *rbpp;
        /*
         * Otherwise we have to get the buffer.
@@ -465,7 +469,7 @@ xfs_rtmodify_summary(
                /*
                 * If there was an old one, get rid of it first.
                 */
-               if (rbpp && *rbpp)
+               if (*rbpp)
                        xfs_trans_brelse(tp, *rbpp);
                error = xfs_rtbuf_get(mp, tp, sb, 1, &bp);
                if (error) {
@@ -474,21 +478,38 @@ xfs_rtmodify_summary(
                /*
                 * Remember this buffer and block for the next call.
                 */
-               if (rbpp) {
-                       *rbpp = bp;
-                       *rsb = sb;
-               }
+               *rbpp = bp;
+               *rsb = sb;
        }
        /*
-        * Point to the summary information, modify and log it.
+        * Point to the summary information, modify/log it, and/or copy it out.
         */
        sp = XFS_SUMPTR(mp, bp, so);
-       *sp += delta;
-       xfs_trans_log_buf(tp, bp, (uint)((char *)sp - (char *)bp->b_addr),
-               (uint)((char *)sp - (char *)bp->b_addr + sizeof(*sp) - 1));
+       if (delta) {
+               uint first = (uint)((char *)sp - (char *)bp->b_addr);
+
+               *sp += delta;
+               xfs_trans_log_buf(tp, bp, first, first + sizeof(*sp) - 1);
+       }
+       if (sum)
+               *sum = *sp;
        return 0;
 }
 
+int
+xfs_rtmodify_summary(
+       xfs_mount_t     *mp,            /* file system mount structure */
+       xfs_trans_t     *tp,            /* transaction pointer */
+       int             log,            /* log2 of extent size */
+       xfs_rtblock_t   bbno,           /* bitmap block number */
+       int             delta,          /* change to make to summary info */
+       xfs_buf_t       **rbpp,         /* in/out: summary block buffer */
+       xfs_fsblock_t   *rsb)           /* in/out: summary block number */
+{
+       return xfs_rtmodify_summary_int(mp, tp, log, bbno,
+                                       delta, rbpp, rsb, NULL);
+}
+
 /*
  * Set the given range of bitmap bits to the given value.
  * Do whatever I/O and logging is required.
index ad525a5623a49557c9554f23aa72d323e9ed8b77..8426e5e2682ef47e677a174b9e4d12e58fe190a1 100644 (file)
@@ -279,11 +279,13 @@ xfs_mount_validate_sb(
            sbp->sb_blocklog < XFS_MIN_BLOCKSIZE_LOG                    ||
            sbp->sb_blocklog > XFS_MAX_BLOCKSIZE_LOG                    ||
            sbp->sb_blocksize != (1 << sbp->sb_blocklog)                ||
+           sbp->sb_dirblklog > XFS_MAX_BLOCKSIZE_LOG                   ||
            sbp->sb_inodesize < XFS_DINODE_MIN_SIZE                     ||
            sbp->sb_inodesize > XFS_DINODE_MAX_SIZE                     ||
            sbp->sb_inodelog < XFS_DINODE_MIN_LOG                       ||
            sbp->sb_inodelog > XFS_DINODE_MAX_LOG                       ||
            sbp->sb_inodesize != (1 << sbp->sb_inodelog)                ||
+           sbp->sb_logsunit > XLOG_MAX_RECORD_BSIZE                    ||
            sbp->sb_inopblock != howmany(sbp->sb_blocksize,sbp->sb_inodesize) ||
            (sbp->sb_blocklog - sbp->sb_inodelog != sbp->sb_inopblog)   ||
            (sbp->sb_rextsize * sbp->sb_blocksize > XFS_MAX_RTEXTSIZE)  ||
index cd7b8ca9b06410c5d34e92161906532a6221ef66..ec6505056b2ca2291961da64096b7ae7c7747efd 100644 (file)
@@ -1884,7 +1884,7 @@ xfs_buf_init(void)
                goto out;
 
        xfslogd_workqueue = alloc_workqueue("xfslogd",
-                                       WQ_MEM_RECLAIM | WQ_HIGHPRI, 1);
+                               WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_FREEZABLE, 1);
        if (!xfslogd_workqueue)
                goto out_free_buf_zone;
 
index de5368c803f9db192416e21032ade4535a0efcdd..eb596b4199420fa8378dcd49146640c9783037b4 100644 (file)
@@ -983,7 +983,7 @@ xfs_vm_page_mkwrite(
 
 /*
  * This type is designed to indicate the type of offset we would like
- * to search from page cache for either xfs_seek_data() or xfs_seek_hole().
+ * to search from page cache for xfs_seek_hole_data().
  */
 enum {
        HOLE_OFF = 0,
@@ -1040,7 +1040,7 @@ xfs_lookup_buffer_offset(
 /*
  * This routine is called to find out and return a data or hole offset
  * from the page cache for unwritten extents according to the desired
- * type for xfs_seek_data() or xfs_seek_hole().
+ * type for xfs_seek_hole_data().
  *
  * The argument offset is used to tell where we start to search from the
  * page cache.  Map is used to figure out the end points of the range to
@@ -1200,9 +1200,10 @@ out:
 }
 
 STATIC loff_t
-xfs_seek_data(
+xfs_seek_hole_data(
        struct file             *file,
-       loff_t                  start)
+       loff_t                  start,
+       int                     whence)
 {
        struct inode            *inode = file->f_mapping->host;
        struct xfs_inode        *ip = XFS_I(inode);
@@ -1214,6 +1215,9 @@ xfs_seek_data(
        uint                    lock;
        int                     error;
 
+       if (XFS_FORCED_SHUTDOWN(mp))
+               return -EIO;
+
        lock = xfs_ilock_data_map_shared(ip);
 
        isize = i_size_read(inode);
@@ -1228,6 +1232,7 @@ xfs_seek_data(
         */
        fsbno = XFS_B_TO_FSBT(mp, start);
        end = XFS_B_TO_FSB(mp, isize);
+
        for (;;) {
                struct xfs_bmbt_irec    map[2];
                int                     nmap = 2;
@@ -1248,29 +1253,48 @@ xfs_seek_data(
                        offset = max_t(loff_t, start,
                                       XFS_FSB_TO_B(mp, map[i].br_startoff));
 
-                       /* Landed in a data extent */
-                       if (map[i].br_startblock == DELAYSTARTBLOCK ||
-                           (map[i].br_state == XFS_EXT_NORM &&
-                            !isnullstartblock(map[i].br_startblock)))
+                       /* Landed in the hole we wanted? */
+                       if (whence == SEEK_HOLE &&
+                           map[i].br_startblock == HOLESTARTBLOCK)
+                               goto out;
+
+                       /* Landed in the data extent we wanted? */
+                       if (whence == SEEK_DATA &&
+                           (map[i].br_startblock == DELAYSTARTBLOCK ||
+                            (map[i].br_state == XFS_EXT_NORM &&
+                             !isnullstartblock(map[i].br_startblock))))
                                goto out;
 
                        /*
-                        * Landed in an unwritten extent, try to search data
-                        * from page cache.
+                        * Landed in an unwritten extent, try to search
+                        * for hole or data from page cache.
                         */
                        if (map[i].br_state == XFS_EXT_UNWRITTEN) {
                                if (xfs_find_get_desired_pgoff(inode, &map[i],
-                                                       DATA_OFF, &offset))
+                                     whence == SEEK_HOLE ? HOLE_OFF : DATA_OFF,
+                                                       &offset))
                                        goto out;
                        }
                }
 
                /*
-                * map[0] is hole or its an unwritten extent but
-                * without data in page cache.  Probably means that
-                * we are reading after EOF if nothing in map[1].
+                * We only received one extent out of the two requested. This
+                * means we've hit EOF and didn't find what we are looking for.
                 */
                if (nmap == 1) {
+                       /*
+                        * If we were looking for a hole, set offset to
+                        * the end of the file (i.e., there is an implicit
+                        * hole at the end of any file).
+                        */
+                       if (whence == SEEK_HOLE) {
+                               offset = isize;
+                               break;
+                       }
+                       /*
+                        * If we were looking for data, it's nowhere to be found
+                        */
+                       ASSERT(whence == SEEK_DATA);
                        error = -ENXIO;
                        goto out_unlock;
                }
@@ -1279,125 +1303,30 @@ xfs_seek_data(
 
                /*
                 * Nothing was found, proceed to the next round of search
-                * if reading offset not beyond or hit EOF.
+                * if the next reading offset is not at or beyond EOF.
                 */
                fsbno = map[i - 1].br_startoff + map[i - 1].br_blockcount;
                start = XFS_FSB_TO_B(mp, fsbno);
                if (start >= isize) {
+                       if (whence == SEEK_HOLE) {
+                               offset = isize;
+                               break;
+                       }
+                       ASSERT(whence == SEEK_DATA);
                        error = -ENXIO;
                        goto out_unlock;
                }
        }
 
-out:
-       offset = vfs_setpos(file, offset, inode->i_sb->s_maxbytes);
-
-out_unlock:
-       xfs_iunlock(ip, lock);
-
-       if (error)
-               return error;
-       return offset;
-}
-
-STATIC loff_t
-xfs_seek_hole(
-       struct file             *file,
-       loff_t                  start)
-{
-       struct inode            *inode = file->f_mapping->host;
-       struct xfs_inode        *ip = XFS_I(inode);
-       struct xfs_mount        *mp = ip->i_mount;
-       loff_t                  uninitialized_var(offset);
-       xfs_fsize_t             isize;
-       xfs_fileoff_t           fsbno;
-       xfs_filblks_t           end;
-       uint                    lock;
-       int                     error;
-
-       if (XFS_FORCED_SHUTDOWN(mp))
-               return -EIO;
-
-       lock = xfs_ilock_data_map_shared(ip);
-
-       isize = i_size_read(inode);
-       if (start >= isize) {
-               error = -ENXIO;
-               goto out_unlock;
-       }
-
-       fsbno = XFS_B_TO_FSBT(mp, start);
-       end = XFS_B_TO_FSB(mp, isize);
-
-       for (;;) {
-               struct xfs_bmbt_irec    map[2];
-               int                     nmap = 2;
-               unsigned int            i;
-
-               error = xfs_bmapi_read(ip, fsbno, end - fsbno, map, &nmap,
-                                      XFS_BMAPI_ENTIRE);
-               if (error)
-                       goto out_unlock;
-
-               /* No extents at given offset, must be beyond EOF */
-               if (nmap == 0) {
-                       error = -ENXIO;
-                       goto out_unlock;
-               }
-
-               for (i = 0; i < nmap; i++) {
-                       offset = max_t(loff_t, start,
-                                      XFS_FSB_TO_B(mp, map[i].br_startoff));
-
-                       /* Landed in a hole */
-                       if (map[i].br_startblock == HOLESTARTBLOCK)
-                               goto out;
-
-                       /*
-                        * Landed in an unwritten extent, try to search hole
-                        * from page cache.
-                        */
-                       if (map[i].br_state == XFS_EXT_UNWRITTEN) {
-                               if (xfs_find_get_desired_pgoff(inode, &map[i],
-                                                       HOLE_OFF, &offset))
-                                       goto out;
-                       }
-               }
-
-               /*
-                * map[0] contains data or its unwritten but contains
-                * data in page cache, probably means that we are
-                * reading after EOF.  We should fix offset to point
-                * to the end of the file(i.e., there is an implicit
-                * hole at the end of any file).
-                */
-               if (nmap == 1) {
-                       offset = isize;
-                       break;
-               }
-
-               ASSERT(i > 1);
-
-               /*
-                * Both mappings contains data, proceed to the next round of
-                * search if the current reading offset not beyond or hit EOF.
-                */
-               fsbno = map[i - 1].br_startoff + map[i - 1].br_blockcount;
-               start = XFS_FSB_TO_B(mp, fsbno);
-               if (start >= isize) {
-                       offset = isize;
-                       break;
-               }
-       }
-
 out:
        /*
-        * At this point, we must have found a hole.  However, the returned
+        * If at this point we have found the hole we wanted, the returned
         * offset may be bigger than the file size as it may be aligned to
-        * page boundary for unwritten extents, we need to deal with this
+        * page boundary for unwritten extents.  We need to deal with this
         * situation in particular.
         */
-       offset = min_t(loff_t, offset, isize);
+       if (whence == SEEK_HOLE)
+               offset = min_t(loff_t, offset, isize);
        offset = vfs_setpos(file, offset, inode->i_sb->s_maxbytes);
 
 out_unlock:
@@ -1412,17 +1341,16 @@ STATIC loff_t
 xfs_file_llseek(
        struct file     *file,
        loff_t          offset,
-       int             origin)
+       int             whence)
 {
-       switch (origin) {
+       switch (whence) {
        case SEEK_END:
        case SEEK_CUR:
        case SEEK_SET:
-               return generic_file_llseek(file, offset, origin);
-       case SEEK_DATA:
-               return xfs_seek_data(file, offset);
+               return generic_file_llseek(file, offset, whence);
        case SEEK_HOLE:
-               return xfs_seek_hole(file, offset);
+       case SEEK_DATA:
+               return xfs_seek_hole_data(file, offset, whence);
        default:
                return -EINVAL;
        }
index 5399ef222dd738b85d39096ac7db5a39ebb8c359..4d41b241298fba5031fb93e59e39e209bf36b308 100644 (file)
@@ -43,3 +43,7 @@ xfs_param_t xfs_params = {
        .fstrm_timer    = {     1,              30*100,         3600*100},
        .eofb_timer     = {     1,              300,            3600*24},
 };
+
+struct xfs_globals xfs_globals = {
+       .log_recovery_delay     =       0,      /* no delay by default */
+};
index fea3c92fb3f0603b5ca44bb86a5a18dcaaac6240..c92cb48617d1e2ebb58e127622593b345c1caffd 100644 (file)
@@ -1153,9 +1153,11 @@ xfs_create(
        if (error)
                goto out_trans_cancel;
 
-       error = xfs_dir_canenter(tp, dp, name, resblks);
-       if (error)
-               goto out_trans_cancel;
+       if (!resblks) {
+               error = xfs_dir_canenter(tp, dp, name);
+               if (error)
+                       goto out_trans_cancel;
+       }
 
        /*
         * A newly created regular or special file just has one directory
@@ -1421,9 +1423,11 @@ xfs_link(
                goto error_return;
        }
 
-       error = xfs_dir_canenter(tp, tdp, target_name, resblks);
-       if (error)
-               goto error_return;
+       if (!resblks) {
+               error = xfs_dir_canenter(tp, tdp, target_name);
+               if (error)
+                       goto error_return;
+       }
 
        xfs_bmap_init(&free_list, &first_block);
 
@@ -2759,9 +2763,11 @@ xfs_rename(
                 * If there's no space reservation, check the entry will
                 * fit before actually inserting it.
                 */
-               error = xfs_dir_canenter(tp, target_dp, target_name, spaceres);
-               if (error)
-                       goto error_return;
+               if (!spaceres) {
+                       error = xfs_dir_canenter(tp, target_dp, target_name);
+                       if (error)
+                               goto error_return;
+               }
                /*
                 * If target does not exist and the rename crosses
                 * directories, adjust the target directory link count
index 1fd5787add9924d7ac726329f2ee88c13a90422d..29e101fc32c5c2dcd5d3a61fc2e1269e2057217c 100644 (file)
@@ -4132,41 +4132,13 @@ xlog_do_recovery_pass(
        }
 
        memset(rhash, 0, sizeof(rhash));
-       if (tail_blk <= head_blk) {
-               for (blk_no = tail_blk; blk_no < head_blk; ) {
-                       error = xlog_bread(log, blk_no, hblks, hbp, &offset);
-                       if (error)
-                               goto bread_err2;
-
-                       rhead = (xlog_rec_header_t *)offset;
-                       error = xlog_valid_rec_header(log, rhead, blk_no);
-                       if (error)
-                               goto bread_err2;
-
-                       /* blocks in data section */
-                       bblks = (int)BTOBB(be32_to_cpu(rhead->h_len));
-                       error = xlog_bread(log, blk_no + hblks, bblks, dbp,
-                                          &offset);
-                       if (error)
-                               goto bread_err2;
-
-                       error = xlog_unpack_data(rhead, offset, log);
-                       if (error)
-                               goto bread_err2;
-
-                       error = xlog_recover_process_data(log,
-                                               rhash, rhead, offset, pass);
-                       if (error)
-                               goto bread_err2;
-                       blk_no += bblks + hblks;
-               }
-       } else {
+       blk_no = tail_blk;
+       if (tail_blk > head_blk) {
                /*
                 * Perform recovery around the end of the physical log.
                 * When the head is not on the same cycle number as the tail,
-                * we can't do a sequential recovery as above.
+                * we can't do a sequential recovery.
                 */
-               blk_no = tail_blk;
                while (blk_no < log->l_logBBsize) {
                        /*
                         * Check for header wrapping around physical end-of-log
@@ -4280,34 +4252,35 @@ xlog_do_recovery_pass(
 
                ASSERT(blk_no >= log->l_logBBsize);
                blk_no -= log->l_logBBsize;
+       }
 
-               /* read first part of physical log */
-               while (blk_no < head_blk) {
-                       error = xlog_bread(log, blk_no, hblks, hbp, &offset);
-                       if (error)
-                               goto bread_err2;
+       /* read first part of physical log */
+       while (blk_no < head_blk) {
+               error = xlog_bread(log, blk_no, hblks, hbp, &offset);
+               if (error)
+                       goto bread_err2;
 
-                       rhead = (xlog_rec_header_t *)offset;
-                       error = xlog_valid_rec_header(log, rhead, blk_no);
-                       if (error)
-                               goto bread_err2;
+               rhead = (xlog_rec_header_t *)offset;
+               error = xlog_valid_rec_header(log, rhead, blk_no);
+               if (error)
+                       goto bread_err2;
 
-                       bblks = (int)BTOBB(be32_to_cpu(rhead->h_len));
-                       error = xlog_bread(log, blk_no+hblks, bblks, dbp,
-                                          &offset);
-                       if (error)
-                               goto bread_err2;
+               /* blocks in data section */
+               bblks = (int)BTOBB(be32_to_cpu(rhead->h_len));
+               error = xlog_bread(log, blk_no+hblks, bblks, dbp,
+                                  &offset);
+               if (error)
+                       goto bread_err2;
 
-                       error = xlog_unpack_data(rhead, offset, log);
-                       if (error)
-                               goto bread_err2;
+               error = xlog_unpack_data(rhead, offset, log);
+               if (error)
+                       goto bread_err2;
 
-                       error = xlog_recover_process_data(log, rhash,
-                                                       rhead, offset, pass);
-                       if (error)
-                               goto bread_err2;
-                       blk_no += bblks + hblks;
-               }
+               error = xlog_recover_process_data(log, rhash,
+                                               rhead, offset, pass);
+               if (error)
+                       goto bread_err2;
+               blk_no += bblks + hblks;
        }
 
  bread_err2:
@@ -4509,6 +4482,18 @@ xlog_recover(
                        return -EINVAL;
                }
 
+               /*
+                * Delay log recovery if the debug hook is set. This is debug
+                * instrumention to coordinate simulation of I/O failures with
+                * log recovery.
+                */
+               if (xfs_globals.log_recovery_delay) {
+                       xfs_notice(log->l_mp,
+                               "Delaying log recovery for %d seconds.",
+                               xfs_globals.log_recovery_delay);
+                       msleep(xfs_globals.log_recovery_delay * 1000);
+               }
+
                xfs_notice(log->l_mp, "Starting recovery (logdev: %s)",
                                log->l_mp->m_logname ? log->l_mp->m_logname
                                                     : "internal");
index 1eb6f3df698c8bb4eac11b5c03aa23790cbc65c4..30ecca3037e37bc5354fb9e37deb4db6e163fa8a 100644 (file)
@@ -304,7 +304,8 @@ _xfs_mru_cache_reap(
 int
 xfs_mru_cache_init(void)
 {
-       xfs_mru_reap_wq = alloc_workqueue("xfs_mru_cache", WQ_MEM_RECLAIM, 1);
+       xfs_mru_reap_wq = alloc_workqueue("xfs_mru_cache",
+                               WQ_MEM_RECLAIM|WQ_FREEZABLE, 1);
        if (!xfs_mru_reap_wq)
                return -ENOMEM;
        return 0;
index 909e143b87ae66124472c8f8e08fe1a9aaa4737e..d1160cce5dad80c91a4f7604ea0423408e2145b7 100644 (file)
@@ -46,7 +46,7 @@
  * Keeps track of a current summary block, so we don't keep reading
  * it from the buffer cache.
  */
-STATIC int                             /* error */
+int
 xfs_rtget_summary(
        xfs_mount_t     *mp,            /* file system mount structure */
        xfs_trans_t     *tp,            /* transaction pointer */
@@ -56,60 +56,9 @@ xfs_rtget_summary(
        xfs_fsblock_t   *rsb,           /* in/out: summary block number */
        xfs_suminfo_t   *sum)           /* out: summary info for this block */
 {
-       xfs_buf_t       *bp;            /* buffer for summary block */
-       int             error;          /* error value */
-       xfs_fsblock_t   sb;             /* summary fsblock */
-       int             so;             /* index into the summary file */
-       xfs_suminfo_t   *sp;            /* pointer to returned data */
-
-       /*
-        * Compute entry number in the summary file.
-        */
-       so = XFS_SUMOFFS(mp, log, bbno);
-       /*
-        * Compute the block number in the summary file.
-        */
-       sb = XFS_SUMOFFSTOBLOCK(mp, so);
-       /*
-        * If we have an old buffer, and the block number matches, use that.
-        */
-       if (rbpp && *rbpp && *rsb == sb)
-               bp = *rbpp;
-       /*
-        * Otherwise we have to get the buffer.
-        */
-       else {
-               /*
-                * If there was an old one, get rid of it first.
-                */
-               if (rbpp && *rbpp)
-                       xfs_trans_brelse(tp, *rbpp);
-               error = xfs_rtbuf_get(mp, tp, sb, 1, &bp);
-               if (error) {
-                       return error;
-               }
-               /*
-                * Remember this buffer and block for the next call.
-                */
-               if (rbpp) {
-                       *rbpp = bp;
-                       *rsb = sb;
-               }
-       }
-       /*
-        * Point to the summary information & copy it out.
-        */
-       sp = XFS_SUMPTR(mp, bp, so);
-       *sum = *sp;
-       /*
-        * Drop the buffer if we're not asked to remember it.
-        */
-       if (!rbpp)
-               xfs_trans_brelse(tp, bp);
-       return 0;
+       return xfs_rtmodify_summary_int(mp, tp, log, bbno, 0, rbpp, rsb, sum);
 }
 
-
 /*
  * Return whether there are any free extents in the size range given
  * by low and high, for the bitmap block bbno.
index c642795324af649c1c80666e5bdc7e0739551e1d..76c0a4a9bb170a327936d1719c8cc9fa736de324 100644 (file)
@@ -111,6 +111,10 @@ int xfs_rtfind_forw(struct xfs_mount *mp, struct xfs_trans *tp,
                    xfs_rtblock_t *rtblock);
 int xfs_rtmodify_range(struct xfs_mount *mp, struct xfs_trans *tp,
                       xfs_rtblock_t start, xfs_extlen_t len, int val);
+int xfs_rtmodify_summary_int(struct xfs_mount *mp, struct xfs_trans *tp,
+                            int log, xfs_rtblock_t bbno, int delta,
+                            xfs_buf_t **rbpp, xfs_fsblock_t *rsb,
+                            xfs_suminfo_t *sum);
 int xfs_rtmodify_summary(struct xfs_mount *mp, struct xfs_trans *tp, int log,
                         xfs_rtblock_t bbno, int delta, xfs_buf_t **rbpp,
                         xfs_fsblock_t *rsb);
index b194652033cd11c8530ae762d01972fa455a23aa..dcd4b93dccdc564ed42c98eb3571f6f890e90812 100644 (file)
@@ -47,6 +47,7 @@
 #include "xfs_dinode.h"
 #include "xfs_filestream.h"
 #include "xfs_quota.h"
+#include "xfs_sysfs.h"
 
 #include <linux/namei.h>
 #include <linux/init.h>
 static const struct super_operations xfs_super_operations;
 static kmem_zone_t *xfs_ioend_zone;
 mempool_t *xfs_ioend_pool;
-struct kset *xfs_kset;
+
+struct kset *xfs_kset;                 /* top-level xfs sysfs dir */
+#ifdef DEBUG
+static struct xfs_kobj xfs_dbg_kobj;   /* global debug sysfs attrs */
+#endif
 
 #define MNTOPT_LOGBUFS "logbufs"       /* number of XFS log buffers */
 #define MNTOPT_LOGBSIZE        "logbsize"      /* size of XFS log buffers */
@@ -838,32 +843,32 @@ xfs_init_mount_workqueues(
        struct xfs_mount        *mp)
 {
        mp->m_data_workqueue = alloc_workqueue("xfs-data/%s",
-                       WQ_MEM_RECLAIM, 0, mp->m_fsname);
+                       WQ_MEM_RECLAIM|WQ_FREEZABLE, 0, mp->m_fsname);
        if (!mp->m_data_workqueue)
                goto out;
 
        mp->m_unwritten_workqueue = alloc_workqueue("xfs-conv/%s",
-                       WQ_MEM_RECLAIM, 0, mp->m_fsname);
+                       WQ_MEM_RECLAIM|WQ_FREEZABLE, 0, mp->m_fsname);
        if (!mp->m_unwritten_workqueue)
                goto out_destroy_data_iodone_queue;
 
        mp->m_cil_workqueue = alloc_workqueue("xfs-cil/%s",
-                       WQ_MEM_RECLAIM, 0, mp->m_fsname);
+                       WQ_MEM_RECLAIM|WQ_FREEZABLE, 0, mp->m_fsname);
        if (!mp->m_cil_workqueue)
                goto out_destroy_unwritten;
 
        mp->m_reclaim_workqueue = alloc_workqueue("xfs-reclaim/%s",
-                       0, 0, mp->m_fsname);
+                       WQ_FREEZABLE, 0, mp->m_fsname);
        if (!mp->m_reclaim_workqueue)
                goto out_destroy_cil;
 
        mp->m_log_workqueue = alloc_workqueue("xfs-log/%s",
-                       0, 0, mp->m_fsname);
+                       WQ_FREEZABLE, 0, mp->m_fsname);
        if (!mp->m_log_workqueue)
                goto out_destroy_reclaim;
 
        mp->m_eofblocks_workqueue = alloc_workqueue("xfs-eofblocks/%s",
-                       0, 0, mp->m_fsname);
+                       WQ_FREEZABLE, 0, mp->m_fsname);
        if (!mp->m_eofblocks_workqueue)
                goto out_destroy_log;
 
@@ -1715,7 +1720,8 @@ xfs_init_workqueues(void)
         * AGs in all the filesystems mounted. Hence use the default large
         * max_active value for this workqueue.
         */
-       xfs_alloc_wq = alloc_workqueue("xfsalloc", WQ_MEM_RECLAIM, 0);
+       xfs_alloc_wq = alloc_workqueue("xfsalloc",
+                       WQ_MEM_RECLAIM|WQ_FREEZABLE, 0);
        if (!xfs_alloc_wq)
                return -ENOMEM;
 
@@ -1768,9 +1774,16 @@ init_xfs_fs(void)
                goto out_sysctl_unregister;;
        }
 
-       error = xfs_qm_init();
+#ifdef DEBUG
+       xfs_dbg_kobj.kobject.kset = xfs_kset;
+       error = xfs_sysfs_init(&xfs_dbg_kobj, &xfs_dbg_ktype, NULL, "debug");
        if (error)
                goto out_kset_unregister;
+#endif
+
+       error = xfs_qm_init();
+       if (error)
+               goto out_remove_kobj;
 
        error = register_filesystem(&xfs_fs_type);
        if (error)
@@ -1779,7 +1792,11 @@ init_xfs_fs(void)
 
  out_qm_exit:
        xfs_qm_exit();
+ out_remove_kobj:
+#ifdef DEBUG
+       xfs_sysfs_del(&xfs_dbg_kobj);
  out_kset_unregister:
+#endif
        kset_unregister(xfs_kset);
  out_sysctl_unregister:
        xfs_sysctl_unregister();
@@ -1802,6 +1819,9 @@ exit_xfs_fs(void)
 {
        xfs_qm_exit();
        unregister_filesystem(&xfs_fs_type);
+#ifdef DEBUG
+       xfs_sysfs_del(&xfs_dbg_kobj);
+#endif
        kset_unregister(xfs_kset);
        xfs_sysctl_unregister();
        xfs_cleanup_procfs();
index 6a944a2cd36fbf97717ea31f56e82c101caef3a9..02ae62a998e082a54fe86b3a9c6f6b7cdf071e57 100644 (file)
@@ -269,9 +269,11 @@ xfs_symlink(
        /*
         * Check for ability to enter directory entry, if no space reserved.
         */
-       error = xfs_dir_canenter(tp, dp, link_name, resblks);
-       if (error)
-               goto error_return;
+       if (!resblks) {
+               error = xfs_dir_canenter(tp, dp, link_name);
+               if (error)
+                       goto error_return;
+       }
        /*
         * Initialize the bmap freelist prior to calling either
         * bmapi or the directory create code.
index bd8e157c20efa254c736952967e6c894dbd706a0..ffef453757543a94d742eb2890e4858e8bcd7716 100644 (file)
@@ -92,6 +92,11 @@ enum {
 
 extern xfs_param_t     xfs_params;
 
+struct xfs_globals {
+       int     log_recovery_delay;     /* log recovery delay (secs) */
+};
+extern struct xfs_globals      xfs_globals;
+
 #ifdef CONFIG_SYSCTL
 extern int xfs_sysctl_register(void);
 extern void xfs_sysctl_unregister(void);
index 9835139ce1ec24cd2e1d5358377bd844d4323ab7..aa03670851d86574cc542a2eccb1b5c4607e4ca5 100644 (file)
@@ -51,6 +51,80 @@ struct kobj_type xfs_mp_ktype = {
        .release = xfs_sysfs_release,
 };
 
+#ifdef DEBUG
+/* debug */
+
+STATIC ssize_t
+log_recovery_delay_store(
+       const char      *buf,
+       size_t          count,
+       void            *data)
+{
+       int             ret;
+       int             val;
+
+       ret = kstrtoint(buf, 0, &val);
+       if (ret)
+               return ret;
+
+       if (val < 0 || val > 60)
+               return -EINVAL;
+
+       xfs_globals.log_recovery_delay = val;
+
+       return count;
+}
+
+STATIC ssize_t
+log_recovery_delay_show(
+       char    *buf,
+       void    *data)
+{
+       return snprintf(buf, PAGE_SIZE, "%d\n", xfs_globals.log_recovery_delay);
+}
+XFS_SYSFS_ATTR_RW(log_recovery_delay);
+
+static struct attribute *xfs_dbg_attrs[] = {
+       ATTR_LIST(log_recovery_delay),
+       NULL,
+};
+
+STATIC ssize_t
+xfs_dbg_show(
+       struct kobject          *kobject,
+       struct attribute        *attr,
+       char                    *buf)
+{
+       struct xfs_sysfs_attr *xfs_attr = to_attr(attr);
+
+       return xfs_attr->show ? xfs_attr->show(buf, NULL) : 0;
+}
+
+STATIC ssize_t
+xfs_dbg_store(
+       struct kobject          *kobject,
+       struct attribute        *attr,
+       const char              *buf,
+       size_t                  count)
+{
+       struct xfs_sysfs_attr *xfs_attr = to_attr(attr);
+
+       return xfs_attr->store ? xfs_attr->store(buf, count, NULL) : 0;
+}
+
+static struct sysfs_ops xfs_dbg_ops = {
+       .show = xfs_dbg_show,
+       .store = xfs_dbg_store,
+};
+
+struct kobj_type xfs_dbg_ktype = {
+       .release = xfs_sysfs_release,
+       .sysfs_ops = &xfs_dbg_ops,
+       .default_attrs = xfs_dbg_attrs,
+};
+
+#endif /* DEBUG */
+
 /* xlog */
 
 STATIC ssize_t
index 54a2091183c08a066b9751cfca37ba63f1e83b01..240eee35f342b8bbae4511f0ef04d38e32e3a0c4 100644 (file)
@@ -20,6 +20,7 @@
 #define __XFS_SYSFS_H__
 
 extern struct kobj_type xfs_mp_ktype;  /* xfs_mount */
+extern struct kobj_type xfs_dbg_ktype; /* debug */
 extern struct kobj_type xfs_log_ktype; /* xlog */
 
 static inline struct xfs_kobj *