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

UFS2 super block changes



Hi,

This is the most delicate step in getting kernel support for UFS2. I'd
like to ask you guys to put all the effort you can in reviewing and
testing this diff. A more precise explanation of what it does follows.

The super block changes that UFS2 requires are somewhat straightforward.
Basically what we have to do is to nuke the old rotational table crud
and use this space for broader, 64-bit fields. However, since we're
talking about an essential structure for any file system to be properly
mounted, it's always good to take as much care as possible and stay on
the safe side.

The approach I suggest we take is similar to the one FreeBSD and NetBSD
have taken: make use of a new UFS1 flag (FS_FLAGS_UPDATED) that meant
"this is an ordinary UFS1 file system, but with flags and other fields
shifted to the new (UFS2) location". Doing so would allow the kernel to
access those fields uniformly. When a file system gets mounted with that
flag absent, we do the shift, mark it as updated forever and, upon
unmount, we update the UFS1 fields to maintain compatibility.

Userland tools that manipulate super blocks are then tricked into
looking and using UFS1 fields, to keep current behaviour. Care must be
taken with tools that _change_ (not create) certain super block fields,
such as growfs. These tools, when flushing the super block back to disk
after modifying it, now need to unset the FS_FLAGS_UPDATED flag to force
another update upon the next mount.

I've tested this on both i386 and macppc by making full releases and
using them to update other boxes. Everything went as smooth as usual.

-p.

Index: sys/ufs/ffs/ffs_vfsops.c
===================================================================
RCS file: /cvs/src/sys/ufs/ffs/ffs_vfsops.c,v
retrieving revision 1.82
diff -u -r1.82 ffs_vfsops.c
--- sys/ufs/ffs/ffs_vfsops.c	9 Mar 2006 13:25:02 -0000	1.82
+++ sys/ufs/ffs/ffs_vfsops.c	12 Mar 2006 16:21:06 -0000
@@ -68,6 +68,9 @@
 int ffs_reload_vnode(struct vnode *, void *);
 int ffs_sync_vnode(struct vnode *, void *);
 
+void ffs1_compat_read(struct fs *, struct ufsmount *, ufs2_daddr_t);
+void ffs1_compat_write(struct fs *, struct ufsmount *);
+
 const struct vfsops ffs_vfsops = {
 	ffs_mount,
 	ufs_start,
@@ -754,6 +757,9 @@
 	brelse(bp);
 	bp = NULL;
 	fs = ump->um_fs;
+
+	ffs1_compat_read(fs, ump, sbloc);
+
 	fs->fs_ronly = ronly;
 	size = fs->fs_cssize;
 	blks = howmany(size, fs->fs_fsize);
@@ -901,6 +907,48 @@
 }
 
 /*
+ * Auxiliary function for reading FFS1 super blocks.
+ */
+void
+ffs1_compat_read(struct fs *fs, struct ufsmount *ump, ufs2_daddr_t sbloc)
+{
+	if (fs->fs_magic == FS_UFS2_MAGIC)
+		return; /* UFS2 */
+
+	if (fs->fs_ffs1_flags & FS_FLAGS_UPDATED)
+		return; /* Already updated */
+
+	fs->fs_flags = fs->fs_ffs1_flags;
+	fs->fs_sblockloc = sbloc;
+	fs->fs_maxbsize = fs->fs_bsize;
+	fs->fs_time = fs->fs_ffs1_time;
+	fs->fs_size = fs->fs_ffs1_size;
+	fs->fs_dsize = fs->fs_ffs1_dsize;
+	fs->fs_csaddr = fs->fs_ffs1_csaddr;
+	fs->fs_cstotal.cs_ndir = fs->fs_ffs1_cstotal.cs_ndir;
+	fs->fs_cstotal.cs_nbfree = fs->fs_ffs1_cstotal.cs_nbfree;
+	fs->fs_cstotal.cs_nifree = fs->fs_ffs1_cstotal.cs_nifree;
+	fs->fs_cstotal.cs_nffree = fs->fs_ffs1_cstotal.cs_nffree;
+	fs->fs_ffs1_flags |= FS_FLAGS_UPDATED;
+}
+
+/*
+ * Auxiliary function for writing FFS1 super blocks.
+ */
+void
+ffs1_compat_write(struct fs *fs, struct ufsmount *ump)
+{
+	if (fs->fs_magic != FS_UFS1_MAGIC)
+		return; /* UFS2 */
+
+	fs->fs_ffs1_time = fs->fs_time;
+	fs->fs_ffs1_cstotal.cs_ndir = fs->fs_cstotal.cs_ndir;
+	fs->fs_ffs1_cstotal.cs_nbfree = fs->fs_cstotal.cs_nbfree;
+	fs->fs_ffs1_cstotal.cs_nifree = fs->fs_cstotal.cs_nifree;
+	fs->fs_ffs1_cstotal.cs_nffree = fs->fs_cstotal.cs_nffree;
+}
+
+/*
  * unmount system call
  */
 int
@@ -1350,6 +1398,9 @@
 		lp[0] = tmp;					/* XXX */
 	}							/* XXX */
 	dfs->fs_maxfilesize = mp->um_savedmaxfilesize;		/* XXX */
+
+	ffs1_compat_write(dfs, mp);
+
 	if (waitfor != MNT_WAIT)
 		bawrite(bp);
 	else if ((error = bwrite(bp)))
Index: sys/ufs/ffs/fs.h
===================================================================
RCS file: /cvs/src/sys/ufs/ffs/fs.h,v
retrieving revision 1.19
diff -u -r1.19 fs.h
--- sys/ufs/ffs/fs.h	9 Mar 2006 13:35:02 -0000	1.19
+++ sys/ufs/ffs/fs.h	17 Mar 2006 20:34:40 -0000
@@ -105,7 +105,13 @@
  * in fs_fsmnt. MAXMNTLEN defines the amount of space allocated in
  * the super block for this name.
  */
-#define MAXMNTLEN	512
+#define MAXMNTLEN	468
+
+/*
+ * The volume name for this file system is kept in fs_volname.
+ * MAXVOLLEN defines the length of the buffer allocated.
+ */
+#define MAXVOLLEN	32
 
 /*
  * There is a 128-byte region in the superblock reserved for in-core
@@ -120,7 +126,7 @@
  * and the third points to an array that tracks the creation of new
  * directories.
  */
-#define		NOCSPTRS	((128 / sizeof(void *)) - 3)
+#define NOCSPTRS	((128 / sizeof(void *)) - 4)
 
 /*
  * A summary of contiguous blocks of various sizes is maintained
@@ -156,6 +162,11 @@
 #define AFPDIR		64	/* expected number of files per directory */
 
 /*
+ * Size of super block space reserved for snapshots.
+ */
+#define FSMAXSNAP	20
+
+/*
  * Per cylinder group information; summarized in blocks allocated
  * from first cylinder group data blocks.  These blocks have to be
  * read in from fs_csaddr (size fs_cssize) in addition to the
@@ -168,6 +179,14 @@
 	int32_t	cs_nffree;		/* number of free frags */
 };
 
+struct csum_total {
+	int64_t	cs_ndir;		/* number of directories */
+	int64_t	cs_nbfree;		/* number of free blocks */
+	int64_t	cs_nifree;		/* number of free inodes */
+	int64_t	cs_nffree;		/* number of free frags */
+	int64_t	cs_spare[4];		/* future expansion */
+};
+
 /*
  * Super block for an FFS file system.
  */
@@ -180,9 +199,9 @@
 	int32_t	 fs_dblkno;		/* offset of first data after cg */
 	int32_t	 fs_cgoffset;		/* cylinder group offset in cylinder */
 	int32_t	 fs_cgmask;		/* used to calc mod fs_ntrak */
-	time_t 	 fs_time;		/* last time written */
-	int32_t	 fs_size;		/* number of blocks in fs */
-	int32_t	 fs_dsize;		/* number of data blocks in fs */
+	time_t 	 fs_ffs1_time;		/* last time written */
+	int32_t	 fs_ffs1_size;		/* number of blocks in fs */
+	int32_t	 fs_ffs1_dsize;		/* number of data blocks in fs */
 	int32_t	 fs_ncg;		/* number of cylinder groups */
 	int32_t	 fs_bsize;		/* size of basic blocks in fs */
 	int32_t	 fs_fsize;		/* size of frag blocks in fs */
@@ -217,7 +236,7 @@
 /* fs_id takes the space of the unused fs_headswitch and fs_trkseek fields */
 	int32_t  fs_id[2];		/* unique filesystem id */
 /* sizes determined by number of cylinder groups and their sizes */
-	int32_t  fs_csaddr;		/* blk addr of cyl grp summary area */
+	int32_t  fs_ffs1_csaddr;	/* blk addr of cyl grp summary area */
 	int32_t	 fs_cssize;		/* size of cyl grp summary area */
 	int32_t	 fs_cgsize;		/* cylinder group size */
 /* these fields are derived from the hardware */
@@ -231,25 +250,41 @@
 	int32_t	 fs_ipg;		/* inodes per group */
 	int32_t	 fs_fpg;		/* blocks per group * fs_frag */
 /* this data must be re-computed after crashes */
-	struct	csum fs_cstotal;	/* cylinder summary information */
+	struct	csum fs_ffs1_cstotal;	/* cylinder summary information */
 /* these fields are cleared at mount time */
 	int8_t	 fs_fmod;		/* super block modified flag */
 	int8_t	 fs_clean;		/* file system is clean flag */
 	int8_t	 fs_ronly;		/* mounted read-only flag */
-	int8_t	 fs_flags;		/* see FS_ below */
+	u_int8_t fs_ffs1_flags;		/* see FS_ below */
 	u_char	 fs_fsmnt[MAXMNTLEN];	/* name mounted on */
+	u_char	 fs_volname[MAXVOLLEN];	/* volume name */
+	u_int64_t fs_swuid;		/* system-wide uid */
+	int32_t	 fs_pad;		/* due to alignment of fs_swuid */
 /* these fields retain the current block allocation info */
 	int32_t	 fs_cgrotor;		/* last cg searched */
 	void    *fs_ocsp[NOCSPTRS];	/* padding; was list of fs_cs buffers */
 	u_int8_t *fs_contigdirs;	/* # of contiguously allocated dirs */
 	struct csum *fs_csp;		/* cg summary info buffer for fs_cs */
 	int32_t	*fs_maxcluster;		/* max cluster in each cyl group */
+	u_char	*fs_active;		/* reserved for snapshots */
 	int32_t	 fs_cpc;		/* cyl per cycle in postbl */
-	int16_t	 fs_opostbl[16][8];	/* old rotation block list head */
-	int32_t  fs_snapinum[20];	/* reserved for snapshot inode nums */
+/* this area is only allocated if fs_ffs1_flags & FS_FLAGS_UPDATED */
+	int32_t	 fs_maxbsize;		/* maximum blocking factor permitted */
+	int64_t	 fs_spareconf64[17];	/* old rotation block list head */
+	int64_t	 fs_sblockloc;		/* offset of standard super block */
+	struct	csum_total fs_cstotal;	/* cylinder summary information */
+	int64_t	 fs_time;		/* time last written */
+	int64_t	 fs_size;		/* number of blocks in fs */
+	int64_t	 fs_dsize;		/* number of data blocks in fs */
+	int64_t	 fs_csaddr;		/* blk addr of cyl grp summary area */
+	int64_t	 fs_pendingblocks;	/* blocks in process of being freed */
+	int32_t	 fs_pendinginodes;	/* inodes in process of being freed */
+	int32_t	 fs_snapinum[FSMAXSNAP];/* space reserved for snapshots */
+/* back to stuff that has been around a while */
 	int32_t	 fs_avgfilesize;	/* expected average file size */
 	int32_t	 fs_avgfpdir;		/* expected # of files per directory */
-	int32_t	 fs_sparecon[27];	/* reserved for future constants */
+	int32_t	 fs_sparecon[26];	/* reserved for future constants */
+	u_int32_t fs_flags;		/* see FS_ flags below */
 	time_t	 fs_fscktime;		/* last time fsck(8)ed */
 	int32_t	 fs_contigsumsize;	/* size of cluster summary array */ 
 	int32_t	 fs_maxsymlinklen;	/* max length of an internal symlink */
@@ -267,7 +302,19 @@
 /* actually longer */
 };
 
-#define	fs_opostbl_start	fs_opostbl[0][0]
+#ifndef _KERNEL
+/*
+ * Trick userland tools into accessing FFS1 fields until they all get switched
+ * to correctly use the new ones.
+ */
+#define fs_opostbl_start	fs_maxbsize
+#define fs_flags		fs_ffs1_flags
+#define fs_time			fs_ffs1_time
+#define fs_size			fs_ffs1_size
+#define fs_dsize		fs_ffs1_dsize
+#define fs_csaddr		fs_ffs1_csaddr
+#define fs_cstotal		fs_ffs1_cstotal
+#endif /* !_KERNEL */
 
 /*
  * Filesystem identification
@@ -294,8 +341,13 @@
 /* 
  * Filesystem flags.
  */
-#define FS_UNCLEAN    0x01   /* filesystem not clean at mount */
-#define FS_DOSOFTDEP  0x02   /* filesystem using soft dependencies */
+#define FS_UNCLEAN		0x01	/* file system not clean at mount */
+#define FS_DOSOFTDEP		0x02	/* file system using softdeps */
+/*
+ * The following flag is used to detect a FFS1 file system that had its flags
+ * moved to the new (FFS2) location for compatibility.
+ */
+#define FS_FLAGS_UPDATED	0x80	/* file system has FFS2-like flags */
 
 /*
  * Rotational layout table format types
Index: sbin/growfs/growfs.c
===================================================================
RCS file: /cvs/src/sbin/growfs/growfs.c,v
retrieving revision 1.14
diff -u -r1.14 growfs.c
--- sbin/growfs/growfs.c	14 Jan 2006 21:10:20 -0000	1.14
+++ sbin/growfs/growfs.c	12 Mar 2006 16:21:07 -0000
@@ -285,6 +285,8 @@
 }
 #endif /* FS_DEBUG */
 
+	sblock.fs_flags &= ~FS_FLAGS_UPDATED; /* Force update on next mount */
+
 	/*
 	 * Now write the new superblock back to disk.
 	 */



Visit your host, monkey.org