Module Name: src
Committed By: reinoud
Date: Wed Jun 24 17:09:14 UTC 2009
Modified Files:
src/sys/fs/udf: udf.h udf_allocation.c udf_subr.c udf_subr.h
udf_vfsops.c udf_vnops.c
Log Message:
Commit first stage of free-space accounting. It is estimating the underlimit
of free blocks on the device and when free blocks are getting tight it tries
to readjust/recalculate that value by syncing the FS.
Second stage will be resizing the data/metadata partitions.
To generate a diff of this commit:
cvs rdiff -u -r1.33 -r1.34 src/sys/fs/udf/udf.h
cvs rdiff -u -r1.25 -r1.26 src/sys/fs/udf/udf_allocation.c
cvs rdiff -u -r1.94 -r1.95 src/sys/fs/udf/udf_subr.c
cvs rdiff -u -r1.14 -r1.15 src/sys/fs/udf/udf_subr.h
cvs rdiff -u -r1.56 -r1.57 src/sys/fs/udf/udf_vfsops.c
cvs rdiff -u -r1.45 -r1.46 src/sys/fs/udf/udf_vnops.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/fs/udf/udf.h
diff -u src/sys/fs/udf/udf.h:1.33 src/sys/fs/udf/udf.h:1.34
--- src/sys/fs/udf/udf.h:1.33 Tue Jun 23 20:13:37 2009
+++ src/sys/fs/udf/udf.h Wed Jun 24 17:09:13 2009
@@ -1,4 +1,4 @@
-/* $NetBSD: udf.h,v 1.33 2009/06/23 20:13:37 reinoud Exp $ */
+/* $NetBSD: udf.h,v 1.34 2009/06/24 17:09:13 reinoud Exp $ */
/*
* Copyright (c) 2006, 2008 Reinoud Zandijk
@@ -124,6 +124,7 @@
#define UDF_VAT_CHUNKSIZE (64*1024) /* picked */
#define UDF_SYMLINKBUFLEN (64*1024) /* picked */
+#define UDF_DISC_SLACK (128) /* picked, at least 64 kb or 128 */
#define UDF_ISO_VRS_SIZE (32*2048) /* 32 ISO `sectors' */
@@ -340,7 +341,7 @@
kcondvar_t dirtynodes_cv; /* sleeping on sync */
/* late allocation */
- uint32_t uncomitted_lb; /* for free space */
+ int32_t uncommitted_lbs[UDF_PARTITIONS];
struct long_ad *la_node_ad_cpy; /* issue buf */
uint64_t *la_lmapping, *la_pmapping; /* issue buf */
@@ -387,6 +388,7 @@
struct lockf *lockf; /* lock list */
uint32_t outstanding_bufs; /* file data */
uint32_t outstanding_nodedscr; /* node dscr */
+ int32_t uncommitted_lbs; /* in UBC */
/* references to associated nodes */
struct udf_node *extattr;
Index: src/sys/fs/udf/udf_allocation.c
diff -u src/sys/fs/udf/udf_allocation.c:1.25 src/sys/fs/udf/udf_allocation.c:1.26
--- src/sys/fs/udf/udf_allocation.c:1.25 Thu Jun 18 15:09:18 2009
+++ src/sys/fs/udf/udf_allocation.c Wed Jun 24 17:09:13 2009
@@ -1,4 +1,4 @@
-/* $NetBSD: udf_allocation.c,v 1.25 2009/06/18 15:09:18 reinoud Exp $ */
+/* $NetBSD: udf_allocation.c,v 1.26 2009/06/24 17:09:13 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.25 2009/06/18 15:09:18 reinoud Exp $");
+__KERNEL_RCSID(0, "$NetBSD: udf_allocation.c,v 1.26 2009/06/24 17:09:13 reinoud Exp $");
#endif /* not lint */
@@ -367,6 +367,93 @@
/* --------------------------------------------------------------------- */
+void
+udf_calc_freespace(struct udf_mount *ump, uint64_t *sizeblks, uint64_t *freeblks)
+{
+ struct logvol_int_desc *lvid;
+ uint32_t *pos1, *pos2;
+ int vpart, num_vpart;
+
+ lvid = ump->logvol_integrity;
+ *freeblks = *sizeblks = 0;
+
+ /*
+ * Sequentials media report free space directly (CD/DVD/BD-R), for the
+ * other media we need the logical volume integrity.
+ *
+ * We sum all free space up here regardless of type.
+ */
+
+ KASSERT(lvid);
+ num_vpart = udf_rw32(lvid->num_part);
+
+ if (ump->discinfo.mmc_cur & MMC_CAP_SEQUENTIAL) {
+ /* use track info directly summing if there are 2 open */
+ /* XXX assumption at most two tracks open */
+ *freeblks = ump->data_track.free_blocks;
+ if (ump->data_track.tracknr != ump->metadata_track.tracknr)
+ *freeblks += ump->metadata_track.free_blocks;
+ *sizeblks = ump->discinfo.last_possible_lba;
+ } else {
+ /* free and used space for mountpoint based on logvol integrity */
+ for (vpart = 0; vpart < num_vpart; vpart++) {
+ pos1 = &lvid->tables[0] + vpart;
+ pos2 = &lvid->tables[0] + num_vpart + vpart;
+ if (udf_rw32(*pos1) != (uint32_t) -1) {
+ *freeblks += udf_rw32(*pos1);
+ *sizeblks += udf_rw32(*pos2);
+ }
+ }
+ }
+ /* adjust for accounted uncommitted blocks */
+ for (vpart = 0; vpart < num_vpart; vpart++)
+ *freeblks -= ump->uncommitted_lbs[vpart];
+
+ if (*freeblks > UDF_DISC_SLACK) {
+ *freeblks -= UDF_DISC_SLACK;
+ } else {
+ *freeblks = 0;
+ }
+}
+
+
+static void
+udf_calc_vpart_freespace(struct udf_mount *ump, uint16_t vpart_num, uint64_t *freeblks)
+{
+ struct logvol_int_desc *lvid;
+ uint32_t *pos1;
+
+ lvid = ump->logvol_integrity;
+ *freeblks = 0;
+
+ /*
+ * Sequentials media report free space directly (CD/DVD/BD-R), for the
+ * other media we need the logical volume integrity.
+ *
+ * We sum all free space up here regardless of type.
+ */
+
+ KASSERT(lvid);
+ if (ump->discinfo.mmc_cur & MMC_CAP_SEQUENTIAL) {
+ /* XXX assumption at most two tracks open */
+ if (vpart_num == ump->data_part) {
+ *freeblks = ump->data_track.free_blocks;
+ } else {
+ *freeblks = ump->metadata_track.free_blocks;
+ }
+ } else {
+ /* free and used space for mountpoint based on logvol integrity */
+ pos1 = &lvid->tables[0] + vpart_num;
+ if (udf_rw32(*pos1) != (uint32_t) -1)
+ *freeblks += udf_rw32(*pos1);
+ }
+
+ /* adjust for accounted uncommitted blocks */
+ *freeblks -= ump->uncommitted_lbs[vpart_num];
+}
+
+/* --------------------------------------------------------------------- */
+
int
udf_translate_vtop(struct udf_mount *ump, struct long_ad *icb_loc,
uint32_t *lb_numres, uint32_t *extres)
@@ -897,11 +984,139 @@
}
}
+/* --------------------------------------------------------------------- */
-/* allocate a contiguous sequence of sectornumbers */
-static int
-udf_allocate_space(struct udf_mount *ump, int udf_c_type,
- uint16_t vpart_num, uint32_t num_lb, uint64_t *lmapping)
+/*
+ * We check for overall disc space with a margin to prevent critical
+ * conditions. If disc space is low we try to force a sync() to improve our
+ * estimates. When confronted with meta-data partition size shortage we know
+ * we have to check if it can be extended and we need to extend it when
+ * needed.
+ *
+ * A 2nd strategy we could use when disc space is getting low on a disc
+ * formatted with a meta-data partition is to see if there are sparse areas in
+ * the meta-data partition and free blocks there for extra data.
+ */
+
+void
+udf_do_reserve_space(struct udf_mount *ump, struct udf_node *udf_node,
+ uint16_t vpart_num, uint32_t num_lb)
+{
+ ump->uncommitted_lbs[vpart_num] += num_lb;
+ if (udf_node)
+ udf_node->uncommitted_lbs += num_lb;
+}
+
+
+void
+udf_do_unreserve_space(struct udf_mount *ump, struct udf_node *udf_node,
+ uint16_t vpart_num, uint32_t num_lb)
+{
+ ump->uncommitted_lbs[vpart_num] -= num_lb;
+ if (ump->uncommitted_lbs[vpart_num] < 0) {
+ DPRINTF(RESERVE, ("UDF: underflow on partition reservation, "
+ "part %d: %d\n", vpart_num,
+ ump->uncommitted_lbs[vpart_num]));
+ ump->uncommitted_lbs[vpart_num] = 0;
+ }
+ if (udf_node) {
+ udf_node->uncommitted_lbs -= num_lb;
+ if (udf_node->uncommitted_lbs < 0) {
+ DPRINTF(RESERVE, ("UDF: underflow of node "
+ "reservation : %d\n",
+ udf_node->uncommitted_lbs));
+ udf_node->uncommitted_lbs = 0;
+ }
+ }
+}
+
+
+int
+udf_reserve_space(struct udf_mount *ump, struct udf_node *udf_node,
+ int udf_c_type, uint16_t vpart_num, uint32_t num_lb, int can_fail)
+{
+ uint64_t freeblks;
+ uint64_t slack;
+ int i, error;
+
+ slack = 0;
+ if (can_fail)
+ slack = UDF_DISC_SLACK;
+
+ error = 0;
+ mutex_enter(&ump->allocate_mutex);
+
+ /* check if there is enough space available */
+ for (i = 0; i < 16; i++) { /* XXX arbitrary number */
+ udf_calc_vpart_freespace(ump, vpart_num, &freeblks);
+ if (num_lb + slack < freeblks)
+ break;
+ /* issue SYNC */
+ DPRINTF(RESERVE, ("udf_reserve_space: issuing sync\n"));
+ mutex_exit(&ump->allocate_mutex);
+ udf_do_sync(ump, FSCRED, 0);
+ mutex_enter(&mntvnode_lock);
+ /* 1/4 second wait */
+ cv_timedwait(&ump->dirtynodes_cv, &mntvnode_lock,
+ hz/4);
+ mutex_exit(&mntvnode_lock);
+ mutex_enter(&ump->allocate_mutex);
+ }
+
+ /* 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 */
+ }
+
+ /* check if there is enough space available now */
+ udf_calc_vpart_freespace(ump, vpart_num, &freeblks);
+ if (num_lb + slack <= freeblks) {
+ udf_do_reserve_space(ump, udf_node, vpart_num, num_lb);
+ } else {
+ DPRINTF(RESERVE, ("udf_reserve_space: out of disc space\n"));
+ error = ENOSPC;
+ }
+
+ mutex_exit(&ump->allocate_mutex);
+ return error;
+}
+
+
+void
+udf_cleanup_reservation(struct udf_node *udf_node)
+{
+ struct udf_mount *ump = udf_node->ump;
+ int vpart_num;
+
+ mutex_enter(&ump->allocate_mutex);
+
+ /* compensate for overlapping blocks */
+ DPRINTF(RESERVE, ("UDF: overlapped %d blocks in count\n", udf_node->uncommitted_lbs));
+
+ vpart_num = udf_get_record_vpart(ump, udf_get_c_type(udf_node));
+ udf_do_unreserve_space(ump, udf_node, vpart_num, udf_node->uncommitted_lbs);
+
+ DPRINTF(RESERVE, ("\ttotal now %d\n", ump->uncommitted_lbs[vpart_num]));
+
+ /* sanity */
+ if (ump->uncommitted_lbs[vpart_num] < 0)
+ ump->uncommitted_lbs[vpart_num] = 0;
+
+ mutex_exit(&ump->allocate_mutex);
+}
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Allocate an extent of given length on given virt. partition. It doesn't
+ * have to be one stretch.
+ */
+
+int
+udf_allocate_space(struct udf_mount *ump, struct udf_node *udf_node,
+ int udf_c_type, uint16_t vpart_num, uint32_t num_lb, uint64_t *lmapping)
{
struct mmc_trackinfo *alloc_track, *other_track;
struct udf_bitmap *bitmap;
@@ -920,8 +1135,6 @@
lb_size = udf_rw32(ump->logical_vol->lb_size);
KASSERT(lb_size == ump->discinfo.sector_size);
- /* XXX TODO check disc space */
-
alloc_type = ump->vtop_alloc[vpart_num];
is_node = (udf_c_type == UDF_C_NODE);
@@ -932,8 +1145,14 @@
/* search empty slot in VAT file */
KASSERT(num_lb == 1);
error = udf_search_free_vatloc(ump, &lb_num);
- if (!error)
+ if (!error) {
*lmappos = lb_num;
+
+ /* reserve on the backing sequential partition since
+ * that partition is credited back later */
+ udf_do_reserve_space(ump, udf_node,
+ ump->vtop[vpart_num], num_lb);
+ }
break;
case UDF_ALLOC_SEQUENTIAL :
/* sequential allocation on recordable media */
@@ -1023,6 +1242,11 @@
break;
}
+ if (!error) {
+ /* credit our partition since we have committed the space */
+ udf_do_unreserve_space(ump, udf_node, vpart_num, num_lb);
+ }
+
#ifdef DEBUG
if (udf_verbose & UDF_DEBUG_ALLOC) {
lmappos = lmapping;
@@ -1131,24 +1355,6 @@
/* --------------------------------------------------------------------- */
-int
-udf_pre_allocate_space(struct udf_mount *ump, int udf_c_type,
- uint32_t num_lb, uint16_t vpartnr, uint64_t *lmapping)
-{
- /* TODO properly maintain uncomitted_lb per partition */
-
- /* reserve size for VAT allocated data */
- if (ump->vtop_alloc[vpartnr] == UDF_ALLOC_VAT) {
- mutex_enter(&ump->allocate_mutex);
- ump->uncomitted_lb += num_lb;
- mutex_exit(&ump->allocate_mutex);
- }
-
- return udf_allocate_space(ump, udf_c_type, vpartnr, num_lb, lmapping);
-}
-
-/* --------------------------------------------------------------------- */
-
/*
* Allocate a buf on disc for direct write out. The space doesn't have to be
* contiguous as the caller takes care of this.
@@ -1178,12 +1384,7 @@
KASSERT(lb_size == ump->discinfo.sector_size);
/* select partition to record the buffer on */
- vpart_num = ump->data_part;
- if (udf_c_type == UDF_C_NODE)
- vpart_num = ump->node_part;
- if (udf_c_type == UDF_C_FIDS)
- vpart_num = ump->fids_part;
- *vpart_nump = vpart_num;
+ vpart_num = *vpart_nump = udf_get_record_vpart(ump, udf_c_type);
if (udf_c_type == UDF_C_NODE) {
/* if not VAT, its allready allocated */
@@ -1194,23 +1395,18 @@
vpart_num = ump->data_part;
}
+ /* XXX can this still happen? */
/* do allocation on the selected partition */
- error = udf_allocate_space(ump, udf_c_type,
+ error = udf_allocate_space(ump, udf_node, udf_c_type,
vpart_num, num_lb, lmapping);
if (error) {
- /* ARGH! we've not done our accounting right! */
+ /*
+ * ARGH! we haven't done our accounting right! it should
+ * allways succeed.
+ */
panic("UDF disc allocation accounting gone wrong");
}
- /* commit our sector count */
- mutex_enter(&ump->allocate_mutex);
- if (num_lb > ump->uncomitted_lb) {
- ump->uncomitted_lb = 0;
- } else {
- ump->uncomitted_lb -= num_lb;
- }
- mutex_exit(&ump->allocate_mutex);
-
/* If its userdata or FIDs, record its allocation in its node. */
if ((udf_c_type == UDF_C_USERDATA) ||
(udf_c_type == UDF_C_FIDS) ||
@@ -1607,11 +1803,17 @@
if (ext == NULL) {
DPRINTF(ALLOC,("adding allocation extent %d\n", extnr));
- error = udf_pre_allocate_space(ump, UDF_C_NODE, 1,
- vpart_num, &lmapping);
+ error = udf_reserve_space(ump, NULL, UDF_C_NODE,
+ vpart_num, 1, /* can fail */ false);
+ if (error) {
+ printf("UDF: couldn't reserve space for AED!\n");
+ return error;
+ }
+ error = udf_allocate_space(ump, NULL, UDF_C_NODE,
+ vpart_num, 1, &lmapping);
lb_num = lmapping;
if (error)
- return error;
+ panic("UDF: couldn't allocate AED!\n");
/* initialise pointer to location */
memset(&l_icb, 0, sizeof(struct long_ad));
@@ -2150,7 +2352,7 @@
uint8_t *data_pos, *evacuated_data;
int addr_type;
int slot, cpy_slot;
- int isdir, eof, error;
+ int eof, error;
DPRINTF(ALLOC, ("udf_grow_node\n"));
@@ -2251,9 +2453,8 @@
}
/* convert to a normal alloc and select type */
- isdir = (vp->v_type == VDIR);
my_part = udf_rw16(udf_node->loc.loc.part_num);
- dst_part = isdir ? ump->fids_part : ump->data_part;
+ dst_part = udf_get_record_vpart(ump, udf_get_c_type(udf_node));
addr_type = UDF_ICB_SHORT_ALLOC;
if (dst_part != my_part)
addr_type = UDF_ICB_LONG_ALLOC;
Index: src/sys/fs/udf/udf_subr.c
diff -u src/sys/fs/udf/udf_subr.c:1.94 src/sys/fs/udf/udf_subr.c:1.95
--- src/sys/fs/udf/udf_subr.c:1.94 Tue Jun 23 20:09:07 2009
+++ src/sys/fs/udf/udf_subr.c Wed Jun 24 17:09:13 2009
@@ -1,4 +1,4 @@
-/* $NetBSD: udf_subr.c,v 1.94 2009/06/23 20:09:07 reinoud Exp $ */
+/* $NetBSD: udf_subr.c,v 1.95 2009/06/24 17:09:13 reinoud Exp $ */
/*
* Copyright (c) 2006, 2008 Reinoud Zandijk
@@ -29,7 +29,7 @@
#include <sys/cdefs.h>
#ifndef lint
-__KERNEL_RCSID(0, "$NetBSD: udf_subr.c,v 1.94 2009/06/23 20:09:07 reinoud Exp $");
+__KERNEL_RCSID(0, "$NetBSD: udf_subr.c,v 1.95 2009/06/24 17:09:13 reinoud Exp $");
#endif /* not lint */
@@ -953,6 +953,38 @@
/* --------------------------------------------------------------------- */
+int
+udf_get_c_type(struct udf_node *udf_node)
+{
+ int isdir, what;
+
+ isdir = (udf_node->vnode->v_type == VDIR);
+ what = isdir ? UDF_C_FIDS : UDF_C_USERDATA;
+
+ if (udf_node->ump)
+ if (udf_node == udf_node->ump->metadatabitmap_node)
+ what = UDF_C_METADATA_SBM;
+
+ return what;
+}
+
+
+int
+udf_get_record_vpart(struct udf_mount *ump, int udf_c_type)
+{
+ int vpart_num;
+
+ vpart_num = ump->data_part;
+ if (udf_c_type == UDF_C_NODE)
+ vpart_num = ump->node_part;
+ if (udf_c_type == UDF_C_FIDS)
+ vpart_num = ump->fids_part;
+
+ return vpart_num;
+}
+
+/* --------------------------------------------------------------------- */
+
/* we dont try to be smart; we just record the parts */
#define UDF_UPDATE_DSCR(name, dscr) \
if (name) \
@@ -2776,7 +2808,7 @@
DPRINTF(CALL, ("udf_writeout_vat\n"));
- mutex_enter(&ump->allocate_mutex);
+// mutex_enter(&ump->allocate_mutex);
udf_update_vat_descriptor(ump);
/* write out the VAT contents ; TODO intelligent writing */
@@ -2789,7 +2821,7 @@
goto out;
}
- mutex_exit(&ump->allocate_mutex);
+// mutex_exit(&ump->allocate_mutex);
vflushbuf(ump->vat_node->vnode, 1 /* sync */);
error = VOP_FSYNC(ump->vat_node->vnode,
@@ -3898,24 +3930,53 @@
*/
/*
- * Callback from genfs to allocate len bytes at offset off; only called when
- * filling up gaps in the allocation.
+ * Called for allocating an extent of the file either by VOP_WRITE() or by
+ * genfs filling up gaps.
*/
-/* XXX should we check if there is space enough in udf_gop_alloc? */
static int
udf_gop_alloc(struct vnode *vp, off_t off,
off_t len, int flags, kauth_cred_t cred)
{
-#if 0
struct udf_node *udf_node = VTOI(vp);
struct udf_mount *ump = udf_node->ump;
+ uint64_t lb_start, lb_end;
uint32_t lb_size, num_lb;
-#endif
+ int udf_c_type, vpart_num, can_fail;
+ int error;
- DPRINTF(NOTIMPL, ("udf_gop_alloc not implemented\n"));
- DPRINTF(ALLOC, ("udf_gop_alloc called for %"PRIu64" bytes\n", len));
+ DPRINTF(ALLOC, ("udf_gop_alloc called for offset %"PRIu64" for %"PRIu64" bytes, %s\n",
+ off, len, flags? "SYNC":"NONE"));
- return 0;
+ /*
+ * request the pages of our vnode and see how many pages will need to
+ * be allocated and reserve that space
+ */
+ lb_size = udf_rw32(udf_node->ump->logical_vol->lb_size);
+ lb_start = off / lb_size;
+ lb_end = (off + len + lb_size -1) / lb_size;
+ num_lb = lb_end - lb_start;
+
+ udf_c_type = udf_get_c_type(udf_node);
+ vpart_num = udf_get_record_vpart(ump, udf_c_type);
+
+ /* all requests can fail */
+ can_fail = true;
+
+ /* fid's (directories) can't fail */
+ if (udf_c_type == UDF_C_FIDS)
+ can_fail = false;
+
+ /* system files can't fail */
+ if (vp->v_vflag & VV_SYSTEM)
+ can_fail = false;
+
+ error = udf_reserve_space(ump, udf_node, udf_c_type,
+ vpart_num, num_lb, can_fail);
+
+ DPRINTF(ALLOC, ("\tlb_start %"PRIu64", lb_end %"PRIu64", num_lb %d\n",
+ lb_start, lb_end, num_lb));
+
+ return error;
}
@@ -5255,6 +5316,7 @@
genfs_node_init(nvp, &udf_genfsops); /* inititise genfs */
udf_node->outstanding_bufs = 0;
udf_node->outstanding_nodedscr = 0;
+ udf_node->uncommitted_lbs = 0;
/* check if we're fetching the root */
if (ump->fileset_desc)
@@ -5548,12 +5610,16 @@
if (udf_node->i_flags & IN_DELETED) {
DPRINTF(NODE, ("\tnode deleted; not writing out\n"));
+ udf_cleanup_reservation(udf_node);
return 0;
}
/* lock node; unlocked in callback */
UDF_LOCK_NODE(udf_node, 0);
+ /* remove pending reservations, we're written out */
+ udf_cleanup_reservation(udf_node);
+
/* at least one descriptor writeout */
udf_node->outstanding_nodedscr = 1;
@@ -5587,6 +5653,7 @@
loc = &udf_node->write_loc;
error = udf_write_logvol_dscr(udf_node, dscr, loc, waitfor);
+
return error;
}
@@ -5611,6 +5678,7 @@
"v_numoutput = %d", udf_node, vp->v_numoutput);
#endif
+ udf_cleanup_reservation(udf_node);
/* TODO extended attributes and streamdir */
@@ -5685,22 +5753,22 @@
/* lock node */
error = vn_lock(nvp, LK_EXCLUSIVE | LK_RETRY);
- if (error) {
- nvp->v_data = NULL;
- ungetnewvnode(nvp);
- return error;
- }
+ if (error)
+ goto error_out_unget;
- /* get disc allocation for one logical block */
+ /* reserve space for one logical block */
vpart_num = ump->node_part;
- error = udf_pre_allocate_space(ump, UDF_C_NODE, 1,
- vpart_num, &lmapping);
+ error = udf_reserve_space(ump, NULL, UDF_C_NODE,
+ vpart_num, 1, /* can_fail */ true);
+ if (error)
+ goto error_out_unlock;
+
+ /* allocate node */
+ error = udf_allocate_space(ump, NULL, UDF_C_NODE,
+ vpart_num, 1, &lmapping);
+ if (error)
+ goto error_out_unreserve;
lb_num = lmapping;
- if (error) {
- vlockmgr(nvp->v_vnlock, LK_RELEASE);
- ungetnewvnode(nvp);
- return error;
- }
/* initialise pointer to location */
memset(&node_icb_loc, 0, sizeof(struct long_ad));
@@ -5724,6 +5792,7 @@
cv_init(&udf_node->node_lock, "udf_nlk");
udf_node->outstanding_bufs = 0;
udf_node->outstanding_nodedscr = 0;
+ udf_node->uncommitted_lbs = 0;
/* initialise genfs */
genfs_node_init(nvp, &udf_genfsops);
@@ -5790,6 +5859,18 @@
*vpp = nvp;
return 0;
+
+error_out_unreserve:
+ udf_do_unreserve_space(ump, NULL, vpart_num, 1);
+
+error_out_unlock:
+ vlockmgr(nvp->v_vnlock, LK_RELEASE);
+
+error_out_unget:
+ nvp->v_data = NULL;
+ ungetnewvnode(nvp);
+
+ return error;
}
@@ -6470,15 +6551,14 @@
uint32_t from, lblkno;
uint32_t sectors;
uint8_t *buf_pos;
- int error, run_length, isdir, what;
+ int error, run_length, what;
sector_size = udf_node->ump->discinfo.sector_size;
from = buf->b_blkno;
sectors = buf->b_bcount / sector_size;
- isdir = (udf_node->vnode->v_type == VDIR);
- what = isdir ? UDF_C_FIDS : UDF_C_USERDATA;
+ what = udf_get_c_type(udf_node);
/* assure we have enough translation slots */
KASSERT(buf->b_bcount / sector_size <= UDF_MAX_MAPPINGS);
@@ -6599,18 +6679,14 @@
uint32_t buf_offset, lb_num, rbuflen, rblk;
uint32_t from, lblkno;
uint32_t num_lb;
- int error, run_length, isdir, what, s;
+ int error, run_length, what, s;
lb_size = udf_rw32(udf_node->ump->logical_vol->lb_size);
from = buf->b_blkno;
num_lb = buf->b_bcount / lb_size;
- isdir = (udf_node->vnode->v_type == VDIR);
- what = isdir ? UDF_C_FIDS : UDF_C_USERDATA;
-
- if (udf_node == ump->metadatabitmap_node)
- what = UDF_C_METADATA_SBM;
+ what = udf_get_c_type(udf_node);
/* assure we have enough translation slots */
KASSERT(buf->b_bcount / lb_size <= UDF_MAX_MAPPINGS);
@@ -6659,7 +6735,6 @@
*/
/* XXX why not ignore the mapping altogether ? */
- /* TODO estimate here how much will be late-allocated */
DPRINTF(WRITE, ("\twrite lb_num "
"%"PRIu64, mapping[lb_num]));
@@ -6679,19 +6754,6 @@
rbuflen = run_length * lb_size;
rblk = run_start * (lb_size/DEV_BSIZE);
-#if 0
- /* if its zero or unmapped, our blknr gets -1 for unmapped */
- switch (mapping[lb_num]) {
- case UDF_TRANS_UNMAPPED:
- case UDF_TRANS_ZERO:
- rblk = -1;
- break;
- default:
- rblk = run_start * (lb_size/DEV_BSIZE);
- break;
- }
-#endif
-
nestbuf = getiobuf(NULL, true);
nestiobuf_setup(buf, nestbuf, buf_offset, rbuflen);
/* nestbuf is B_ASYNC */
Index: src/sys/fs/udf/udf_subr.h
diff -u src/sys/fs/udf/udf_subr.h:1.14 src/sys/fs/udf/udf_subr.h:1.15
--- src/sys/fs/udf/udf_subr.h:1.14 Tue Jun 23 20:09:07 2009
+++ src/sys/fs/udf/udf_subr.h Wed Jun 24 17:09:13 2009
@@ -1,4 +1,4 @@
-/* $NetBSD: udf_subr.h,v 1.14 2009/06/23 20:09:07 reinoud Exp $ */
+/* $NetBSD: udf_subr.h,v 1.15 2009/06/24 17:09:13 reinoud Exp $ */
/*
* Copyright (c) 2006, 2008 Reinoud Zandijk
@@ -109,11 +109,18 @@
int udf_vat_write(struct udf_node *vat_node, uint8_t *blob, int size, uint32_t offset);
/* disc allocation */
-void udf_late_allocate_buf(struct udf_mount *ump, struct buf *buf, uint64_t *lmapping, struct long_ad *node_ad_cpy, uint16_t *vpart_num);
+int udf_get_c_type(struct udf_node *udf_node);
+int udf_get_record_vpart(struct udf_mount *ump, int udf_c_type);
+void udf_do_reserve_space(struct udf_mount *ump, struct udf_node *udf_node, uint16_t vpart_num, uint32_t num_lb);
+void udf_do_unreserve_space(struct udf_mount *ump, struct udf_node *udf_node, uint16_t vpart_num, uint32_t num_lb);
+int udf_reserve_space(struct udf_mount *ump, struct udf_node *udf_node, int udf_c_type, uint16_t vpart_num, uint32_t num_lb, int can_fail);
+void udf_cleanup_reservation(struct udf_node *udf_node);
+int udf_allocate_space(struct udf_mount *ump, struct udf_node *udf_node, int udf_c_type, uint16_t vpart_num, uint32_t num_lb, uint64_t *lmapping);
void udf_free_allocated_space(struct udf_mount *ump, uint32_t lb_num, uint16_t vpart_num, uint32_t num_lb);
-int udf_pre_allocate_space(struct udf_mount *ump, int udf_c_type, uint32_t num_lb, uint16_t vpartnr, uint64_t *lmapping);
+void udf_late_allocate_buf(struct udf_mount *ump, struct buf *buf, uint64_t *lmapping, struct long_ad *node_ad_cpy, uint16_t *vpart_num);
int udf_grow_node(struct udf_node *node, uint64_t new_size);
int udf_shrink_node(struct udf_node *node, uint64_t new_size);
+void udf_calc_freespace(struct udf_mount *ump, uint64_t *sizeblks, uint64_t *freeblks);
/* node readers and writers */
uint64_t udf_advance_uniqueid(struct udf_mount *ump);
Index: src/sys/fs/udf/udf_vfsops.c
diff -u src/sys/fs/udf/udf_vfsops.c:1.56 src/sys/fs/udf/udf_vfsops.c:1.57
--- src/sys/fs/udf/udf_vfsops.c:1.56 Sat Apr 25 18:53:45 2009
+++ src/sys/fs/udf/udf_vfsops.c Wed Jun 24 17:09:13 2009
@@ -1,4 +1,4 @@
-/* $NetBSD: udf_vfsops.c,v 1.56 2009/04/25 18:53:45 elad Exp $ */
+/* $NetBSD: udf_vfsops.c,v 1.57 2009/06/24 17:09:13 reinoud Exp $ */
/*
* Copyright (c) 2006, 2008 Reinoud Zandijk
@@ -28,7 +28,7 @@
#include <sys/cdefs.h>
#ifndef lint
-__KERNEL_RCSID(0, "$NetBSD: udf_vfsops.c,v 1.56 2009/04/25 18:53:45 elad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: udf_vfsops.c,v 1.57 2009/06/24 17:09:13 reinoud Exp $");
#endif /* not lint */
@@ -782,8 +782,7 @@
struct logvol_int_desc *lvid;
struct udf_logvol_info *impl;
uint64_t freeblks, sizeblks;
- uint32_t *pos1, *pos2;
- int part, num_part;
+ int num_part;
DPRINTF(CALL, ("udf_statvfs called\n"));
sbp->f_flag = mp->mnt_flag;
@@ -792,36 +791,16 @@
sbp->f_iosize = ump->discinfo.sector_size;
mutex_enter(&ump->allocate_mutex);
- lvid = ump->logvol_integrity;
- freeblks = sizeblks = 0;
-
- /* Sequentials report free space directly (CD/DVD/BD-R) */
- KASSERT(lvid);
- num_part = udf_rw32(lvid->num_part);
- impl = (struct udf_logvol_info *) (lvid->tables + 2*num_part);
- if (ump->discinfo.mmc_cur & MMC_CAP_SEQUENTIAL) {
- /* XXX assumption at most two tracks open */
- freeblks = ump->data_track.free_blocks;
- if (ump->data_track.tracknr != ump->metadata_track.tracknr)
- freeblks += ump->metadata_track.free_blocks;
- sizeblks = ump->discinfo.last_possible_lba;
- } else {
- /* free and used space for mountpoint based on logvol integrity */
- for (part=0; part < num_part; part++) {
- pos1 = &lvid->tables[0] + part;
- pos2 = &lvid->tables[0] + num_part + part;
- if (udf_rw32(*pos1) != (uint32_t) -1) {
- freeblks += udf_rw32(*pos1);
- sizeblks += udf_rw32(*pos2);
- }
- }
- }
- freeblks -= ump->uncomitted_lb;
+ udf_calc_freespace(ump, &sizeblks, &freeblks);
sbp->f_blocks = sizeblks;
sbp->f_bfree = freeblks;
sbp->f_files = 0;
+
+ lvid = ump->logvol_integrity;
+ num_part = udf_rw32(lvid->num_part);
+ impl = (struct udf_logvol_info *) (lvid->tables + 2*num_part);
if (impl) {
sbp->f_files = udf_rw32(impl->num_files);
sbp->f_files += udf_rw32(impl->num_directories);
Index: src/sys/fs/udf/udf_vnops.c
diff -u src/sys/fs/udf/udf_vnops.c:1.45 src/sys/fs/udf/udf_vnops.c:1.46
--- src/sys/fs/udf/udf_vnops.c:1.45 Tue Jun 23 20:09:07 2009
+++ src/sys/fs/udf/udf_vnops.c Wed Jun 24 17:09:13 2009
@@ -1,4 +1,4 @@
-/* $NetBSD: udf_vnops.c,v 1.45 2009/06/23 20:09:07 reinoud Exp $ */
+/* $NetBSD: udf_vnops.c,v 1.46 2009/06/24 17:09:13 reinoud Exp $ */
/*
* Copyright (c) 2006, 2008 Reinoud Zandijk
@@ -32,7 +32,7 @@
#include <sys/cdefs.h>
#ifndef lint
-__KERNEL_RCSID(0, "$NetBSD: udf_vnops.c,v 1.45 2009/06/23 20:09:07 reinoud Exp $");
+__KERNEL_RCSID(0, "$NetBSD: udf_vnops.c,v 1.46 2009/06/24 17:09:13 reinoud Exp $");
#endif /* not lint */
@@ -277,6 +277,7 @@
uint64_t file_size, old_size, old_offset;
vsize_t len;
int async = vp->v_mount->mnt_flag & MNT_ASYNC;
+ int aflag = ioflag & IO_SYNC ? B_SYNC : 0;
int error;
int resid, extended;
@@ -344,6 +345,12 @@
if (len == 0)
break;
+ genfs_node_wrlock(vp);
+ error = GOP_ALLOC(vp, uio->uio_offset, len, aflag, cred);
+ genfs_node_unlock(vp);
+ if (error)
+ break;
+
/* ubc, here we come, prepare to trap */
error = ubc_uiomove(uobj, uio, len, advice,
UBC_WRITE | UBC_UNMAP_FLAG(vp));