xfs: Inode create log items
authorDave Chinner <david@fromorbit.com>
Thu, 27 Jun 2013 06:04:53 +0000 (16:04 +1000)
committerBen Myers <bpm@sgi.com>
Thu, 27 Jun 2013 18:34:12 +0000 (13:34 -0500)
Introduce the inode create log item type for logical inode create logging.
Instead of logging the changes in buffers, pass the range to be
initialised through the log by a new transaction type.  This reduces
the amount of log space required to record initialisation during
allocation from about 128 bytes per inode to a small fixed amount
per inode extent to be initialised.

This requires a new log item type to track it through the log
and the AIL. This is a relatively simple item - most callbacks are
noops as this item has the same life cycle as the transaction.

Signed-off-by: Dave Chinner <david@fromorbit.com>
Reviewed-by: Mark Tinguely <tinguely@sgi.com>
Signed-off-by: Ben Myers <bpm@sgi.com>
fs/xfs/Makefile
fs/xfs/xfs_icreate_item.c [new file with mode: 0644]
fs/xfs/xfs_icreate_item.h [new file with mode: 0644]
fs/xfs/xfs_log.h
fs/xfs/xfs_super.c
fs/xfs/xfs_trans.h

index 6313b69b6644cd6b8ab5d1a153f6e13c38e39e82..4a4508023a3c15724a2edfd87204550f718c805b 100644 (file)
@@ -71,6 +71,7 @@ xfs-y                         += xfs_alloc.o \
                                   xfs_dir2_sf.o \
                                   xfs_ialloc.o \
                                   xfs_ialloc_btree.o \
+                                  xfs_icreate_item.o \
                                   xfs_inode.o \
                                   xfs_log_recover.o \
                                   xfs_mount.o \
diff --git a/fs/xfs/xfs_icreate_item.c b/fs/xfs/xfs_icreate_item.c
new file mode 100644 (file)
index 0000000..7716a4e
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2008-2010, 2013 Dave Chinner
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+#include "xfs.h"
+#include "xfs_fs.h"
+#include "xfs_types.h"
+#include "xfs_bit.h"
+#include "xfs_log.h"
+#include "xfs_inum.h"
+#include "xfs_trans.h"
+#include "xfs_buf_item.h"
+#include "xfs_sb.h"
+#include "xfs_ag.h"
+#include "xfs_dir2.h"
+#include "xfs_mount.h"
+#include "xfs_trans_priv.h"
+#include "xfs_bmap_btree.h"
+#include "xfs_alloc_btree.h"
+#include "xfs_ialloc_btree.h"
+#include "xfs_attr_sf.h"
+#include "xfs_dinode.h"
+#include "xfs_inode.h"
+#include "xfs_inode_item.h"
+#include "xfs_btree.h"
+#include "xfs_ialloc.h"
+#include "xfs_error.h"
+#include "xfs_icreate_item.h"
+
+kmem_zone_t    *xfs_icreate_zone;              /* inode create item zone */
+
+static inline struct xfs_icreate_item *ICR_ITEM(struct xfs_log_item *lip)
+{
+       return container_of(lip, struct xfs_icreate_item, ic_item);
+}
+
+/*
+ * This returns the number of iovecs needed to log the given inode item.
+ *
+ * We only need one iovec for the icreate log structure.
+ */
+STATIC uint
+xfs_icreate_item_size(
+       struct xfs_log_item     *lip)
+{
+       return 1;
+}
+
+/*
+ * This is called to fill in the vector of log iovecs for the
+ * given inode create log item.
+ */
+STATIC void
+xfs_icreate_item_format(
+       struct xfs_log_item     *lip,
+       struct xfs_log_iovec    *log_vector)
+{
+       struct xfs_icreate_item *icp = ICR_ITEM(lip);
+
+       log_vector->i_addr = (xfs_caddr_t)&icp->ic_format;
+       log_vector->i_len  = sizeof(struct xfs_icreate_log);
+       log_vector->i_type = XLOG_REG_TYPE_ICREATE;
+}
+
+
+/* Pinning has no meaning for the create item, so just return. */
+STATIC void
+xfs_icreate_item_pin(
+       struct xfs_log_item     *lip)
+{
+}
+
+
+/* pinning has no meaning for the create item, so just return. */
+STATIC void
+xfs_icreate_item_unpin(
+       struct xfs_log_item     *lip,
+       int                     remove)
+{
+}
+
+STATIC void
+xfs_icreate_item_unlock(
+       struct xfs_log_item     *lip)
+{
+       struct xfs_icreate_item *icp = ICR_ITEM(lip);
+
+       if (icp->ic_item.li_flags & XFS_LI_ABORTED)
+               kmem_zone_free(xfs_icreate_zone, icp);
+       return;
+}
+
+/*
+ * Because we have ordered buffers being tracked in the AIL for the inode
+ * creation, we don't need the create item after this. Hence we can free
+ * the log item and return -1 to tell the caller we're done with the item.
+ */
+STATIC xfs_lsn_t
+xfs_icreate_item_committed(
+       struct xfs_log_item     *lip,
+       xfs_lsn_t               lsn)
+{
+       struct xfs_icreate_item *icp = ICR_ITEM(lip);
+
+       kmem_zone_free(xfs_icreate_zone, icp);
+       return (xfs_lsn_t)-1;
+}
+
+/* item can never get into the AIL */
+STATIC uint
+xfs_icreate_item_push(
+       struct xfs_log_item     *lip,
+       struct list_head        *buffer_list)
+{
+       ASSERT(0);
+       return XFS_ITEM_SUCCESS;
+}
+
+/* Ordered buffers do the dependency tracking here, so this does nothing. */
+STATIC void
+xfs_icreate_item_committing(
+       struct xfs_log_item     *lip,
+       xfs_lsn_t               lsn)
+{
+}
+
+/*
+ * This is the ops vector shared by all buf log items.
+ */
+static struct xfs_item_ops xfs_icreate_item_ops = {
+       .iop_size       = xfs_icreate_item_size,
+       .iop_format     = xfs_icreate_item_format,
+       .iop_pin        = xfs_icreate_item_pin,
+       .iop_unpin      = xfs_icreate_item_unpin,
+       .iop_push       = xfs_icreate_item_push,
+       .iop_unlock     = xfs_icreate_item_unlock,
+       .iop_committed  = xfs_icreate_item_committed,
+       .iop_committing = xfs_icreate_item_committing,
+};
+
+
+/*
+ * Initialize the inode log item for a newly allocated (in-core) inode.
+ *
+ * Inode extents can only reside within an AG. Hence specify the starting
+ * block for the inode chunk by offset within an AG as well as the
+ * length of the allocated extent.
+ *
+ * This joins the item to the transaction and marks it dirty so
+ * that we don't need a separate call to do this, nor does the
+ * caller need to know anything about the icreate item.
+ */
+void
+xfs_icreate_log(
+       struct xfs_trans        *tp,
+       xfs_agnumber_t          agno,
+       xfs_agblock_t           agbno,
+       unsigned int            count,
+       unsigned int            inode_size,
+       xfs_agblock_t           length,
+       unsigned int            generation)
+{
+       struct xfs_icreate_item *icp;
+
+       icp = kmem_zone_zalloc(xfs_icreate_zone, KM_SLEEP);
+
+       xfs_log_item_init(tp->t_mountp, &icp->ic_item, XFS_LI_ICREATE,
+                         &xfs_icreate_item_ops);
+
+       icp->ic_format.icl_type = XFS_LI_ICREATE;
+       icp->ic_format.icl_size = 1;    /* single vector */
+       icp->ic_format.icl_ag = cpu_to_be32(agno);
+       icp->ic_format.icl_agbno = cpu_to_be32(agbno);
+       icp->ic_format.icl_count = cpu_to_be32(count);
+       icp->ic_format.icl_isize = cpu_to_be32(inode_size);
+       icp->ic_format.icl_length = cpu_to_be32(length);
+       icp->ic_format.icl_gen = cpu_to_be32(generation);
+
+       xfs_trans_add_item(tp, &icp->ic_item);
+       tp->t_flags |= XFS_TRANS_DIRTY;
+       icp->ic_item.li_desc->lid_flags |= XFS_LID_DIRTY;
+}
diff --git a/fs/xfs/xfs_icreate_item.h b/fs/xfs/xfs_icreate_item.h
new file mode 100644 (file)
index 0000000..88ba8aa
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2008-2010, Dave Chinner
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+#ifndef XFS_ICREATE_ITEM_H
+#define XFS_ICREATE_ITEM_H     1
+
+/*
+ * on disk log item structure
+ *
+ * Log recovery assumes the first two entries are the type and size and they fit
+ * in 32 bits. Also in host order (ugh) so they have to be 32 bit aligned so
+ * decoding can be done correctly.
+ */
+struct xfs_icreate_log {
+       __uint16_t      icl_type;       /* type of log format structure */
+       __uint16_t      icl_size;       /* size of log format structure */
+       __be32          icl_ag;         /* ag being allocated in */
+       __be32          icl_agbno;      /* start block of inode range */
+       __be32          icl_count;      /* number of inodes to initialise */
+       __be32          icl_isize;      /* size of inodes */
+       __be32          icl_length;     /* length of extent to initialise */
+       __be32          icl_gen;        /* inode generation number to use */
+};
+
+/* in memory log item structure */
+struct xfs_icreate_item {
+       struct xfs_log_item     ic_item;
+       struct xfs_icreate_log  ic_format;
+};
+
+extern kmem_zone_t *xfs_icreate_zone;  /* inode create item zone */
+
+void xfs_icreate_log(struct xfs_trans *tp, xfs_agnumber_t agno,
+                       xfs_agblock_t agbno, unsigned int count,
+                       unsigned int inode_size, xfs_agblock_t length,
+                       unsigned int generation);
+
+#endif /* XFS_ICREATE_ITEM_H */
index b20918c554aa39c6f0ced9bbc4db63f3c76f3887..fb630e496c12406c558b7cc53854bf0cd123ccaf 100644 (file)
@@ -88,7 +88,8 @@ static inline xfs_lsn_t       _lsn_cmp(xfs_lsn_t lsn1, xfs_lsn_t lsn2)
 #define XLOG_REG_TYPE_UNMOUNT          17
 #define XLOG_REG_TYPE_COMMIT           18
 #define XLOG_REG_TYPE_TRANSHDR         19
-#define XLOG_REG_TYPE_MAX              19
+#define XLOG_REG_TYPE_ICREATE          20
+#define XLOG_REG_TYPE_MAX              20
 
 typedef struct xfs_log_iovec {
        void            *i_addr;        /* beginning address of region */
index 14924099bcb8e7d8daff1ae2e4fd95f669529a55..30ef68f8a390d2cbfe6e96971dbadd5ca887fa8c 100644 (file)
@@ -51,6 +51,7 @@
 #include "xfs_inode_item.h"
 #include "xfs_icache.h"
 #include "xfs_trace.h"
+#include "xfs_icreate_item.h"
 
 #include <linux/namei.h>
 #include <linux/init.h>
@@ -1650,9 +1651,15 @@ xfs_init_zones(void)
                                        KM_ZONE_SPREAD, NULL);
        if (!xfs_ili_zone)
                goto out_destroy_inode_zone;
+       xfs_icreate_zone = kmem_zone_init(sizeof(struct xfs_icreate_item),
+                                       "xfs_icr");
+       if (!xfs_icreate_zone)
+               goto out_destroy_ili_zone;
 
        return 0;
 
+ out_destroy_ili_zone:
+       kmem_zone_destroy(xfs_ili_zone);
  out_destroy_inode_zone:
        kmem_zone_destroy(xfs_inode_zone);
  out_destroy_efi_zone:
@@ -1691,6 +1698,7 @@ xfs_destroy_zones(void)
         * destroy caches.
         */
        rcu_barrier();
+       kmem_zone_destroy(xfs_icreate_zone);
        kmem_zone_destroy(xfs_ili_zone);
        kmem_zone_destroy(xfs_inode_zone);
        kmem_zone_destroy(xfs_efi_zone);
index 822570ec605ac3f14da0d12a9a7a204e6a2da4e1..2b4946393e30f56655e55c782813778760846f79 100644 (file)
@@ -48,6 +48,7 @@ typedef struct xfs_trans_header {
 #define        XFS_LI_BUF              0x123c  /* v2 bufs, variable sized inode bufs */
 #define        XFS_LI_DQUOT            0x123d
 #define        XFS_LI_QUOTAOFF         0x123e
+#define        XFS_LI_ICREATE          0x123f
 
 #define XFS_LI_TYPE_DESC \
        { XFS_LI_EFI,           "XFS_LI_EFI" }, \
@@ -107,7 +108,8 @@ typedef struct xfs_trans_header {
 #define        XFS_TRANS_SWAPEXT               40
 #define        XFS_TRANS_SB_COUNT              41
 #define        XFS_TRANS_CHECKPOINT            42
-#define        XFS_TRANS_TYPE_MAX              42
+#define        XFS_TRANS_ICREATE               43
+#define        XFS_TRANS_TYPE_MAX              43
 /* new transaction types need to be reflected in xfs_logprint(8) */
 
 #define XFS_TRANS_TYPES \