|
@@ -1327,6 +1327,121 @@ int gfs2_file_dealloc(struct gfs2_inode *ip)
|
|
return trunc_dealloc(ip, 0);
|
|
return trunc_dealloc(ip, 0);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * gfs2_free_journal_extents - Free cached journal bmap info
|
|
|
|
+ * @jd: The journal
|
|
|
|
+ *
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+void gfs2_free_journal_extents(struct gfs2_jdesc *jd)
|
|
|
|
+{
|
|
|
|
+ struct gfs2_journal_extent *jext;
|
|
|
|
+
|
|
|
|
+ while(!list_empty(&jd->extent_list)) {
|
|
|
|
+ jext = list_entry(jd->extent_list.next, struct gfs2_journal_extent, list);
|
|
|
|
+ list_del(&jext->list);
|
|
|
|
+ kfree(jext);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * gfs2_add_jextent - Add or merge a new extent to extent cache
|
|
|
|
+ * @jd: The journal descriptor
|
|
|
|
+ * @lblock: The logical block at start of new extent
|
|
|
|
+ * @pblock: The physical block at start of new extent
|
|
|
|
+ * @blocks: Size of extent in fs blocks
|
|
|
|
+ *
|
|
|
|
+ * Returns: 0 on success or -ENOMEM
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+static int gfs2_add_jextent(struct gfs2_jdesc *jd, u64 lblock, u64 dblock, u64 blocks)
|
|
|
|
+{
|
|
|
|
+ struct gfs2_journal_extent *jext;
|
|
|
|
+
|
|
|
|
+ if (!list_empty(&jd->extent_list)) {
|
|
|
|
+ jext = list_entry(jd->extent_list.prev, struct gfs2_journal_extent, list);
|
|
|
|
+ if ((jext->dblock + jext->blocks) == dblock) {
|
|
|
|
+ jext->blocks += blocks;
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ jext = kzalloc(sizeof(struct gfs2_journal_extent), GFP_NOFS);
|
|
|
|
+ if (jext == NULL)
|
|
|
|
+ return -ENOMEM;
|
|
|
|
+ jext->dblock = dblock;
|
|
|
|
+ jext->lblock = lblock;
|
|
|
|
+ jext->blocks = blocks;
|
|
|
|
+ list_add_tail(&jext->list, &jd->extent_list);
|
|
|
|
+ jd->nr_extents++;
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * gfs2_map_journal_extents - Cache journal bmap info
|
|
|
|
+ * @sdp: The super block
|
|
|
|
+ * @jd: The journal to map
|
|
|
|
+ *
|
|
|
|
+ * Create a reusable "extent" mapping from all logical
|
|
|
|
+ * blocks to all physical blocks for the given journal. This will save
|
|
|
|
+ * us time when writing journal blocks. Most journals will have only one
|
|
|
|
+ * extent that maps all their logical blocks. That's because gfs2.mkfs
|
|
|
|
+ * arranges the journal blocks sequentially to maximize performance.
|
|
|
|
+ * So the extent would map the first block for the entire file length.
|
|
|
|
+ * However, gfs2_jadd can happen while file activity is happening, so
|
|
|
|
+ * those journals may not be sequential. Less likely is the case where
|
|
|
|
+ * the users created their own journals by mounting the metafs and
|
|
|
|
+ * laying it out. But it's still possible. These journals might have
|
|
|
|
+ * several extents.
|
|
|
|
+ *
|
|
|
|
+ * Returns: 0 on success, or error on failure
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+int gfs2_map_journal_extents(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd)
|
|
|
|
+{
|
|
|
|
+ u64 lblock = 0;
|
|
|
|
+ u64 lblock_stop;
|
|
|
|
+ struct gfs2_inode *ip = GFS2_I(jd->jd_inode);
|
|
|
|
+ struct buffer_head bh;
|
|
|
|
+ unsigned int shift = sdp->sd_sb.sb_bsize_shift;
|
|
|
|
+ u64 size;
|
|
|
|
+ int rc;
|
|
|
|
+
|
|
|
|
+ lblock_stop = i_size_read(jd->jd_inode) >> shift;
|
|
|
|
+ size = (lblock_stop - lblock) << shift;
|
|
|
|
+ jd->nr_extents = 0;
|
|
|
|
+ WARN_ON(!list_empty(&jd->extent_list));
|
|
|
|
+
|
|
|
|
+ do {
|
|
|
|
+ bh.b_state = 0;
|
|
|
|
+ bh.b_blocknr = 0;
|
|
|
|
+ bh.b_size = size;
|
|
|
|
+ rc = gfs2_block_map(jd->jd_inode, lblock, &bh, 0);
|
|
|
|
+ if (rc || !buffer_mapped(&bh))
|
|
|
|
+ goto fail;
|
|
|
|
+ rc = gfs2_add_jextent(jd, lblock, bh.b_blocknr, bh.b_size >> shift);
|
|
|
|
+ if (rc)
|
|
|
|
+ goto fail;
|
|
|
|
+ size -= bh.b_size;
|
|
|
|
+ lblock += (bh.b_size >> ip->i_inode.i_blkbits);
|
|
|
|
+ } while(size > 0);
|
|
|
|
+
|
|
|
|
+ fs_info(sdp, "journal %d mapped with %u extents\n", jd->jd_jid,
|
|
|
|
+ jd->nr_extents);
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+fail:
|
|
|
|
+ fs_warn(sdp, "error %d mapping journal %u at offset %llu (extent %u)\n",
|
|
|
|
+ rc, jd->jd_jid,
|
|
|
|
+ (unsigned long long)(i_size_read(jd->jd_inode) - size),
|
|
|
|
+ jd->nr_extents);
|
|
|
|
+ fs_warn(sdp, "bmap=%d lblock=%llu block=%llu, state=0x%08lx, size=%llu\n",
|
|
|
|
+ rc, (unsigned long long)lblock, (unsigned long long)bh.b_blocknr,
|
|
|
|
+ bh.b_state, (unsigned long long)bh.b_size);
|
|
|
|
+ gfs2_free_journal_extents(jd);
|
|
|
|
+ return rc;
|
|
|
|
+}
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* gfs2_write_alloc_required - figure out if a write will require an allocation
|
|
* gfs2_write_alloc_required - figure out if a write will require an allocation
|
|
* @ip: the file being written to
|
|
* @ip: the file being written to
|