]> git.proxmox.com Git - mirror_zfs.git/blobdiff - include/sys/dnode.h
Add support for user/group dnode accounting & quota
[mirror_zfs.git] / include / sys / dnode.h
index 8a72722eb2798cc756c7976bdb04aa25b51df56b..fe4cd3e4bf375338dde06a181dc5531b7ce1c34f 100644 (file)
@@ -20,7 +20,8 @@
  */
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2016 by Delphix. All rights reserved.
+ * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
  */
 
 #ifndef        _SYS_DNODE_H
@@ -56,7 +57,13 @@ extern "C" {
  * Fixed constants.
  */
 #define        DNODE_SHIFT             9       /* 512 bytes */
-#define        DN_MIN_INDBLKSHIFT      10      /* 1k */
+#define        DN_MIN_INDBLKSHIFT      12      /* 4k */
+/*
+ * If we ever increase this value beyond 20, we need to revisit all logic that
+ * does x << level * ebps to handle overflow.  With a 1M indirect block size,
+ * 4 levels of indirect blocks would not be able to guarantee addressing an
+ * entire object, so 5 levels will be used, but 5 * (20 - 7) = 65.
+ */
 #define        DN_MAX_INDBLKSHIFT      14      /* 16k */
 #define        DNODE_BLOCK_SHIFT       14      /* 16k */
 #define        DNODE_CORE_SIZE         64      /* 64 bytes for dnode sans blkptrs */
@@ -78,11 +85,18 @@ extern "C" {
 /*
  * Derived constants.
  */
-#define        DNODE_SIZE      (1 << DNODE_SHIFT)
-#define        DN_MAX_NBLKPTR  ((DNODE_SIZE - DNODE_CORE_SIZE) >> SPA_BLKPTRSHIFT)
-#define        DN_MAX_BONUSLEN (DNODE_SIZE - DNODE_CORE_SIZE - (1 << SPA_BLKPTRSHIFT))
+#define        DNODE_MIN_SIZE          (1 << DNODE_SHIFT)
+#define        DNODE_MAX_SIZE          (1 << DNODE_BLOCK_SHIFT)
+#define        DNODE_BLOCK_SIZE        (1 << DNODE_BLOCK_SHIFT)
+#define        DNODE_MIN_SLOTS         (DNODE_MIN_SIZE >> DNODE_SHIFT)
+#define        DNODE_MAX_SLOTS         (DNODE_MAX_SIZE >> DNODE_SHIFT)
+#define        DN_BONUS_SIZE(dnsize)   ((dnsize) - DNODE_CORE_SIZE - \
+       (1 << SPA_BLKPTRSHIFT))
+#define        DN_SLOTS_TO_BONUSLEN(slots)     DN_BONUS_SIZE((slots) << DNODE_SHIFT)
+#define        DN_OLD_MAX_BONUSLEN     (DN_BONUS_SIZE(DNODE_MIN_SIZE))
+#define        DN_MAX_NBLKPTR  ((DNODE_MIN_SIZE - DNODE_CORE_SIZE) >> SPA_BLKPTRSHIFT)
 #define        DN_MAX_OBJECT   (1ULL << DN_MAX_OBJECT_SHIFT)
-#define        DN_ZERO_BONUSLEN        (DN_MAX_BONUSLEN + 1)
+#define        DN_ZERO_BONUSLEN        (DN_BONUS_SIZE(DNODE_MAX_SIZE) + 1)
 #define        DN_KILL_SPILLBLK (1)
 
 #define        DNODES_PER_BLOCK_SHIFT  (DNODE_BLOCK_SHIFT - DNODE_SHIFT)
@@ -90,9 +104,8 @@ extern "C" {
 #define        DNODES_PER_LEVEL_SHIFT  (DN_MAX_INDBLKSHIFT - SPA_BLKPTRSHIFT)
 #define        DNODES_PER_LEVEL        (1ULL << DNODES_PER_LEVEL_SHIFT)
 
-/* The +2 here is a cheesy way to round up */
-#define        DN_MAX_LEVELS   (2 + ((DN_MAX_OFFSET_SHIFT - SPA_MINBLOCKSHIFT) / \
-       (DN_MIN_INDBLKSHIFT - SPA_BLKPTRSHIFT)))
+#define        DN_MAX_LEVELS   (DIV_ROUND_UP(DN_MAX_OFFSET_SHIFT - SPA_MINBLOCKSHIFT, \
+       DN_MIN_INDBLKSHIFT - SPA_BLKPTRSHIFT) + 1)
 
 #define        DN_BONUS(dnp)   ((void*)((dnp)->dn_bonus + \
        (((dnp)->dn_nblkptr - 1) * sizeof (blkptr_t))))
@@ -113,11 +126,14 @@ enum dnode_dirtycontext {
 };
 
 /* Is dn_used in bytes?  if not, it's in multiples of SPA_MINBLOCKSIZE */
-#define        DNODE_FLAG_USED_BYTES           (1<<0)
-#define        DNODE_FLAG_USERUSED_ACCOUNTED   (1<<1)
+#define        DNODE_FLAG_USED_BYTES                   (1 << 0)
+#define        DNODE_FLAG_USERUSED_ACCOUNTED           (1 << 1)
 
 /* Does dnode have a SA spill blkptr in bonus? */
-#define        DNODE_FLAG_SPILL_BLKPTR (1<<2)
+#define        DNODE_FLAG_SPILL_BLKPTR                 (1 << 2)
+
+/* User/Group dnode accounting */
+#define        DNODE_FLAG_USEROBJUSED_ACCOUNTED        (1 << 3)
 
 typedef struct dnode_phys {
        uint8_t dn_type;                /* dmu_object_type_t */
@@ -130,7 +146,8 @@ typedef struct dnode_phys {
        uint8_t dn_flags;               /* DNODE_FLAG_* */
        uint16_t dn_datablkszsec;       /* data block size in 512b sectors */
        uint16_t dn_bonuslen;           /* length of dn_bonus */
-       uint8_t dn_pad2[4];
+       uint8_t dn_extra_slots;         /* # of subsequent slots consumed */
+       uint8_t dn_pad2[3];
 
        /* accounting is protected by dn_dirty_mtx */
        uint64_t dn_maxblkid;           /* largest allocated block ID */
@@ -139,8 +156,11 @@ typedef struct dnode_phys {
        uint64_t dn_pad3[4];
 
        /*
-        * The tail region is 448 bytes, and there are three ways to
-        * look at it.
+        * The tail region is 448 bytes for a 512 byte dnode, and
+        * correspondingly larger for larger dnode sizes. The spill
+        * block pointer, when present, is always at the end of the tail
+        * region. There are three ways this space may be used, using
+        * a 512 byte dnode for this diagram:
         *
         * 0       64      128     192     256     320     384     448 (offset)
         * +---------------+---------------+---------------+-------+
@@ -148,24 +168,28 @@ typedef struct dnode_phys {
         * +---------------+---------------+---------------+-------+
         * | dn_blkptr[0]  | dn_bonus[0..319]                      |
         * +---------------+-----------------------+---------------+
-        * | dn_blkptr[0]  | /                     | dn_spill      |
+        * | dn_blkptr[0]  | dn_bonus[0..191]      | dn_spill      |
         * +---------------+-----------------------+---------------+
         */
        union {
-               blkptr_t dn_blkptr[1+DN_MAX_BONUSLEN/sizeof (blkptr_t)];
+               blkptr_t dn_blkptr[1+DN_OLD_MAX_BONUSLEN/sizeof (blkptr_t)];
                struct {
                        blkptr_t __dn_ignore1;
-                       uint8_t dn_bonus[DN_MAX_BONUSLEN];
+                       uint8_t dn_bonus[DN_OLD_MAX_BONUSLEN];
                };
                struct {
                        blkptr_t __dn_ignore2;
-                       uint8_t __dn_ignore3[DN_MAX_BONUSLEN-sizeof (blkptr_t)];
+                       uint8_t __dn_ignore3[DN_OLD_MAX_BONUSLEN -
+                           sizeof (blkptr_t)];
                        blkptr_t dn_spill;
                };
        };
 } dnode_phys_t;
 
-typedef struct dnode {
+#define        DN_SPILL_BLKPTR(dnp)    (blkptr_t *)((char *)(dnp) + \
+       (((dnp)->dn_extra_slots + 1) << DNODE_SHIFT) - (1 << SPA_BLKPTRSHIFT))
+
+struct dnode {
        /*
         * Protects the structure of the dnode, including the number of levels
         * of indirection (dn_nlevels), dn_maxblkid, and dn_next_*
@@ -201,6 +225,7 @@ typedef struct dnode {
        uint32_t dn_datablksz;          /* in bytes */
        uint64_t dn_maxblkid;
        uint8_t dn_next_type[TXG_SIZE];
+       uint8_t dn_num_slots;           /* metadnode slots consumed on disk */
        uint8_t dn_next_nblkptr[TXG_SIZE];
        uint8_t dn_next_nlevels[TXG_SIZE];
        uint8_t dn_next_indblkshift[TXG_SIZE];
@@ -233,7 +258,18 @@ typedef struct dnode {
        refcount_t dn_holds;
 
        kmutex_t dn_dbufs_mtx;
-       avl_tree_t dn_dbufs;            /* descendent dbufs */
+       /*
+        * Descendent dbufs, ordered by dbuf_compare. Note that dn_dbufs
+        * can contain multiple dbufs of the same (level, blkid) when a
+        * dbuf is marked DB_EVICTING without being removed from
+        * dn_dbufs. To maintain the avl invariant that there cannot be
+        * duplicate entries, we order the dbufs by an arbitrary value -
+        * their address in memory. This means that dn_dbufs cannot be used to
+        * directly look up a dbuf. Instead, callers must use avl_walk, have
+        * a reference to the dbuf, or look up a non-existant node with
+        * db_state = DB_SEARCH (see dbuf_free_range for an example).
+        */
+       avl_tree_t dn_dbufs;
 
        /* protected by dn_struct_rwlock */
        struct dmu_buf_impl *dn_bonus;  /* bonus buffer dbuf */
@@ -252,7 +288,7 @@ typedef struct dnode {
 
        /* holds prefetch structure */
        struct zfetch   dn_zfetch;
-} dnode_t;
+};
 
 /*
  * Adds a level of indirection between the dbuf and the dnode to avoid
@@ -266,8 +302,9 @@ typedef struct dnode_handle {
 } dnode_handle_t;
 
 typedef struct dnode_children {
+       dmu_buf_user_t dnc_dbu;         /* User evict data */
        size_t dnc_count;               /* number of children */
-       dnode_handle_t dnc_children[1]; /* sized dynamically */
+       dnode_handle_t dnc_children[];  /* sized dynamically */
 } dnode_children_t;
 
 typedef struct free_range {
@@ -276,7 +313,7 @@ typedef struct free_range {
        uint64_t fr_nblks;
 } free_range_t;
 
-dnode_t *dnode_special_open(struct objset *dd, dnode_phys_t *dnp,
+void dnode_special_open(struct objset *dd, dnode_phys_t *dnp,
     uint64_t object, dnode_handle_t *dnh);
 void dnode_special_close(dnode_handle_t *dnh);
 
@@ -286,7 +323,7 @@ void dnode_rm_spill(dnode_t *dn, dmu_tx_t *tx);
 
 int dnode_hold(struct objset *dd, uint64_t object,
     void *ref, dnode_t **dnp);
-int dnode_hold_impl(struct objset *dd, uint64_t object, int flag,
+int dnode_hold_impl(struct objset *dd, uint64_t object, int flag, int dn_slots,
     void *ref, dnode_t **dnp);
 boolean_t dnode_add_ref(dnode_t *dn, void *ref);
 void dnode_rele(dnode_t *dn, void *ref);
@@ -294,9 +331,9 @@ void dnode_rele_and_unlock(dnode_t *dn, void *tag);
 void dnode_setdirty(dnode_t *dn, dmu_tx_t *tx);
 void dnode_sync(dnode_t *dn, dmu_tx_t *tx);
 void dnode_allocate(dnode_t *dn, dmu_object_type_t ot, int blocksize, int ibs,
-    dmu_object_type_t bonustype, int bonuslen, dmu_tx_t *tx);
+    dmu_object_type_t bonustype, int bonuslen, int dn_slots, dmu_tx_t *tx);
 void dnode_reallocate(dnode_t *dn, dmu_object_type_t ot, int blocksize,
-    dmu_object_type_t bonustype, int bonuslen, dmu_tx_t *tx);
+    dmu_object_type_t bonustype, int bonuslen, int dn_slots, dmu_tx_t *tx);
 void dnode_free(dnode_t *dn, dmu_tx_t *tx);
 void dnode_byteswap(dnode_phys_t *dnp);
 void dnode_buf_byteswap(void *buf, size_t size);
@@ -314,6 +351,15 @@ int dnode_next_offset(dnode_t *dn, int flags, uint64_t *off,
 void dnode_evict_dbufs(dnode_t *dn);
 void dnode_evict_bonus(dnode_t *dn);
 
+#define        DNODE_IS_CACHEABLE(_dn)                                         \
+       ((_dn)->dn_objset->os_primary_cache == ZFS_CACHE_ALL ||         \
+       (DMU_OT_IS_METADATA((_dn)->dn_type) &&                          \
+       (_dn)->dn_objset->os_primary_cache == ZFS_CACHE_METADATA))
+
+#define        DNODE_META_IS_CACHEABLE(_dn)                                    \
+       ((_dn)->dn_objset->os_primary_cache == ZFS_CACHE_ALL ||         \
+       (_dn)->dn_objset->os_primary_cache == ZFS_CACHE_METADATA)
+
 #ifdef ZFS_DEBUG
 
 /*