Module Name:    src
Committed By:   reinoud
Date:           Tue May 10 15:23:39 UTC 2016

Modified Files:
        src/sys/fs/udf: udf.h udf_subr.c

Log Message:
Rework VAT searching on recordable media. It is now a lot more resilliant to
errors and it allows for VAT searching on crashed writeouts.

While here, make sure the node pointer is always initialised in
udf_get_node().


To generate a diff of this commit:
cvs rdiff -u -r1.50 -r1.51 src/sys/fs/udf/udf.h
cvs rdiff -u -r1.136 -r1.137 src/sys/fs/udf/udf_subr.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.50 src/sys/fs/udf/udf.h:1.51
--- src/sys/fs/udf/udf.h:1.50	Mon Aug 24 08:31:56 2015
+++ src/sys/fs/udf/udf.h	Tue May 10 15:23:39 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: udf.h,v 1.50 2015/08/24 08:31:56 hannken Exp $ */
+/* $NetBSD: udf.h,v 1.51 2016/05/10 15:23:39 reinoud Exp $ */
 
 /*
  * Copyright (c) 2006, 2008 Reinoud Zandijk
@@ -417,11 +417,12 @@ struct udf_node {
 #define	IN_SYNCED		0x0200	/* node is being used by sync */
 #define	IN_CALLBACK_ULK		0x0400	/* node will be unlocked by callback */
 #define	IN_NODE_REBUILD		0x0800	/* node is rebuild */
+#define IN_NO_DELETE		0x1000	/* node is not to be deleted */
 
 
 #define IN_FLAGBITS \
 	"\10\1IN_ACCESS\2IN_CHANGE\3IN_UPDATE\4IN_MODIFY\5IN_MODIFIED" \
 	"\6IN_ACCESSED\7IN_RENAME\10IN_DELETED\11IN_LOCKED\12IN_SYNCED" \
-	"\13IN_CALLBACK_ULK\14IN_NODE_REBUILD"
+	"\13IN_CALLBACK_ULK\14IN_NODE_REBUILD\15IN_NO_DELETE"
 
 #endif /* !_FS_UDF_UDF_H_ */

Index: src/sys/fs/udf/udf_subr.c
diff -u src/sys/fs/udf/udf_subr.c:1.136 src/sys/fs/udf/udf_subr.c:1.137
--- src/sys/fs/udf/udf_subr.c:1.136	Wed Jan 27 00:06:49 2016
+++ src/sys/fs/udf/udf_subr.c	Tue May 10 15:23:39 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: udf_subr.c,v 1.136 2016/01/27 00:06:49 reinoud Exp $ */
+/* $NetBSD: udf_subr.c,v 1.137 2016/05/10 15:23:39 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.136 2016/01/27 00:06:49 reinoud Exp $");
+__KERNEL_RCSID(0, "$NetBSD: udf_subr.c,v 1.137 2016/05/10 15:23:39 reinoud Exp $");
 #endif /* not lint */
 
 
@@ -946,7 +946,7 @@ udf_read_anchors(struct udf_mount *ump)
 
 	/* VATs are only recorded on sequential media, but initialise */
 	ump->first_possible_vat_location = track_start + 2;
-	ump->last_possible_vat_location  = track_end + last_track.packet_size;
+	ump->last_possible_vat_location  = track_end;
 
 	return ok;
 }
@@ -2995,6 +2995,10 @@ udf_check_for_vat(struct udf_node *vat_n
 	ump->logvol_integrity->integrity_type = udf_rw32(UDF_INTEGRITY_CLOSED);
 	ump->logvol_integrity->time           = *mtime;
 
+	/* if we're updating, free old allocated space */
+	if (ump->vat_table)
+		free(ump->vat_table, M_UDFVOLD);
+
 	ump->vat_table_len = vat_length;
 	ump->vat_table_alloc_len = vat_table_alloc_len;
 	ump->vat_table   = vat_table;
@@ -3017,49 +3021,70 @@ out:
 static int
 udf_search_vat(struct udf_mount *ump, union udf_pmap *mapping)
 {
-	struct udf_node *vat_node;
+	struct udf_node *vat_node, *accepted_vat_node;
 	struct long_ad	 icb_loc;
-	uint32_t early_vat_loc, vat_loc;
+	uint32_t early_vat_loc, late_vat_loc, vat_loc;
 	int error;
 
 	/* mapping info not needed */
 	mapping = mapping;
 
-	vat_loc = ump->last_possible_vat_location;
-	early_vat_loc = vat_loc - 256;	/* 8 blocks of 32 sectors */
-
-	DPRINTF(VOLUMES, ("1) last possible %d, early_vat_loc %d \n",
-		vat_loc, early_vat_loc));
-	early_vat_loc = MAX(early_vat_loc, ump->first_possible_vat_location);
-
-	DPRINTF(VOLUMES, ("2) last possible %d, early_vat_loc %d \n",
-		vat_loc, early_vat_loc));
-
-	/* start looking from the end of the range */
+	DPRINTF(VOLUMES, ("Searching VAT\n"));
+	
+	/*
+	 * Start reading forward in blocks from the first possible vat
+	 * location. If not found in this block, start again a bit before
+	 * until we get a hit.
+	 */
+	late_vat_loc = ump->last_possible_vat_location;
+	early_vat_loc = MAX(late_vat_loc - 64, ump->first_possible_vat_location);
+ 
+	DPRINTF(VOLUMES, ("\tfull range %d to %d\n", early_vat_loc, late_vat_loc));
+	accepted_vat_node = NULL;
 	do {
-		DPRINTF(VOLUMES, ("Checking for VAT at sector %d\n", vat_loc));
-		icb_loc.loc.part_num = udf_rw16(UDF_VTOP_RAWPART);
-		icb_loc.loc.lb_num   = udf_rw32(vat_loc);
+		vat_loc = early_vat_loc;
+		DPRINTF(VOLUMES, ("\tchecking range %d to %d\n",
+			early_vat_loc, late_vat_loc));
+		do {
+			DPRINTF(VOLUMES, ("\t\tChecking for VAT at sector %d\n",
+				vat_loc));
+			icb_loc.loc.part_num = udf_rw16(UDF_VTOP_RAWPART);
+			icb_loc.loc.lb_num   = udf_rw32(vat_loc);
 
-		error = udf_get_node(ump, &icb_loc, &vat_node);
-		if (!error) {
-			error = udf_check_for_vat(vat_node);
-			DPRINTFIF(VOLUMES, !error,
-				("VAT accepted at %d\n", vat_loc));
-			if (!error)
-				break;
-		}
-		if (vat_node) {
-			vput(vat_node->vnode);
-			vat_node = NULL;
-		}
-		vat_loc--;	/* walk backwards */
-	} while (vat_loc >= early_vat_loc);
-
-	/* keep our VAT node around */
-	if (vat_node) {
-		UDF_SET_SYSTEMFILE(vat_node->vnode);
-		ump->vat_node = vat_node;
+			error = udf_get_node(ump, &icb_loc, &vat_node);
+			if (!error) {
+				error = udf_check_for_vat(vat_node);
+				vat_node->i_flags = 0;	/* reset access */
+			}
+			if (!error) {
+				DPRINTFIF(VOLUMES, !error,
+					("VAT candidate accepted at %d\n",
+					 vat_loc));
+				if (accepted_vat_node)
+					vput(accepted_vat_node->vnode);
+				accepted_vat_node = vat_node;
+				accepted_vat_node->i_flags |= IN_NO_DELETE;
+				vat_node = NULL;
+			}
+			if (vat_node)
+				vput(vat_node->vnode);
+			vat_loc++;	/* walk forward */
+		} while (vat_loc < late_vat_loc);
+		if (accepted_vat_node)
+			break;
+
+		early_vat_loc = MAX(early_vat_loc - 64, ump->first_possible_vat_location);
+		late_vat_loc = MIN(early_vat_loc + 64, ump->last_possible_vat_location);
+	} while (late_vat_loc > ump->first_possible_vat_location);
+
+	/* keep our last accepted VAT node around */
+	if (accepted_vat_node) {
+		/* revert no delete flag again to avoid potential side effects */
+		accepted_vat_node->i_flags &= ~IN_NO_DELETE;
+
+		UDF_SET_SYSTEMFILE(accepted_vat_node->vnode);
+		ump->vat_node = accepted_vat_node;
+		return 0;
 	}
 
 	return error;
@@ -3674,6 +3699,22 @@ udf_open_logvol(struct udf_mount *ump)
 
 		/* determine data and metadata tracks again */
 		error = udf_search_writing_tracks(ump);
+
+		if (ump->lvclose & UDF_WRITE_VAT) {
+			/*
+			 * we writeout the VAT to get a self-sustained session
+			 * for fsck
+			 */
+			DPRINTF(VOLUMES, ("lvclose & UDF_WRITE_VAT\n"));
+
+			/* write out the VAT data and all its descriptors */
+			DPRINTF(VOLUMES, ("writeout vat_node\n"));
+			udf_writeout_vat(ump);
+			vflushbuf(ump->vat_node->vnode, 1 /* sync */);
+
+			(void) VOP_FSYNC(ump->vat_node->vnode,
+					FSCRED, FSYNC_WAIT, 0, 0);
+		}
 	}
 
 	/* mark it open */
@@ -5562,6 +5603,8 @@ udf_get_node(struct udf_mount *ump, stru
 	int error;
 	struct vnode *vp;
 
+	*udf_noderes = NULL;
+
 	error = vcache_get(ump->vfs_mountp, &node_icb_loc->loc,
 	    sizeof(node_icb_loc->loc), &vp);
 	if (error)
@@ -5927,6 +5970,9 @@ udf_delete_node(struct udf_node *udf_nod
 	struct long_ad *loc;
 	int extnr, lvint, dummy;
 
+	if (udf_node->i_flags & IN_NO_DELETE)
+		return;
+
 	/* paranoia check on integrity; should be open!; we could panic */
 	lvint = udf_rw32(udf_node->ump->logvol_integrity->integrity_type);
 	if (lvint == UDF_INTEGRITY_CLOSED)

Reply via email to