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));

Reply via email to