Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/fs/udf First part of shrinking/growing metadata partitio...



details:   https://anonhg.NetBSD.org/src/rev/2ebb35bd22ba
branches:  trunk
changeset: 752416:2ebb35bd22ba
user:      reinoud <reinoud%NetBSD.org@localhost>
date:      Thu Feb 25 16:15:57 2010 +0000

description:
First part of shrinking/growing metadata partition support:

- extending the metadata partition

Still to follow:
- sparsify metadata partition
- growing the metadata partition
- unsparsifying metadata partition

diffstat:

 sys/fs/udf/udf.h            |    5 +-
 sys/fs/udf/udf_allocation.c |  284 ++++++++++++++++++++++++++++++++++++++++++-
 sys/fs/udf/udf_subr.c       |   27 +++-
 sys/fs/udf/udf_subr.h       |    3 +-
 4 files changed, 306 insertions(+), 13 deletions(-)

diffs (truncated from 434 to 300 lines):

diff -r ea01fae0de9b -r 2ebb35bd22ba sys/fs/udf/udf.h
--- a/sys/fs/udf/udf.h  Thu Feb 25 15:07:06 2010 +0000
+++ b/sys/fs/udf/udf.h  Thu Feb 25 16:15:57 2010 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: udf.h,v 1.40 2010/02/24 19:20:13 reinoud Exp $ */
+/* $NetBSD: udf.h,v 1.41 2010/02/25 16:15:57 reinoud Exp $ */
 
 /*
  * Copyright (c) 2006, 2008 Reinoud Zandijk
@@ -190,9 +190,10 @@
 #define UDF_WRITE_LVINT                  0x10  /* write out open lvint              */
 #define UDF_WRITE_PART_BITMAPS   0x20  /* write out partition space bitmaps */
 #define UDF_APPENDONLY_LVINT     0x40  /* no shifting, only appending       */
+#define UDF_WRITE_METAPART_NODES  0x80 /* write out metadata partition nodes*/
 #define UDFLOGVOL_BITS "\20\1OPEN_SESSION\2CLOSE_SESSION\3FINALISE_DISC" \
                        "\4WRITE_VAT\5WRITE_LVINT\6WRITE_PART_BITMAPS" \
-                       "\7APPENDONLY_LVINT"
+                       "\7APPENDONLY_LVINT\10WRITE_METAPART_NODES"
 
 /* logical volume error handling actions */
 #define UDF_UPDATE_TRACKINFO     0x01  /* update trackinfo and re-shedule   */
diff -r ea01fae0de9b -r 2ebb35bd22ba sys/fs/udf/udf_allocation.c
--- a/sys/fs/udf/udf_allocation.c       Thu Feb 25 15:07:06 2010 +0000
+++ b/sys/fs/udf/udf_allocation.c       Thu Feb 25 16:15:57 2010 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: udf_allocation.c,v 1.27 2009/06/27 13:42:06 reinoud Exp $ */
+/* $NetBSD: udf_allocation.c,v 1.28 2010/02/25 16:15:57 reinoud Exp $ */
 
 /*
  * Copyright (c) 2006, 2008 Reinoud Zandijk
@@ -28,7 +28,7 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__KERNEL_RCSID(0, "$NetBSD: udf_allocation.c,v 1.27 2009/06/27 13:42:06 reinoud Exp $");
+__KERNEL_RCSID(0, "$NetBSD: udf_allocation.c,v 1.28 2010/02/25 16:15:57 reinoud Exp $");
 #endif /* not lint */
 
 
@@ -73,6 +73,12 @@
        struct buf *buf, uint16_t vpart_num, uint64_t *mapping,
        struct long_ad *node_ad_cpy);
 
+static void udf_collect_free_space_for_vpart(struct udf_mount *ump,
+       uint16_t vpart_num, uint32_t num_lb);
+
+static void udf_wipe_adslots(struct udf_node *udf_node);
+static void udf_count_alloc_exts(struct udf_node *udf_node);
+
 /*
  * IDEA/BUSY: Each udf_node gets its own extentwalker state for all operations;
  * this will hopefully/likely reduce O(nlog(n)) to O(1) for most functionality
@@ -449,7 +455,11 @@
        }
 
        /* adjust for accounted uncommitted blocks */
-       *freeblks -= ump->uncommitted_lbs[vpart_num];
+       if (*freeblks > ump->uncommitted_lbs[vpart_num]) {
+               *freeblks -= ump->uncommitted_lbs[vpart_num];
+       } else {
+               *freeblks = 0;
+       }
 }
 
 /* --------------------------------------------------------------------- */
@@ -984,6 +994,38 @@
        }
 }
 
+
+static uint32_t
+udf_bitmap_check_trunc_free(struct udf_bitmap *bitmap, uint32_t to_trunc)
+{
+       uint32_t seq_free, offset;
+       uint8_t *bpos;
+       uint8_t  bit, bitval;
+
+       DPRINTF(RESERVE, ("\ttrying to trunc %d bits from bitmap\n", to_trunc));
+       offset = bitmap->max_offset - to_trunc;
+
+       /* starter bits (if any) */
+       bpos = bitmap->bits + offset/8;
+       bit = offset % 8;
+       seq_free = 0;
+       while (to_trunc > 0) {
+               seq_free++;
+               bitval = (1 << bit);
+               if (!(*bpos & bitval))
+                       seq_free = 0;
+               offset++; to_trunc--;
+               bit++;
+               if (bit == 8) {
+                       bpos++;
+                       bit = 0;
+               }
+       }
+
+       DPRINTF(RESERVE, ("\tfound %d sequential free bits in bitmap\n", seq_free));
+       return seq_free;
+}
+
 /* --------------------------------------------------------------------- */
 
 /*
@@ -1047,7 +1089,7 @@
        mutex_enter(&ump->allocate_mutex);
 
        /* check if there is enough space available */
-       for (i = 0; i < 16; i++) {      /* XXX arbitrary number */
+       for (i = 0; i < 3; i++) {       /* XXX arbitrary number */
                udf_calc_vpart_freespace(ump, vpart_num, &freeblks);
                if (num_lb + slack < freeblks)
                        break;
@@ -1056,9 +1098,9 @@
                mutex_exit(&ump->allocate_mutex);
                udf_do_sync(ump, FSCRED, 0);
                mutex_enter(&mntvnode_lock);
-               /* 1/4 second wait */
+               /* 1/8 second wait */
                cv_timedwait(&ump->dirtynodes_cv, &mntvnode_lock,
-                       hz/4);
+                       hz/8);
                mutex_exit(&mntvnode_lock);
                mutex_enter(&ump->allocate_mutex);
        }
@@ -1066,8 +1108,12 @@
        /* check if there is enough space available now */
        udf_calc_vpart_freespace(ump, vpart_num, &freeblks);
        if (num_lb + slack >= freeblks) {
-               DPRINTF(RESERVE, ("udf_reserve_space: try to juggle partitions\n"));
-               /* TODO juggle with data and metadata partitions if possible */
+               DPRINTF(RESERVE, ("udf_reserve_space: try to redistribute "
+                                 "partition space\n"));
+               DPRINTF(RESERVE, ("\tvpart %d, type %d is full\n",
+                               vpart_num, ump->vtop_alloc[vpart_num]));
+               /* Try to redistribute space if possible */
+               udf_collect_free_space_for_vpart(ump, vpart_num, num_lb + slack);
        }
 
        /* check if there is enough space available now */
@@ -1356,6 +1402,228 @@
 /* --------------------------------------------------------------------- */
 
 /*
+ * Special function to synchronise the metadatamirror file when they change on
+ * resizing. When the metadatafile is actually duplicated, this action is a
+ * no-op since they describe different extents on the disc.
+ */
+
+void udf_synchronise_metadatamirror_node(struct udf_mount *ump)
+{
+       struct udf_node *meta_node, *metamirror_node;
+       struct long_ad s_ad;
+       int slot, cpy_slot;
+       int error, eof;
+
+       if (ump->metadata_flags & METADATA_DUPLICATED)
+               return;
+
+       meta_node       = ump->metadata_node;
+       metamirror_node = ump->metadatamirror_node;
+
+       /* 1) wipe mirror node */
+       udf_wipe_adslots(metamirror_node);
+
+       /* 2) copy all node descriptors from the meta_node */
+       slot     = 0;
+       cpy_slot = 0;
+       for (;;) {
+               udf_get_adslot(meta_node, slot, &s_ad, &eof);
+               if (eof)
+                       break;
+               error = udf_append_adslot(metamirror_node, &cpy_slot, &s_ad);
+               if (error) {
+                       /* WTF, this shouldn't happen, what to do now? */
+                       panic("udf_synchronise_metadatamirror_node failed!");
+               }
+               slot++;
+       }
+
+       /* 3) adjust metamirror_node size */
+       if (meta_node->fe) {
+               KASSERT(metamirror_node->fe);
+               metamirror_node->fe->inf_len = meta_node->fe->inf_len;
+       } else {
+               KASSERT(meta_node->efe);
+               KASSERT(metamirror_node->efe);
+               metamirror_node->efe->inf_len  = meta_node->efe->inf_len;
+               metamirror_node->efe->obj_size = meta_node->efe->obj_size;
+       }
+
+       /* for sanity */
+       udf_count_alloc_exts(metamirror_node);
+}
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * When faced with an out of space but there is still space available on other
+ * partitions, try to redistribute the space. This is only defined for media
+ * using Metadata partitions.
+ *
+ * There are two formats to deal with. Either its a `normal' metadata
+ * partition and we can move blocks between a metadata bitmap and its
+ * companion data spacemap OR its a UDF 2.60 formatted BluRay-R disc with POW
+ * and a metadata partition.
+ */
+
+static uint32_t
+udf_trunc_metadatapart(struct udf_mount *ump, uint32_t num_lb)
+{
+       struct udf_node *bitmap_node;
+       struct udf_bitmap *bitmap;
+       struct space_bitmap_desc *sbd, *new_sbd;
+       struct logvol_int_desc *lvid;
+       uint64_t inf_len;
+       uint64_t meta_free_lbs, data_free_lbs;
+       uint32_t *freepos, *sizepos;
+       uint32_t unit, lb_size, to_trunc;
+       uint16_t meta_vpart_num, data_vpart_num, num_vpart;
+       int err;
+
+       unit = ump->metadata_alloc_unit_size;
+       lb_size = udf_rw32(ump->logical_vol->lb_size);
+       lvid = ump->logvol_integrity;
+
+       /* lookup vpart for metadata partition */
+       meta_vpart_num = ump->node_part;
+       KASSERT(ump->vtop_alloc[meta_vpart_num] == UDF_ALLOC_METABITMAP);
+
+       /* lookup vpart for data partition */
+       data_vpart_num = ump->data_part;
+       KASSERT(ump->vtop_alloc[data_vpart_num] == UDF_ALLOC_SPACEMAP);
+
+       udf_calc_vpart_freespace(ump, data_vpart_num, &data_free_lbs);
+       udf_calc_vpart_freespace(ump, meta_vpart_num, &meta_free_lbs);
+
+       DPRINTF(RESERVE, ("\tfree space on data partition     %"PRIu64" blks\n", data_free_lbs));
+       DPRINTF(RESERVE, ("\tfree space on metadata partition %"PRIu64" blks\n", meta_free_lbs));
+
+       /* give away some of the free meta space, in unit block sizes */
+       to_trunc = meta_free_lbs/4;                     /* give out a quart */
+       to_trunc = MAX(to_trunc, num_lb);
+       to_trunc = unit * ((to_trunc + unit-1) / unit); /* round up */
+
+       /* scale down if needed and bail out when out of space */
+       if (to_trunc >= meta_free_lbs)
+               return num_lb;
+
+       /* check extent of bits marked free at the end of the map */
+       bitmap = &ump->metadata_unalloc_bits;
+       to_trunc = udf_bitmap_check_trunc_free(bitmap, to_trunc);
+       to_trunc = unit * (to_trunc / unit);            /* round down again */
+       if (to_trunc == 0)
+               return num_lb;
+
+       DPRINTF(RESERVE, ("\ttruncating %d lbs from the metadata bitmap\n",
+               to_trunc));
+
+       /* get length of the metadata bitmap node file */
+       bitmap_node = ump->metadatabitmap_node;
+       if (bitmap_node->fe) {
+               inf_len = udf_rw64(bitmap_node->fe->inf_len);
+       } else {
+               KASSERT(bitmap_node->efe);
+               inf_len = udf_rw64(bitmap_node->efe->inf_len);
+       }
+       inf_len -= to_trunc/8;
+
+       /* as per [UDF 2.60/2.2.13.6] : */
+       /* 1) update the SBD in the metadata bitmap file */
+       sbd = (struct space_bitmap_desc *) bitmap->blob;
+       sbd->num_bits  = udf_rw32(sbd->num_bits)  - to_trunc;
+       sbd->num_bytes = udf_rw32(sbd->num_bytes) - to_trunc/8;
+       bitmap->max_offset = udf_rw32(sbd->num_bits);
+
+
+       num_vpart = udf_rw32(lvid->num_part);
+       freepos = &lvid->tables[0] + meta_vpart_num;
+       sizepos = &lvid->tables[0] + num_vpart + meta_vpart_num;
+       *freepos = udf_rw32(*freepos) - to_trunc;
+       *sizepos = udf_rw32(*sizepos) - to_trunc;
+
+       /* realloc bitmap for better memory usage */
+       new_sbd = realloc(sbd, inf_len, M_UDFVOLD,
+               M_CANFAIL | M_WAITOK);
+       if (new_sbd) {
+               /* update pointers */
+               ump->metadata_unalloc_dscr = new_sbd;
+               bitmap->blob = (uint8_t *) new_sbd;
+       }
+       ump->lvclose |= UDF_WRITE_PART_BITMAPS;
+
+       /*
+        * The truncated space is secured now and can't be allocated anymore. Release
+        * the allocate mutex so we can shrink the nodes the normal way.
+        */
+       mutex_exit(&ump->allocate_mutex);
+
+       /* 2) trunc the metadata bitmap information file, freeing blocks */



Home | Main Index | Thread Index | Old Index