linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/41] fs/adfs updates for 5.6
@ 2019-12-09 11:07 Russell King - ARM Linux admin
  2019-12-09 11:08 ` [PATCH 01/41] fs/adfs: inode: update timestamps to centisecond precision Russell King
                   ` (40 more replies)
  0 siblings, 41 replies; 47+ messages in thread
From: Russell King - ARM Linux admin @ 2019-12-09 11:07 UTC (permalink / raw)
  To: Al Viro, Jonathan Corbet; +Cc: linux-doc, linux-fsdevel

Hi,

This patch series updates the fs/adfs code in the kernel (which still
has users!)

- update inode timestamps to centisecond resolution time, as per the
  native format.
- consolidate and clean up map scanning code.
- consolidate and clean up and modernise directory handling code.
- restructure directory handling code to better improve the rudimentary
  write support we have.
- fix inode dropping; otherwise updates are lost on umount.
- add support for E and E+ format image files.

Patches based on v5.4; there have been no changes to fs/adfs during the
merge window.

This is also available from:

   git://git.armlinux.org.uk/~rmk/linux-arm.git adfs

with head SHA1 8901af013ecd.

 Documentation/filesystems/adfs.txt |  24 +++
 fs/adfs/adfs.h                     |  32 ++--
 fs/adfs/dir.c                      | 314 +++++++++++++++++++++++++--------
 fs/adfs/dir_f.c                    | 302 +++++++++-----------------------
 fs/adfs/dir_f.h                    |  52 +++---
 fs/adfs/dir_fplus.c                | 345 +++++++++++++++++++++----------------
 fs/adfs/dir_fplus.h                |   6 +-
 fs/adfs/inode.c                    |  64 +++----
 fs/adfs/map.c                      | 247 +++++++++++++++++++-------
 fs/adfs/super.c                    | 267 ++++++++++------------------
 10 files changed, 913 insertions(+), 740 deletions(-)

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 12.1Mbps down 622kbps up
According to speedtest.net: 11.9Mbps down 500kbps up

^ permalink raw reply	[flat|nested] 47+ messages in thread

* [PATCH 01/41] fs/adfs: inode: update timestamps to centisecond precision
  2019-12-09 11:07 [PATCH 00/41] fs/adfs updates for 5.6 Russell King - ARM Linux admin
@ 2019-12-09 11:08 ` Russell King
  2019-12-09 13:54   ` Vyacheslav Dubeyko
  2019-12-09 11:08 ` [PATCH 02/41] fs/adfs: inode: fix adfs_mode2atts() Russell King
                   ` (39 subsequent siblings)
  40 siblings, 1 reply; 47+ messages in thread
From: Russell King @ 2019-12-09 11:08 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel

Despite ADFS timestamps having centi-second granularity, and Linux
gaining fine-grained timestamp support in v2.5.48, fs/adfs was never
updated.

Update fs/adfs to centi-second support, and ensure that the inode ctime
always reflects what is written in underlying media.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
 fs/adfs/inode.c | 40 ++++++++++++++++++++--------------------
 fs/adfs/super.c |  2 ++
 2 files changed, 22 insertions(+), 20 deletions(-)

diff --git a/fs/adfs/inode.c b/fs/adfs/inode.c
index 124de75413a5..18a1d478669b 100644
--- a/fs/adfs/inode.c
+++ b/fs/adfs/inode.c
@@ -158,6 +158,8 @@ adfs_mode2atts(struct super_block *sb, struct inode *inode)
 	return attr;
 }
 
+static const s64 nsec_unix_epoch_diff_risc_os_epoch = 2208988800000000000LL;
+
 /*
  * Convert an ADFS time to Unix time.  ADFS has a 40-bit centi-second time
  * referenced to 1 Jan 1900 (til 2248) so we need to discard 2208988800 seconds
@@ -170,8 +172,6 @@ adfs_adfs2unix_time(struct timespec64 *tv, struct inode *inode)
 	/* 01 Jan 1970 00:00:00 (Unix epoch) as nanoseconds since
 	 * 01 Jan 1900 00:00:00 (RISC OS epoch)
 	 */
-	static const s64 nsec_unix_epoch_diff_risc_os_epoch =
-							2208988800000000000LL;
 	s64 nsec;
 
 	if (!adfs_inode_is_stamped(inode))
@@ -204,24 +204,23 @@ adfs_adfs2unix_time(struct timespec64 *tv, struct inode *inode)
 	return;
 }
 
-/*
- * Convert an Unix time to ADFS time.  We only do this if the entry has a
- * time/date stamp already.
- */
-static void
-adfs_unix2adfs_time(struct inode *inode, unsigned int secs)
+/* Convert an Unix time to ADFS time for an entry that is already stamped. */
+static void adfs_unix2adfs_time(struct inode *inode,
+				const struct timespec64 *ts)
 {
-	unsigned int high, low;
+	s64 cs, nsec = timespec64_to_ns(ts);
 
-	if (adfs_inode_is_stamped(inode)) {
-		/* convert 32-bit seconds to 40-bit centi-seconds */
-		low  = (secs & 255) * 100;
-		high = (secs / 256) * 100 + (low >> 8) + 0x336e996a;
+	/* convert from Unix to RISC OS epoch */
+	nsec += nsec_unix_epoch_diff_risc_os_epoch;
 
-		ADFS_I(inode)->loadaddr = (high >> 24) |
-				(ADFS_I(inode)->loadaddr & ~0xff);
-		ADFS_I(inode)->execaddr = (low & 255) | (high << 8);
-	}
+	/* convert from nanoseconds to centiseconds */
+	cs = div_s64(nsec, 10000000);
+
+	cs = clamp_t(s64, cs, 0, 0xffffffffff);
+
+	ADFS_I(inode)->loadaddr &= ~0xff;
+	ADFS_I(inode)->loadaddr |= (cs >> 32) & 0xff;
+	ADFS_I(inode)->execaddr = cs;
 }
 
 /*
@@ -315,10 +314,11 @@ adfs_notify_change(struct dentry *dentry, struct iattr *attr)
 	if (ia_valid & ATTR_SIZE)
 		truncate_setsize(inode, attr->ia_size);
 
-	if (ia_valid & ATTR_MTIME) {
-		inode->i_mtime = attr->ia_mtime;
-		adfs_unix2adfs_time(inode, attr->ia_mtime.tv_sec);
+	if (ia_valid & ATTR_MTIME && adfs_inode_is_stamped(inode)) {
+		adfs_unix2adfs_time(inode, &attr->ia_mtime);
+		adfs_adfs2unix_time(&inode->i_mtime, inode);
 	}
+
 	/*
 	 * FIXME: should we make these == to i_mtime since we don't
 	 * have the ability to represent them in our filesystem?
diff --git a/fs/adfs/super.c b/fs/adfs/super.c
index 65b04ebb51c3..e0eea9adb4e6 100644
--- a/fs/adfs/super.c
+++ b/fs/adfs/super.c
@@ -391,7 +391,9 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent)
 	asb = kzalloc(sizeof(*asb), GFP_KERNEL);
 	if (!asb)
 		return -ENOMEM;
+
 	sb->s_fs_info = asb;
+	sb->s_time_gran = 10000000;
 
 	/* set default options */
 	asb->s_uid = GLOBAL_ROOT_UID;
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 02/41] fs/adfs: inode: fix adfs_mode2atts()
  2019-12-09 11:07 [PATCH 00/41] fs/adfs updates for 5.6 Russell King - ARM Linux admin
  2019-12-09 11:08 ` [PATCH 01/41] fs/adfs: inode: update timestamps to centisecond precision Russell King
@ 2019-12-09 11:08 ` Russell King
  2019-12-09 11:08 ` [PATCH 03/41] fs/adfs: map: move map reading and validation to map.c Russell King
                   ` (38 subsequent siblings)
  40 siblings, 0 replies; 47+ messages in thread
From: Russell King @ 2019-12-09 11:08 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel

Fix adfs_mode2atts() to actually update the file permissions on the
media rather than using the current inode mode.  Note also that
directories do not have read/write permissions stored on the media.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
 fs/adfs/inode.c | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/fs/adfs/inode.c b/fs/adfs/inode.c
index 18a1d478669b..212a56fc7911 100644
--- a/fs/adfs/inode.c
+++ b/fs/adfs/inode.c
@@ -126,29 +126,29 @@ adfs_atts2mode(struct super_block *sb, struct inode *inode)
  * Convert Linux permission to ADFS attribute.  We try to do the reverse
  * of atts2mode, but there is not a 1:1 translation.
  */
-static int
-adfs_mode2atts(struct super_block *sb, struct inode *inode)
+static int adfs_mode2atts(struct super_block *sb, struct inode *inode,
+			  umode_t ia_mode)
 {
+	struct adfs_sb_info *asb = ADFS_SB(sb);
 	umode_t mode;
 	int attr;
-	struct adfs_sb_info *asb = ADFS_SB(sb);
 
 	/* FIXME: should we be able to alter a link? */
 	if (S_ISLNK(inode->i_mode))
 		return ADFS_I(inode)->attr;
 
+	/* Directories do not have read/write permissions on the media */
 	if (S_ISDIR(inode->i_mode))
-		attr = ADFS_NDA_DIRECTORY;
-	else
-		attr = 0;
+		return ADFS_NDA_DIRECTORY;
 
-	mode = inode->i_mode & asb->s_owner_mask;
+	attr = 0;
+	mode = ia_mode & asb->s_owner_mask;
 	if (mode & S_IRUGO)
 		attr |= ADFS_NDA_OWNER_READ;
 	if (mode & S_IWUGO)
 		attr |= ADFS_NDA_OWNER_WRITE;
 
-	mode = inode->i_mode & asb->s_other_mask;
+	mode = ia_mode & asb->s_other_mask;
 	mode &= ~asb->s_owner_mask;
 	if (mode & S_IRUGO)
 		attr |= ADFS_NDA_PUBLIC_READ;
@@ -328,7 +328,7 @@ adfs_notify_change(struct dentry *dentry, struct iattr *attr)
 	if (ia_valid & ATTR_CTIME)
 		inode->i_ctime = attr->ia_ctime;
 	if (ia_valid & ATTR_MODE) {
-		ADFS_I(inode)->attr = adfs_mode2atts(sb, inode);
+		ADFS_I(inode)->attr = adfs_mode2atts(sb, inode, attr->ia_mode);
 		inode->i_mode = adfs_atts2mode(sb, inode);
 	}
 
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 03/41] fs/adfs: map: move map reading and validation to map.c
  2019-12-09 11:07 [PATCH 00/41] fs/adfs updates for 5.6 Russell King - ARM Linux admin
  2019-12-09 11:08 ` [PATCH 01/41] fs/adfs: inode: update timestamps to centisecond precision Russell King
  2019-12-09 11:08 ` [PATCH 02/41] fs/adfs: inode: fix adfs_mode2atts() Russell King
@ 2019-12-09 11:08 ` Russell King
  2019-12-09 11:08 ` [PATCH 04/41] fs/adfs: map: rename adfs_map_free() to adfs_map_statfs() Russell King
                   ` (37 subsequent siblings)
  40 siblings, 0 replies; 47+ messages in thread
From: Russell King @ 2019-12-09 11:08 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel

Keep all the map code together in map.c, rather than having some in
super.c

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
 fs/adfs/adfs.h  |  1 +
 fs/adfs/map.c   | 99 +++++++++++++++++++++++++++++++++++++++++++++++++
 fs/adfs/super.c | 98 ------------------------------------------------
 3 files changed, 100 insertions(+), 98 deletions(-)

diff --git a/fs/adfs/adfs.h b/fs/adfs/adfs.h
index b7e844d2f321..d23c84aeb6dd 100644
--- a/fs/adfs/adfs.h
+++ b/fs/adfs/adfs.h
@@ -146,6 +146,7 @@ int adfs_notify_change(struct dentry *dentry, struct iattr *attr);
 /* map.c */
 int adfs_map_lookup(struct super_block *sb, u32 frag_id, unsigned int offset);
 extern unsigned int adfs_map_free(struct super_block *sb);
+struct adfs_discmap *adfs_read_map(struct super_block *sb, struct adfs_discrecord *dr);
 
 /* Misc */
 __printf(3, 4)
diff --git a/fs/adfs/map.c b/fs/adfs/map.c
index f44d12cef5be..120e01451e75 100644
--- a/fs/adfs/map.c
+++ b/fs/adfs/map.c
@@ -4,6 +4,7 @@
  *
  *  Copyright (C) 1997-2002 Russell King
  */
+#include <linux/slab.h>
 #include <asm/unaligned.h>
 #include "adfs.h"
 
@@ -280,3 +281,101 @@ int adfs_map_lookup(struct super_block *sb, u32 frag_id, unsigned int offset)
 		   frag_id, zone, asb->s_map_size);
 	return 0;
 }
+
+static unsigned char adfs_calczonecheck(struct super_block *sb, unsigned char *map)
+{
+	unsigned int v0, v1, v2, v3;
+	int i;
+
+	v0 = v1 = v2 = v3 = 0;
+	for (i = sb->s_blocksize - 4; i; i -= 4) {
+		v0 += map[i]     + (v3 >> 8);
+		v3 &= 0xff;
+		v1 += map[i + 1] + (v0 >> 8);
+		v0 &= 0xff;
+		v2 += map[i + 2] + (v1 >> 8);
+		v1 &= 0xff;
+		v3 += map[i + 3] + (v2 >> 8);
+		v2 &= 0xff;
+	}
+	v0 +=           v3 >> 8;
+	v1 += map[1] + (v0 >> 8);
+	v2 += map[2] + (v1 >> 8);
+	v3 += map[3] + (v2 >> 8);
+
+	return v0 ^ v1 ^ v2 ^ v3;
+}
+
+static int adfs_checkmap(struct super_block *sb, struct adfs_discmap *dm)
+{
+	unsigned char crosscheck = 0, zonecheck = 1;
+	int i;
+
+	for (i = 0; i < ADFS_SB(sb)->s_map_size; i++) {
+		unsigned char *map;
+
+		map = dm[i].dm_bh->b_data;
+
+		if (adfs_calczonecheck(sb, map) != map[0]) {
+			adfs_error(sb, "zone %d fails zonecheck", i);
+			zonecheck = 0;
+		}
+		crosscheck ^= map[3];
+	}
+	if (crosscheck != 0xff)
+		adfs_error(sb, "crosscheck != 0xff");
+	return crosscheck == 0xff && zonecheck;
+}
+
+struct adfs_discmap *adfs_read_map(struct super_block *sb, struct adfs_discrecord *dr)
+{
+	struct adfs_discmap *dm;
+	unsigned int map_addr, zone_size, nzones;
+	int i, zone;
+	struct adfs_sb_info *asb = ADFS_SB(sb);
+
+	nzones    = asb->s_map_size;
+	zone_size = (8 << dr->log2secsize) - le16_to_cpu(dr->zone_spare);
+	map_addr  = (nzones >> 1) * zone_size -
+		     ((nzones > 1) ? ADFS_DR_SIZE_BITS : 0);
+	map_addr  = signed_asl(map_addr, asb->s_map2blk);
+
+	asb->s_ids_per_zone = zone_size / (asb->s_idlen + 1);
+
+	dm = kmalloc_array(nzones, sizeof(*dm), GFP_KERNEL);
+	if (dm == NULL) {
+		adfs_error(sb, "not enough memory");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	for (zone = 0; zone < nzones; zone++, map_addr++) {
+		dm[zone].dm_startbit = 0;
+		dm[zone].dm_endbit   = zone_size;
+		dm[zone].dm_startblk = zone * zone_size - ADFS_DR_SIZE_BITS;
+		dm[zone].dm_bh       = sb_bread(sb, map_addr);
+
+		if (!dm[zone].dm_bh) {
+			adfs_error(sb, "unable to read map");
+			goto error_free;
+		}
+	}
+
+	/* adjust the limits for the first and last map zones */
+	i = zone - 1;
+	dm[0].dm_startblk = 0;
+	dm[0].dm_startbit = ADFS_DR_SIZE_BITS;
+	dm[i].dm_endbit   = (adfs_disc_size(dr) >> dr->log2bpmb) +
+			    (ADFS_DR_SIZE_BITS - i * zone_size);
+
+	if (adfs_checkmap(sb, dm))
+		return dm;
+
+	adfs_error(sb, "map corrupted");
+
+error_free:
+	while (--zone >= 0)
+		brelse(dm[zone].dm_bh);
+
+	kfree(dm);
+	return ERR_PTR(-EIO);
+}
diff --git a/fs/adfs/super.c b/fs/adfs/super.c
index e0eea9adb4e6..4091adb2c7ff 100644
--- a/fs/adfs/super.c
+++ b/fs/adfs/super.c
@@ -88,51 +88,6 @@ static int adfs_checkdiscrecord(struct adfs_discrecord *dr)
 	return 0;
 }
 
-static unsigned char adfs_calczonecheck(struct super_block *sb, unsigned char *map)
-{
-	unsigned int v0, v1, v2, v3;
-	int i;
-
-	v0 = v1 = v2 = v3 = 0;
-	for (i = sb->s_blocksize - 4; i; i -= 4) {
-		v0 += map[i]     + (v3 >> 8);
-		v3 &= 0xff;
-		v1 += map[i + 1] + (v0 >> 8);
-		v0 &= 0xff;
-		v2 += map[i + 2] + (v1 >> 8);
-		v1 &= 0xff;
-		v3 += map[i + 3] + (v2 >> 8);
-		v2 &= 0xff;
-	}
-	v0 +=           v3 >> 8;
-	v1 += map[1] + (v0 >> 8);
-	v2 += map[2] + (v1 >> 8);
-	v3 += map[3] + (v2 >> 8);
-
-	return v0 ^ v1 ^ v2 ^ v3;
-}
-
-static int adfs_checkmap(struct super_block *sb, struct adfs_discmap *dm)
-{
-	unsigned char crosscheck = 0, zonecheck = 1;
-	int i;
-
-	for (i = 0; i < ADFS_SB(sb)->s_map_size; i++) {
-		unsigned char *map;
-
-		map = dm[i].dm_bh->b_data;
-
-		if (adfs_calczonecheck(sb, map) != map[0]) {
-			adfs_error(sb, "zone %d fails zonecheck", i);
-			zonecheck = 0;
-		}
-		crosscheck ^= map[3];
-	}
-	if (crosscheck != 0xff)
-		adfs_error(sb, "crosscheck != 0xff");
-	return crosscheck == 0xff && zonecheck;
-}
-
 static void adfs_put_super(struct super_block *sb)
 {
 	int i;
@@ -322,59 +277,6 @@ static const struct super_operations adfs_sops = {
 	.show_options	= adfs_show_options,
 };
 
-static struct adfs_discmap *adfs_read_map(struct super_block *sb, struct adfs_discrecord *dr)
-{
-	struct adfs_discmap *dm;
-	unsigned int map_addr, zone_size, nzones;
-	int i, zone;
-	struct adfs_sb_info *asb = ADFS_SB(sb);
-
-	nzones    = asb->s_map_size;
-	zone_size = (8 << dr->log2secsize) - le16_to_cpu(dr->zone_spare);
-	map_addr  = (nzones >> 1) * zone_size -
-		     ((nzones > 1) ? ADFS_DR_SIZE_BITS : 0);
-	map_addr  = signed_asl(map_addr, asb->s_map2blk);
-
-	asb->s_ids_per_zone = zone_size / (asb->s_idlen + 1);
-
-	dm = kmalloc_array(nzones, sizeof(*dm), GFP_KERNEL);
-	if (dm == NULL) {
-		adfs_error(sb, "not enough memory");
-		return ERR_PTR(-ENOMEM);
-	}
-
-	for (zone = 0; zone < nzones; zone++, map_addr++) {
-		dm[zone].dm_startbit = 0;
-		dm[zone].dm_endbit   = zone_size;
-		dm[zone].dm_startblk = zone * zone_size - ADFS_DR_SIZE_BITS;
-		dm[zone].dm_bh       = sb_bread(sb, map_addr);
-
-		if (!dm[zone].dm_bh) {
-			adfs_error(sb, "unable to read map");
-			goto error_free;
-		}
-	}
-
-	/* adjust the limits for the first and last map zones */
-	i = zone - 1;
-	dm[0].dm_startblk = 0;
-	dm[0].dm_startbit = ADFS_DR_SIZE_BITS;
-	dm[i].dm_endbit   = (adfs_disc_size(dr) >> dr->log2bpmb) +
-			    (ADFS_DR_SIZE_BITS - i * zone_size);
-
-	if (adfs_checkmap(sb, dm))
-		return dm;
-
-	adfs_error(sb, "map corrupted");
-
-error_free:
-	while (--zone >= 0)
-		brelse(dm[zone].dm_bh);
-
-	kfree(dm);
-	return ERR_PTR(-EIO);
-}
-
 static int adfs_fill_super(struct super_block *sb, void *data, int silent)
 {
 	struct adfs_discrecord *dr;
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 04/41] fs/adfs: map: rename adfs_map_free() to adfs_map_statfs()
  2019-12-09 11:07 [PATCH 00/41] fs/adfs updates for 5.6 Russell King - ARM Linux admin
                   ` (2 preceding siblings ...)
  2019-12-09 11:08 ` [PATCH 03/41] fs/adfs: map: move map reading and validation to map.c Russell King
@ 2019-12-09 11:08 ` Russell King
  2019-12-09 11:08 ` [PATCH 05/41] fs/adfs: map: break up adfs_read_map() Russell King
                   ` (36 subsequent siblings)
  40 siblings, 0 replies; 47+ messages in thread
From: Russell King @ 2019-12-09 11:08 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel

adfs_map_free() is not obvious whether it is freeing the map or
returning the number of free blocks on the filesystem.  Rename it to
the more generic statfs() to make it clear that it's a statistic
function.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
 fs/adfs/adfs.h  |  2 +-
 fs/adfs/map.c   | 10 +++++++---
 fs/adfs/super.c |  7 ++-----
 3 files changed, 10 insertions(+), 9 deletions(-)

diff --git a/fs/adfs/adfs.h b/fs/adfs/adfs.h
index d23c84aeb6dd..45fd48fbd5e0 100644
--- a/fs/adfs/adfs.h
+++ b/fs/adfs/adfs.h
@@ -145,7 +145,7 @@ int adfs_notify_change(struct dentry *dentry, struct iattr *attr);
 
 /* map.c */
 int adfs_map_lookup(struct super_block *sb, u32 frag_id, unsigned int offset);
-extern unsigned int adfs_map_free(struct super_block *sb);
+void adfs_map_statfs(struct super_block *sb, struct kstatfs *buf);
 struct adfs_discmap *adfs_read_map(struct super_block *sb, struct adfs_discrecord *dr);
 
 /* Misc */
diff --git a/fs/adfs/map.c b/fs/adfs/map.c
index 120e01451e75..c322d37e8f91 100644
--- a/fs/adfs/map.c
+++ b/fs/adfs/map.c
@@ -5,6 +5,7 @@
  *  Copyright (C) 1997-2002 Russell King
  */
 #include <linux/slab.h>
+#include <linux/statfs.h>
 #include <asm/unaligned.h>
 #include "adfs.h"
 
@@ -221,10 +222,10 @@ static int scan_map(struct adfs_sb_info *asb, unsigned int zone,
  *  total_free = E(free_in_zone_n)
  *              nzones
  */
-unsigned int
-adfs_map_free(struct super_block *sb)
+void adfs_map_statfs(struct super_block *sb, struct kstatfs *buf)
 {
 	struct adfs_sb_info *asb = ADFS_SB(sb);
+	struct adfs_discrecord *dr = adfs_map_discrecord(asb->s_map);
 	struct adfs_discmap *dm;
 	unsigned int total = 0;
 	unsigned int zone;
@@ -236,7 +237,10 @@ adfs_map_free(struct super_block *sb)
 		total += scan_free_map(asb, dm++);
 	} while (--zone > 0);
 
-	return signed_asl(total, asb->s_map2blk);
+	buf->f_blocks  = adfs_disc_size(dr) >> sb->s_blocksize_bits;
+	buf->f_files   = asb->s_ids_per_zone * asb->s_map_size;
+	buf->f_bavail  =
+	buf->f_bfree   = signed_asl(total, asb->s_map2blk);
 }
 
 int adfs_map_lookup(struct super_block *sb, u32 frag_id, unsigned int offset)
diff --git a/fs/adfs/super.c b/fs/adfs/super.c
index 4091adb2c7ff..458824e0ca83 100644
--- a/fs/adfs/super.c
+++ b/fs/adfs/super.c
@@ -204,16 +204,13 @@ static int adfs_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
 	struct super_block *sb = dentry->d_sb;
 	struct adfs_sb_info *sbi = ADFS_SB(sb);
-	struct adfs_discrecord *dr = adfs_map_discrecord(sbi->s_map);
 	u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
 
+	adfs_map_statfs(sb, buf);
+
 	buf->f_type    = ADFS_SUPER_MAGIC;
 	buf->f_namelen = sbi->s_namelen;
 	buf->f_bsize   = sb->s_blocksize;
-	buf->f_blocks  = adfs_disc_size(dr) >> sb->s_blocksize_bits;
-	buf->f_files   = sbi->s_ids_per_zone * sbi->s_map_size;
-	buf->f_bavail  =
-	buf->f_bfree   = adfs_map_free(sb);
 	buf->f_ffree   = (long)(buf->f_bfree * buf->f_files) / (long)buf->f_blocks;
 	buf->f_fsid.val[0] = (u32)id;
 	buf->f_fsid.val[1] = (u32)(id >> 32);
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 05/41] fs/adfs: map: break up adfs_read_map()
  2019-12-09 11:07 [PATCH 00/41] fs/adfs updates for 5.6 Russell King - ARM Linux admin
                   ` (3 preceding siblings ...)
  2019-12-09 11:08 ` [PATCH 04/41] fs/adfs: map: rename adfs_map_free() to adfs_map_statfs() Russell King
@ 2019-12-09 11:08 ` Russell King
  2019-12-09 11:08 ` [PATCH 06/41] fs/adfs: map: factor out map cleanup Russell King
                   ` (35 subsequent siblings)
  40 siblings, 0 replies; 47+ messages in thread
From: Russell King @ 2019-12-09 11:08 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel

Split up adfs_read_map() into separate helpers to layout the map,
read the map, and release the map buffers.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
 fs/adfs/map.c | 80 +++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 59 insertions(+), 21 deletions(-)

diff --git a/fs/adfs/map.c b/fs/adfs/map.c
index c322d37e8f91..4b677cd5d015 100644
--- a/fs/adfs/map.c
+++ b/fs/adfs/map.c
@@ -331,12 +331,63 @@ static int adfs_checkmap(struct super_block *sb, struct adfs_discmap *dm)
 	return crosscheck == 0xff && zonecheck;
 }
 
+/*
+ * Layout the map - the first zone contains a copy of the disc record,
+ * and the last zone must be limited to the size of the filesystem.
+ */
+static void adfs_map_layout(struct adfs_discmap *dm, unsigned int nzones,
+			    struct adfs_discrecord *dr)
+{
+	unsigned int zone, zone_size;
+	u64 size;
+
+	zone_size = (8 << dr->log2secsize) - le16_to_cpu(dr->zone_spare);
+
+	dm[0].dm_bh       = NULL;
+	dm[0].dm_startblk = 0;
+	dm[0].dm_startbit = ADFS_DR_SIZE_BITS;
+	dm[0].dm_endbit   = zone_size;
+
+	for (zone = 1; zone < nzones; zone++) {
+		dm[zone].dm_bh       = NULL;
+		dm[zone].dm_startblk = zone * zone_size - ADFS_DR_SIZE_BITS;
+		dm[zone].dm_startbit = 0;
+		dm[zone].dm_endbit   = zone_size;
+	}
+
+	size = adfs_disc_size(dr) >> dr->log2bpmb;
+	size -= (nzones - 1) * zone_size - ADFS_DR_SIZE_BITS;
+	dm[nzones - 1].dm_endbit = size;
+}
+
+static int adfs_map_read(struct adfs_discmap *dm, struct super_block *sb,
+			 unsigned int map_addr, unsigned int nzones)
+{
+	unsigned int zone;
+
+	for (zone = 0; zone < nzones; zone++) {
+		dm[zone].dm_bh = sb_bread(sb, map_addr + zone);
+		if (!dm[zone].dm_bh)
+			return -EIO;
+	}
+
+	return 0;
+}
+
+static void adfs_map_relse(struct adfs_discmap *dm, unsigned int nzones)
+{
+	unsigned int zone;
+
+	for (zone = 0; zone < nzones; zone++)
+		brelse(dm[zone].dm_bh);
+}
+
 struct adfs_discmap *adfs_read_map(struct super_block *sb, struct adfs_discrecord *dr)
 {
+	struct adfs_sb_info *asb = ADFS_SB(sb);
 	struct adfs_discmap *dm;
 	unsigned int map_addr, zone_size, nzones;
-	int i, zone;
-	struct adfs_sb_info *asb = ADFS_SB(sb);
+	int ret;
 
 	nzones    = asb->s_map_size;
 	zone_size = (8 << dr->log2secsize) - le16_to_cpu(dr->zone_spare);
@@ -352,34 +403,21 @@ struct adfs_discmap *adfs_read_map(struct super_block *sb, struct adfs_discrecor
 		return ERR_PTR(-ENOMEM);
 	}
 
-	for (zone = 0; zone < nzones; zone++, map_addr++) {
-		dm[zone].dm_startbit = 0;
-		dm[zone].dm_endbit   = zone_size;
-		dm[zone].dm_startblk = zone * zone_size - ADFS_DR_SIZE_BITS;
-		dm[zone].dm_bh       = sb_bread(sb, map_addr);
+	adfs_map_layout(dm, nzones, dr);
 
-		if (!dm[zone].dm_bh) {
-			adfs_error(sb, "unable to read map");
-			goto error_free;
-		}
+	ret = adfs_map_read(dm, sb, map_addr, nzones);
+	if (ret) {
+		adfs_error(sb, "unable to read map");
+		goto error_free;
 	}
 
-	/* adjust the limits for the first and last map zones */
-	i = zone - 1;
-	dm[0].dm_startblk = 0;
-	dm[0].dm_startbit = ADFS_DR_SIZE_BITS;
-	dm[i].dm_endbit   = (adfs_disc_size(dr) >> dr->log2bpmb) +
-			    (ADFS_DR_SIZE_BITS - i * zone_size);
-
 	if (adfs_checkmap(sb, dm))
 		return dm;
 
 	adfs_error(sb, "map corrupted");
 
 error_free:
-	while (--zone >= 0)
-		brelse(dm[zone].dm_bh);
-
+	adfs_map_relse(dm, nzones);
 	kfree(dm);
 	return ERR_PTR(-EIO);
 }
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 06/41] fs/adfs: map: factor out map cleanup
  2019-12-09 11:07 [PATCH 00/41] fs/adfs updates for 5.6 Russell King - ARM Linux admin
                   ` (4 preceding siblings ...)
  2019-12-09 11:08 ` [PATCH 05/41] fs/adfs: map: break up adfs_read_map() Russell King
@ 2019-12-09 11:08 ` Russell King
  2019-12-09 11:08 ` [PATCH 07/41] fs/adfs: map: incorporate map offsets into layout Russell King
                   ` (34 subsequent siblings)
  40 siblings, 0 replies; 47+ messages in thread
From: Russell King @ 2019-12-09 11:08 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel

We have several places which deal with releasing the map buffers and
freeing the map array.  Provide a helper for this.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
 fs/adfs/adfs.h  |  1 +
 fs/adfs/map.c   |  8 ++++++++
 fs/adfs/super.c | 10 ++--------
 3 files changed, 11 insertions(+), 8 deletions(-)

diff --git a/fs/adfs/adfs.h b/fs/adfs/adfs.h
index 45fd48fbd5e0..6497da8a2c8a 100644
--- a/fs/adfs/adfs.h
+++ b/fs/adfs/adfs.h
@@ -147,6 +147,7 @@ int adfs_notify_change(struct dentry *dentry, struct iattr *attr);
 int adfs_map_lookup(struct super_block *sb, u32 frag_id, unsigned int offset);
 void adfs_map_statfs(struct super_block *sb, struct kstatfs *buf);
 struct adfs_discmap *adfs_read_map(struct super_block *sb, struct adfs_discrecord *dr);
+void adfs_free_map(struct super_block *sb);
 
 /* Misc */
 __printf(3, 4)
diff --git a/fs/adfs/map.c b/fs/adfs/map.c
index 4b677cd5d015..8ba8877110ff 100644
--- a/fs/adfs/map.c
+++ b/fs/adfs/map.c
@@ -421,3 +421,11 @@ struct adfs_discmap *adfs_read_map(struct super_block *sb, struct adfs_discrecor
 	kfree(dm);
 	return ERR_PTR(-EIO);
 }
+
+void adfs_free_map(struct super_block *sb)
+{
+	struct adfs_sb_info *asb = ADFS_SB(sb);
+
+	adfs_map_relse(asb->s_map, asb->s_map_size);
+	kfree(asb->s_map);
+}
diff --git a/fs/adfs/super.c b/fs/adfs/super.c
index 458824e0ca83..cef16028e9f2 100644
--- a/fs/adfs/super.c
+++ b/fs/adfs/super.c
@@ -90,12 +90,9 @@ static int adfs_checkdiscrecord(struct adfs_discrecord *dr)
 
 static void adfs_put_super(struct super_block *sb)
 {
-	int i;
 	struct adfs_sb_info *asb = ADFS_SB(sb);
 
-	for (i = 0; i < asb->s_map_size; i++)
-		brelse(asb->s_map[i].dm_bh);
-	kfree(asb->s_map);
+	adfs_free_map(sb);
 	kfree_rcu(asb, rcu);
 }
 
@@ -412,10 +409,7 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent)
 	root = adfs_iget(sb, &root_obj);
 	sb->s_root = d_make_root(root);
 	if (!sb->s_root) {
-		int i;
-		for (i = 0; i < asb->s_map_size; i++)
-			brelse(asb->s_map[i].dm_bh);
-		kfree(asb->s_map);
+		adfs_free_map(sb);
 		adfs_error(sb, "get root inode failed\n");
 		ret = -EIO;
 		goto error;
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 07/41] fs/adfs: map: incorporate map offsets into layout
  2019-12-09 11:07 [PATCH 00/41] fs/adfs updates for 5.6 Russell King - ARM Linux admin
                   ` (5 preceding siblings ...)
  2019-12-09 11:08 ` [PATCH 06/41] fs/adfs: map: factor out map cleanup Russell King
@ 2019-12-09 11:08 ` Russell King
  2019-12-09 11:08 ` [PATCH 08/41] fs/adfs: map: use find_next_bit_le() rather than open coding it Russell King
                   ` (33 subsequent siblings)
  40 siblings, 0 replies; 47+ messages in thread
From: Russell King @ 2019-12-09 11:08 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel

lookup_zone() and scan_free_map() cope in different ways with the
location of the map data within a zone:

1. lookup_zone() adds a four byte offset to the map data pointer to
   skip over the check and free link bytes.

2. scan_free_map() needs to use the free link pointer, which is an
   offset from itself, so we end up adding a 32-bit offset to the
   end pointer (aka mapsize) which is really confusing.

Rename mapsize to endbit as this is really what it is, and incorporate
the 32-bit offset into the map layout.  This means that both dm_startbit
and dm_endbit are now bit offsets from the start of the buffer, rather
than four bytes in to the buffer.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
 fs/adfs/map.c | 22 +++++++++++-----------
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/fs/adfs/map.c b/fs/adfs/map.c
index 8ba8877110ff..55bd7c20158c 100644
--- a/fs/adfs/map.c
+++ b/fs/adfs/map.c
@@ -68,9 +68,9 @@ static DEFINE_RWLOCK(adfs_map_lock);
 static int lookup_zone(const struct adfs_discmap *dm, const unsigned int idlen,
 		       const u32 frag_id, unsigned int *offset)
 {
-	const unsigned int mapsize = dm->dm_endbit;
+	const unsigned int endbit = dm->dm_endbit;
 	const u32 idmask = (1 << idlen) - 1;
-	unsigned char *map = dm->dm_bh->b_data + 4;
+	unsigned char *map = dm->dm_bh->b_data;
 	unsigned int start = dm->dm_startbit;
 	unsigned int mapptr;
 	u32 frag;
@@ -87,7 +87,7 @@ static int lookup_zone(const struct adfs_discmap *dm, const unsigned int idlen,
 			u32 v = le32_to_cpu(_map[mapptr >> 5]) >> (mapptr & 31);
 			while (v == 0) {
 				mapptr = (mapptr & ~31) + 32;
-				if (mapptr >= mapsize)
+				if (mapptr >= endbit)
 					goto error;
 				v = le32_to_cpu(_map[mapptr >> 5]);
 			}
@@ -99,7 +99,7 @@ static int lookup_zone(const struct adfs_discmap *dm, const unsigned int idlen,
 			goto found;
 again:
 		start = mapptr;
-	} while (mapptr < mapsize);
+	} while (mapptr < endbit);
 	return -1;
 
 error:
@@ -127,7 +127,7 @@ static int lookup_zone(const struct adfs_discmap *dm, const unsigned int idlen,
 static unsigned int
 scan_free_map(struct adfs_sb_info *asb, struct adfs_discmap *dm)
 {
-	const unsigned int mapsize = dm->dm_endbit + 32;
+	const unsigned int endbit = dm->dm_endbit;
 	const unsigned int idlen  = asb->s_idlen;
 	const unsigned int frag_idlen = idlen <= 15 ? idlen : 15;
 	const u32 idmask = (1 << frag_idlen) - 1;
@@ -165,7 +165,7 @@ scan_free_map(struct adfs_sb_info *asb, struct adfs_discmap *dm)
 			u32 v = le32_to_cpu(_map[mapptr >> 5]) >> (mapptr & 31);
 			while (v == 0) {
 				mapptr = (mapptr & ~31) + 32;
-				if (mapptr >= mapsize)
+				if (mapptr >= endbit)
 					goto error;
 				v = le32_to_cpu(_map[mapptr >> 5]);
 			}
@@ -345,19 +345,19 @@ static void adfs_map_layout(struct adfs_discmap *dm, unsigned int nzones,
 
 	dm[0].dm_bh       = NULL;
 	dm[0].dm_startblk = 0;
-	dm[0].dm_startbit = ADFS_DR_SIZE_BITS;
-	dm[0].dm_endbit   = zone_size;
+	dm[0].dm_startbit = 32 + ADFS_DR_SIZE_BITS;
+	dm[0].dm_endbit   = 32 + zone_size;
 
 	for (zone = 1; zone < nzones; zone++) {
 		dm[zone].dm_bh       = NULL;
 		dm[zone].dm_startblk = zone * zone_size - ADFS_DR_SIZE_BITS;
-		dm[zone].dm_startbit = 0;
-		dm[zone].dm_endbit   = zone_size;
+		dm[zone].dm_startbit = 32;
+		dm[zone].dm_endbit   = 32 + zone_size;
 	}
 
 	size = adfs_disc_size(dr) >> dr->log2bpmb;
 	size -= (nzones - 1) * zone_size - ADFS_DR_SIZE_BITS;
-	dm[nzones - 1].dm_endbit = size;
+	dm[nzones - 1].dm_endbit = 32 + size;
 }
 
 static int adfs_map_read(struct adfs_discmap *dm, struct super_block *sb,
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 08/41] fs/adfs: map: use find_next_bit_le() rather than open coding it
  2019-12-09 11:07 [PATCH 00/41] fs/adfs updates for 5.6 Russell King - ARM Linux admin
                   ` (6 preceding siblings ...)
  2019-12-09 11:08 ` [PATCH 07/41] fs/adfs: map: incorporate map offsets into layout Russell King
@ 2019-12-09 11:08 ` Russell King
  2019-12-09 11:08 ` [PATCH 09/41] fs/adfs: map: move map-specific sb initialisation to map.c Russell King
                   ` (32 subsequent siblings)
  40 siblings, 0 replies; 47+ messages in thread
From: Russell King @ 2019-12-09 11:08 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel

Use find_next_bit_le() to find the end of a fragment in the map rather
than open-coding this functionality.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
 fs/adfs/map.c | 76 ++++++++++++++-------------------------------------
 1 file changed, 21 insertions(+), 55 deletions(-)

diff --git a/fs/adfs/map.c b/fs/adfs/map.c
index 55bd7c20158c..9be0b47da19c 100644
--- a/fs/adfs/map.c
+++ b/fs/adfs/map.c
@@ -72,50 +72,32 @@ static int lookup_zone(const struct adfs_discmap *dm, const unsigned int idlen,
 	const u32 idmask = (1 << idlen) - 1;
 	unsigned char *map = dm->dm_bh->b_data;
 	unsigned int start = dm->dm_startbit;
-	unsigned int mapptr;
+	unsigned int fragend;
 	u32 frag;
 
 	do {
 		frag = GET_FRAG_ID(map, start, idmask);
-		mapptr = start + idlen;
-
-		/*
-		 * find end of fragment
-		 */
-		{
-			__le32 *_map = (__le32 *)map;
-			u32 v = le32_to_cpu(_map[mapptr >> 5]) >> (mapptr & 31);
-			while (v == 0) {
-				mapptr = (mapptr & ~31) + 32;
-				if (mapptr >= endbit)
-					goto error;
-				v = le32_to_cpu(_map[mapptr >> 5]);
-			}
-
-			mapptr += 1 + ffz(~v);
+
+		fragend = find_next_bit_le(map, endbit, start + idlen);
+		if (fragend >= endbit)
+			goto error;
+
+		if (frag == frag_id) {
+			unsigned int length = fragend + 1 - start;
+
+			if (*offset < length)
+				return start + *offset;
+			*offset -= length;
 		}
 
-		if (frag == frag_id)
-			goto found;
-again:
-		start = mapptr;
-	} while (mapptr < endbit);
+		start = fragend + 1;
+	} while (start < endbit);
 	return -1;
 
 error:
 	printk(KERN_ERR "adfs: oversized fragment 0x%x at 0x%x-0x%x\n",
-		frag, start, mapptr);
+		frag, start, fragend);
 	return -1;
-
-found:
-	{
-		int length = mapptr - start;
-		if (*offset >= length) {
-			*offset -= length;
-			goto again;
-		}
-	}
-	return start + *offset;
 }
 
 /*
@@ -132,7 +114,7 @@ scan_free_map(struct adfs_sb_info *asb, struct adfs_discmap *dm)
 	const unsigned int frag_idlen = idlen <= 15 ? idlen : 15;
 	const u32 idmask = (1 << frag_idlen) - 1;
 	unsigned char *map = dm->dm_bh->b_data;
-	unsigned int start = 8, mapptr;
+	unsigned int start = 8, fragend;
 	u32 frag;
 	unsigned long total = 0;
 
@@ -151,29 +133,13 @@ scan_free_map(struct adfs_sb_info *asb, struct adfs_discmap *dm)
 	do {
 		start += frag;
 
-		/*
-		 * get fragment id
-		 */
 		frag = GET_FRAG_ID(map, start, idmask);
-		mapptr = start + idlen;
-
-		/*
-		 * find end of fragment
-		 */
-		{
-			__le32 *_map = (__le32 *)map;
-			u32 v = le32_to_cpu(_map[mapptr >> 5]) >> (mapptr & 31);
-			while (v == 0) {
-				mapptr = (mapptr & ~31) + 32;
-				if (mapptr >= endbit)
-					goto error;
-				v = le32_to_cpu(_map[mapptr >> 5]);
-			}
-
-			mapptr += 1 + ffz(~v);
-		}
 
-		total += mapptr - start;
+		fragend = find_next_bit_le(map, endbit, start + idlen);
+		if (fragend >= endbit)
+			goto error;
+
+		total += fragend + 1 - start;
 	} while (frag >= idlen + 1);
 
 	if (frag != 0)
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 09/41] fs/adfs: map: move map-specific sb initialisation to map.c
  2019-12-09 11:07 [PATCH 00/41] fs/adfs updates for 5.6 Russell King - ARM Linux admin
                   ` (7 preceding siblings ...)
  2019-12-09 11:08 ` [PATCH 08/41] fs/adfs: map: use find_next_bit_le() rather than open coding it Russell King
@ 2019-12-09 11:08 ` Russell King
  2019-12-09 11:09 ` [PATCH 10/41] fs/adfs: map: fix map scanning Russell King
                   ` (31 subsequent siblings)
  40 siblings, 0 replies; 47+ messages in thread
From: Russell King @ 2019-12-09 11:08 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel

Move map specific superblock initialisation to map.c, rather than
having it spread into super.c.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
 fs/adfs/map.c   | 13 +++++++++----
 fs/adfs/super.c |  7 +------
 2 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/fs/adfs/map.c b/fs/adfs/map.c
index 9be0b47da19c..82e1bf101fe6 100644
--- a/fs/adfs/map.c
+++ b/fs/adfs/map.c
@@ -355,14 +355,19 @@ struct adfs_discmap *adfs_read_map(struct super_block *sb, struct adfs_discrecor
 	unsigned int map_addr, zone_size, nzones;
 	int ret;
 
-	nzones    = asb->s_map_size;
+	nzones    = dr->nzones | dr->nzones_high << 8;
 	zone_size = (8 << dr->log2secsize) - le16_to_cpu(dr->zone_spare);
-	map_addr  = (nzones >> 1) * zone_size -
-		     ((nzones > 1) ? ADFS_DR_SIZE_BITS : 0);
-	map_addr  = signed_asl(map_addr, asb->s_map2blk);
 
+	asb->s_idlen = dr->idlen;
+	asb->s_map_size = nzones;
+	asb->s_map2blk = dr->log2bpmb - dr->log2secsize;
+	asb->s_log2sharesize = dr->log2sharesize;
 	asb->s_ids_per_zone = zone_size / (asb->s_idlen + 1);
 
+	map_addr = (nzones >> 1) * zone_size -
+		     ((nzones > 1) ? ADFS_DR_SIZE_BITS : 0);
+	map_addr = signed_asl(map_addr, asb->s_map2blk);
+
 	dm = kmalloc_array(nzones, sizeof(*dm), GFP_KERNEL);
 	if (dm == NULL) {
 		adfs_error(sb, "not enough memory");
diff --git a/fs/adfs/super.c b/fs/adfs/super.c
index cef16028e9f2..b2455e9ab923 100644
--- a/fs/adfs/super.c
+++ b/fs/adfs/super.c
@@ -289,6 +289,7 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent)
 		return -ENOMEM;
 
 	sb->s_fs_info = asb;
+	sb->s_magic = ADFS_SUPER_MAGIC;
 	sb->s_time_gran = 10000000;
 
 	/* set default options */
@@ -356,12 +357,6 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent)
 	 * blocksize on this device should now be set to the ADFS log2secsize
 	 */
 
-	sb->s_magic		= ADFS_SUPER_MAGIC;
-	asb->s_idlen		= dr->idlen;
-	asb->s_map_size		= dr->nzones | (dr->nzones_high << 8);
-	asb->s_map2blk		= dr->log2bpmb - dr->log2secsize;
-	asb->s_log2sharesize	= dr->log2sharesize;
-
 	asb->s_map = adfs_read_map(sb, dr);
 	if (IS_ERR(asb->s_map)) {
 		ret =  PTR_ERR(asb->s_map);
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 10/41] fs/adfs: map: fix map scanning
  2019-12-09 11:07 [PATCH 00/41] fs/adfs updates for 5.6 Russell King - ARM Linux admin
                   ` (8 preceding siblings ...)
  2019-12-09 11:08 ` [PATCH 09/41] fs/adfs: map: move map-specific sb initialisation to map.c Russell King
@ 2019-12-09 11:09 ` Russell King
  2019-12-09 11:09 ` [PATCH 11/41] fs/adfs: dir: rename bh_fplus to bhs Russell King
                   ` (30 subsequent siblings)
  40 siblings, 0 replies; 47+ messages in thread
From: Russell King @ 2019-12-09 11:09 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel

When scanning the map for a fragment id, we need to keep track of the
free space links, so we don't inadvertently believe that the freespace
link is a valid fragment id.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
 fs/adfs/map.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/fs/adfs/map.c b/fs/adfs/map.c
index 82e1bf101fe6..a81de80c45c1 100644
--- a/fs/adfs/map.c
+++ b/fs/adfs/map.c
@@ -72,9 +72,12 @@ static int lookup_zone(const struct adfs_discmap *dm, const unsigned int idlen,
 	const u32 idmask = (1 << idlen) - 1;
 	unsigned char *map = dm->dm_bh->b_data;
 	unsigned int start = dm->dm_startbit;
-	unsigned int fragend;
+	unsigned int freelink, fragend;
 	u32 frag;
 
+	frag = GET_FRAG_ID(map, 8, idmask & 0x7fff);
+	freelink = frag ? 8 + frag : 0;
+
 	do {
 		frag = GET_FRAG_ID(map, start, idmask);
 
@@ -82,7 +85,9 @@ static int lookup_zone(const struct adfs_discmap *dm, const unsigned int idlen,
 		if (fragend >= endbit)
 			goto error;
 
-		if (frag == frag_id) {
+		if (start == freelink) {
+			freelink += frag & 0x7fff;
+		} else if (frag == frag_id) {
 			unsigned int length = fragend + 1 - start;
 
 			if (*offset < length)
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 11/41] fs/adfs: dir: rename bh_fplus to bhs
  2019-12-09 11:07 [PATCH 00/41] fs/adfs updates for 5.6 Russell King - ARM Linux admin
                   ` (9 preceding siblings ...)
  2019-12-09 11:09 ` [PATCH 10/41] fs/adfs: map: fix map scanning Russell King
@ 2019-12-09 11:09 ` Russell King
  2019-12-09 11:09 ` [PATCH 12/41] fs/adfs: dir: add common dir object initialisation Russell King
                   ` (29 subsequent siblings)
  40 siblings, 0 replies; 47+ messages in thread
From: Russell King @ 2019-12-09 11:09 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel

Rename bh_fplus to bhs in preparation to make some of the directory
handling code sharable between implementations.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
 fs/adfs/adfs.h      |  4 +---
 fs/adfs/dir_fplus.c | 54 ++++++++++++++++++++++-----------------------
 2 files changed, 28 insertions(+), 30 deletions(-)

diff --git a/fs/adfs/adfs.h b/fs/adfs/adfs.h
index 6497da8a2c8a..956ac0bd53e1 100644
--- a/fs/adfs/adfs.h
+++ b/fs/adfs/adfs.h
@@ -93,9 +93,7 @@ struct adfs_dir {
 
 	int			nr_buffers;
 	struct buffer_head	*bh[4];
-
-	/* big directories need allocated buffers */
-	struct buffer_head	**bh_fplus;
+	struct buffer_head	**bhs;
 
 	unsigned int		pos;
 	__u32			parent_id;
diff --git a/fs/adfs/dir_fplus.c b/fs/adfs/dir_fplus.c
index d56924c11b17..5f5420c9b943 100644
--- a/fs/adfs/dir_fplus.c
+++ b/fs/adfs/dir_fplus.c
@@ -20,7 +20,7 @@ adfs_fplus_read(struct super_block *sb, unsigned int id, unsigned int sz, struct
 	dir->nr_buffers = 0;
 
 	/* start off using fixed bh set - only alloc for big dirs */
-	dir->bh_fplus = &dir->bh[0];
+	dir->bhs = &dir->bh[0];
 
 	block = __adfs_block_map(sb, id, 0);
 	if (!block) {
@@ -28,12 +28,12 @@ adfs_fplus_read(struct super_block *sb, unsigned int id, unsigned int sz, struct
 		goto out;
 	}
 
-	dir->bh_fplus[0] = sb_bread(sb, block);
-	if (!dir->bh_fplus[0])
+	dir->bhs[0] = sb_bread(sb, block);
+	if (!dir->bhs[0])
 		goto out;
 	dir->nr_buffers += 1;
 
-	h = (struct adfs_bigdirheader *)dir->bh_fplus[0]->b_data;
+	h = (struct adfs_bigdirheader *)dir->bhs[0]->b_data;
 	size = le32_to_cpu(h->bigdirsize);
 	if (size != sz) {
 		adfs_msg(sb, KERN_WARNING,
@@ -51,19 +51,19 @@ adfs_fplus_read(struct super_block *sb, unsigned int id, unsigned int sz, struct
 	size >>= sb->s_blocksize_bits;
 	if (size > ARRAY_SIZE(dir->bh)) {
 		/* this directory is too big for fixed bh set, must allocate */
-		struct buffer_head **bh_fplus =
+		struct buffer_head **bhs =
 			kcalloc(size, sizeof(struct buffer_head *),
 				GFP_KERNEL);
-		if (!bh_fplus) {
+		if (!bhs) {
 			adfs_msg(sb, KERN_ERR,
 				 "not enough memory for dir object %X (%d blocks)",
 				 id, size);
 			ret = -ENOMEM;
 			goto out;
 		}
-		dir->bh_fplus = bh_fplus;
+		dir->bhs = bhs;
 		/* copy over the pointer to the block that we've already read */
-		dir->bh_fplus[0] = dir->bh[0];
+		dir->bhs[0] = dir->bh[0];
 	}
 
 	for (blk = 1; blk < size; blk++) {
@@ -73,8 +73,8 @@ adfs_fplus_read(struct super_block *sb, unsigned int id, unsigned int sz, struct
 			goto out;
 		}
 
-		dir->bh_fplus[blk] = sb_bread(sb, block);
-		if (!dir->bh_fplus[blk]) {
+		dir->bhs[blk] = sb_bread(sb, block);
+		if (!dir->bhs[blk]) {
 			adfs_error(sb,	"dir object %x failed read for offset %d, mapped block %lX",
 				   id, blk, block);
 			goto out;
@@ -84,7 +84,7 @@ adfs_fplus_read(struct super_block *sb, unsigned int id, unsigned int sz, struct
 	}
 
 	t = (struct adfs_bigdirtail *)
-		(dir->bh_fplus[size - 1]->b_data + (sb->s_blocksize - 8));
+		(dir->bhs[size - 1]->b_data + (sb->s_blocksize - 8));
 
 	if (t->bigdirendname != cpu_to_le32(BIGDIRENDNAME) ||
 	    t->bigdirendmasseq != h->startmasseq ||
@@ -98,14 +98,14 @@ adfs_fplus_read(struct super_block *sb, unsigned int id, unsigned int sz, struct
 	return 0;
 
 out:
-	if (dir->bh_fplus) {
+	if (dir->bhs) {
 		for (i = 0; i < dir->nr_buffers; i++)
-			brelse(dir->bh_fplus[i]);
+			brelse(dir->bhs[i]);
 
-		if (&dir->bh[0] != dir->bh_fplus)
-			kfree(dir->bh_fplus);
+		if (&dir->bh[0] != dir->bhs)
+			kfree(dir->bhs);
 
-		dir->bh_fplus = NULL;
+		dir->bhs = NULL;
 	}
 
 	dir->nr_buffers = 0;
@@ -117,7 +117,7 @@ static int
 adfs_fplus_setpos(struct adfs_dir *dir, unsigned int fpos)
 {
 	struct adfs_bigdirheader *h =
-		(struct adfs_bigdirheader *) dir->bh_fplus[0]->b_data;
+		(struct adfs_bigdirheader *) dir->bhs[0]->b_data;
 	int ret = -ENOENT;
 
 	if (fpos <= le32_to_cpu(h->bigdirentries)) {
@@ -140,18 +140,18 @@ dir_memcpy(struct adfs_dir *dir, unsigned int offset, void *to, int len)
 	partial = sb->s_blocksize - offset;
 
 	if (partial >= len)
-		memcpy(to, dir->bh_fplus[buffer]->b_data + offset, len);
+		memcpy(to, dir->bhs[buffer]->b_data + offset, len);
 	else {
 		char *c = (char *)to;
 
 		remainder = len - partial;
 
 		memcpy(c,
-			dir->bh_fplus[buffer]->b_data + offset,
+			dir->bhs[buffer]->b_data + offset,
 			partial);
 
 		memcpy(c + partial,
-			dir->bh_fplus[buffer + 1]->b_data,
+			dir->bhs[buffer + 1]->b_data,
 			remainder);
 	}
 }
@@ -160,7 +160,7 @@ static int
 adfs_fplus_getnext(struct adfs_dir *dir, struct object_info *obj)
 {
 	struct adfs_bigdirheader *h =
-		(struct adfs_bigdirheader *) dir->bh_fplus[0]->b_data;
+		(struct adfs_bigdirheader *) dir->bhs[0]->b_data;
 	struct adfs_bigdirentry bde;
 	unsigned int offset;
 	int ret = -ENOENT;
@@ -202,7 +202,7 @@ adfs_fplus_sync(struct adfs_dir *dir)
 	int i;
 
 	for (i = dir->nr_buffers - 1; i >= 0; i--) {
-		struct buffer_head *bh = dir->bh_fplus[i];
+		struct buffer_head *bh = dir->bhs[i];
 		sync_dirty_buffer(bh);
 		if (buffer_req(bh) && !buffer_uptodate(bh))
 			err = -EIO;
@@ -216,14 +216,14 @@ adfs_fplus_free(struct adfs_dir *dir)
 {
 	int i;
 
-	if (dir->bh_fplus) {
+	if (dir->bhs) {
 		for (i = 0; i < dir->nr_buffers; i++)
-			brelse(dir->bh_fplus[i]);
+			brelse(dir->bhs[i]);
 
-		if (&dir->bh[0] != dir->bh_fplus)
-			kfree(dir->bh_fplus);
+		if (&dir->bh[0] != dir->bhs)
+			kfree(dir->bhs);
 
-		dir->bh_fplus = NULL;
+		dir->bhs = NULL;
 	}
 
 	dir->nr_buffers = 0;
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 12/41] fs/adfs: dir: add common dir object initialisation
  2019-12-09 11:07 [PATCH 00/41] fs/adfs updates for 5.6 Russell King - ARM Linux admin
                   ` (10 preceding siblings ...)
  2019-12-09 11:09 ` [PATCH 11/41] fs/adfs: dir: rename bh_fplus to bhs Russell King
@ 2019-12-09 11:09 ` Russell King
  2019-12-09 11:09 ` [PATCH 13/41] fs/adfs: dir: add common directory buffer release method Russell King
                   ` (28 subsequent siblings)
  40 siblings, 0 replies; 47+ messages in thread
From: Russell King @ 2019-12-09 11:09 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel

Initialise the dir object before we pass it down to the directory format
specific read handler.  This allows us to get rid of the initialisation
inside those handlers.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
 fs/adfs/dir.c       | 16 +++++++++++++---
 fs/adfs/dir_f.c     |  3 ---
 fs/adfs/dir_fplus.c |  6 ------
 3 files changed, 13 insertions(+), 12 deletions(-)

diff --git a/fs/adfs/dir.c b/fs/adfs/dir.c
index a54c53244992..c1b8b5bccbec 100644
--- a/fs/adfs/dir.c
+++ b/fs/adfs/dir.c
@@ -13,6 +13,16 @@
  */
 static DEFINE_RWLOCK(adfs_dir_lock);
 
+static int adfs_dir_read(struct super_block *sb, u32 indaddr,
+			 unsigned int size, struct adfs_dir *dir)
+{
+	dir->sb = sb;
+	dir->bhs = dir->bh;
+	dir->nr_buffers = 0;
+
+	return ADFS_SB(sb)->s_dir->read(sb, indaddr, size, dir);
+}
+
 void adfs_object_fixup(struct adfs_dir *dir, struct object_info *obj)
 {
 	unsigned int dots, i;
@@ -64,7 +74,7 @@ adfs_readdir(struct file *file, struct dir_context *ctx)
 	if (ctx->pos >> 32)
 		return 0;
 
-	ret = ops->read(sb, inode->i_ino, inode->i_size, &dir);
+	ret = adfs_dir_read(sb, inode->i_ino, inode->i_size, &dir);
 	if (ret)
 		return ret;
 
@@ -115,7 +125,7 @@ adfs_dir_update(struct super_block *sb, struct object_info *obj, int wait)
 		goto out;
 	}
 
-	ret = ops->read(sb, obj->parent_id, 0, &dir);
+	ret = adfs_dir_read(sb, obj->parent_id, 0, &dir);
 	if (ret)
 		goto out;
 
@@ -167,7 +177,7 @@ static int adfs_dir_lookup_byname(struct inode *inode, const struct qstr *qstr,
 	u32 name_len;
 	int ret;
 
-	ret = ops->read(sb, inode->i_ino, inode->i_size, &dir);
+	ret = adfs_dir_read(sb, inode->i_ino, inode->i_size, &dir);
 	if (ret)
 		goto out;
 
diff --git a/fs/adfs/dir_f.c b/fs/adfs/dir_f.c
index c1a950c7400a..e62f35eb7789 100644
--- a/fs/adfs/dir_f.c
+++ b/fs/adfs/dir_f.c
@@ -139,9 +139,6 @@ static int adfs_dir_read(struct super_block *sb, u32 indaddr,
 
 	size >>= blocksize_bits;
 
-	dir->nr_buffers = 0;
-	dir->sb = sb;
-
 	for (blk = 0; blk < size; blk++) {
 		int phys;
 
diff --git a/fs/adfs/dir_fplus.c b/fs/adfs/dir_fplus.c
index 5f5420c9b943..52c42a9986d9 100644
--- a/fs/adfs/dir_fplus.c
+++ b/fs/adfs/dir_fplus.c
@@ -17,11 +17,6 @@ adfs_fplus_read(struct super_block *sb, unsigned int id, unsigned int sz, struct
 	unsigned int blk, size;
 	int i, ret = -EIO;
 
-	dir->nr_buffers = 0;
-
-	/* start off using fixed bh set - only alloc for big dirs */
-	dir->bhs = &dir->bh[0];
-
 	block = __adfs_block_map(sb, id, 0);
 	if (!block) {
 		adfs_error(sb, "dir object %X has a hole at offset 0", id);
@@ -94,7 +89,6 @@ adfs_fplus_read(struct super_block *sb, unsigned int id, unsigned int sz, struct
 	}
 
 	dir->parent_id = le32_to_cpu(h->bigdirparent);
-	dir->sb = sb;
 	return 0;
 
 out:
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 13/41] fs/adfs: dir: add common directory buffer release method
  2019-12-09 11:07 [PATCH 00/41] fs/adfs updates for 5.6 Russell King - ARM Linux admin
                   ` (11 preceding siblings ...)
  2019-12-09 11:09 ` [PATCH 12/41] fs/adfs: dir: add common dir object initialisation Russell King
@ 2019-12-09 11:09 ` Russell King
  2019-12-09 11:09 ` [PATCH 14/41] fs/adfs: dir: add common directory sync method Russell King
                   ` (27 subsequent siblings)
  40 siblings, 0 replies; 47+ messages in thread
From: Russell King @ 2019-12-09 11:09 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel

With the bhs pointer in place, we have no need for separate per-format
free() methods, since a generic version will do.  Provide a generic
implementation, remove the format specific implementations and the
method function pointer.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
 fs/adfs/adfs.h      |  2 +-
 fs/adfs/dir.c       | 21 ++++++++++++++++++---
 fs/adfs/dir_f.c     | 28 ++++------------------------
 fs/adfs/dir_fplus.c | 34 ++--------------------------------
 4 files changed, 25 insertions(+), 60 deletions(-)

diff --git a/fs/adfs/adfs.h b/fs/adfs/adfs.h
index 956ac0bd53e1..3bb6fd5b5eb0 100644
--- a/fs/adfs/adfs.h
+++ b/fs/adfs/adfs.h
@@ -126,7 +126,6 @@ struct adfs_dir_ops {
 	int	(*create)(struct adfs_dir *dir, struct object_info *obj);
 	int	(*remove)(struct adfs_dir *dir, struct object_info *obj);
 	int	(*sync)(struct adfs_dir *dir);
-	void	(*free)(struct adfs_dir *dir);
 };
 
 struct adfs_discmap {
@@ -167,6 +166,7 @@ extern const struct dentry_operations adfs_dentry_operations;
 extern const struct adfs_dir_ops adfs_f_dir_ops;
 extern const struct adfs_dir_ops adfs_fplus_dir_ops;
 
+void adfs_dir_relse(struct adfs_dir *dir);
 void adfs_object_fixup(struct adfs_dir *dir, struct object_info *obj);
 extern int adfs_dir_update(struct super_block *sb, struct object_info *obj,
 			   int wait);
diff --git a/fs/adfs/dir.c b/fs/adfs/dir.c
index c1b8b5bccbec..f50302775504 100644
--- a/fs/adfs/dir.c
+++ b/fs/adfs/dir.c
@@ -6,6 +6,7 @@
  *
  *  Common directory handling for ADFS
  */
+#include <linux/slab.h>
 #include "adfs.h"
 
 /*
@@ -13,6 +14,20 @@
  */
 static DEFINE_RWLOCK(adfs_dir_lock);
 
+void adfs_dir_relse(struct adfs_dir *dir)
+{
+	unsigned int i;
+
+	for (i = 0; i < dir->nr_buffers; i++)
+		brelse(dir->bhs[i]);
+	dir->nr_buffers = 0;
+
+	if (dir->bhs != dir->bh)
+		kfree(dir->bhs);
+	dir->bhs = NULL;
+	dir->sb = NULL;
+}
+
 static int adfs_dir_read(struct super_block *sb, u32 indaddr,
 			 unsigned int size, struct adfs_dir *dir)
 {
@@ -105,7 +120,7 @@ adfs_readdir(struct file *file, struct dir_context *ctx)
 	read_unlock(&adfs_dir_lock);
 
 free_out:
-	ops->free(&dir);
+	adfs_dir_relse(&dir);
 	return ret;
 }
 
@@ -139,7 +154,7 @@ adfs_dir_update(struct super_block *sb, struct object_info *obj, int wait)
 			ret = err;
 	}
 
-	ops->free(&dir);
+	adfs_dir_relse(&dir);
 out:
 #endif
 	return ret;
@@ -211,7 +226,7 @@ static int adfs_dir_lookup_byname(struct inode *inode, const struct qstr *qstr,
 	read_unlock(&adfs_dir_lock);
 
 free_out:
-	ops->free(&dir);
+	adfs_dir_relse(&dir);
 out:
 	return ret;
 }
diff --git a/fs/adfs/dir_f.c b/fs/adfs/dir_f.c
index e62f35eb7789..e249fdb915fa 100644
--- a/fs/adfs/dir_f.c
+++ b/fs/adfs/dir_f.c
@@ -9,8 +9,6 @@
 #include "adfs.h"
 #include "dir_f.h"
 
-static void adfs_f_free(struct adfs_dir *dir);
-
 /*
  * Read an (unaligned) value of length 1..4 bytes
  */
@@ -128,7 +126,7 @@ static int adfs_dir_read(struct super_block *sb, u32 indaddr,
 			 unsigned int size, struct adfs_dir *dir)
 {
 	const unsigned int blocksize_bits = sb->s_blocksize_bits;
-	int blk = 0;
+	int blk;
 
 	/*
 	 * Directories which are not a multiple of 2048 bytes
@@ -152,6 +150,8 @@ static int adfs_dir_read(struct super_block *sb, u32 indaddr,
 		dir->bh[blk] = sb_bread(sb, phys);
 		if (!dir->bh[blk])
 			goto release_buffers;
+
+		dir->nr_buffers += 1;
 	}
 
 	memcpy(&dir->dirhead, bufoff(dir->bh, 0), sizeof(dir->dirhead));
@@ -168,17 +168,12 @@ static int adfs_dir_read(struct super_block *sb, u32 indaddr,
 	if (adfs_dir_checkbyte(dir) != dir->dirtail.new.dircheckbyte)
 		goto bad_dir;
 
-	dir->nr_buffers = blk;
-
 	return 0;
 
 bad_dir:
 	adfs_error(sb, "dir %06x is corrupted", indaddr);
 release_buffers:
-	for (blk -= 1; blk >= 0; blk -= 1)
-		brelse(dir->bh[blk]);
-
-	dir->sb = NULL;
+	adfs_dir_relse(dir);
 
 	return -EIO;
 }
@@ -435,25 +430,10 @@ adfs_f_sync(struct adfs_dir *dir)
 	return err;
 }
 
-static void
-adfs_f_free(struct adfs_dir *dir)
-{
-	int i;
-
-	for (i = dir->nr_buffers - 1; i >= 0; i--) {
-		brelse(dir->bh[i]);
-		dir->bh[i] = NULL;
-	}
-
-	dir->nr_buffers = 0;
-	dir->sb = NULL;
-}
-
 const struct adfs_dir_ops adfs_f_dir_ops = {
 	.read		= adfs_f_read,
 	.setpos		= adfs_f_setpos,
 	.getnext	= adfs_f_getnext,
 	.update		= adfs_f_update,
 	.sync		= adfs_f_sync,
-	.free		= adfs_f_free
 };
diff --git a/fs/adfs/dir_fplus.c b/fs/adfs/dir_fplus.c
index 52c42a9986d9..25308b334dd3 100644
--- a/fs/adfs/dir_fplus.c
+++ b/fs/adfs/dir_fplus.c
@@ -15,7 +15,7 @@ adfs_fplus_read(struct super_block *sb, unsigned int id, unsigned int sz, struct
 	struct adfs_bigdirtail *t;
 	unsigned long block;
 	unsigned int blk, size;
-	int i, ret = -EIO;
+	int ret = -EIO;
 
 	block = __adfs_block_map(sb, id, 0);
 	if (!block) {
@@ -92,18 +92,8 @@ adfs_fplus_read(struct super_block *sb, unsigned int id, unsigned int sz, struct
 	return 0;
 
 out:
-	if (dir->bhs) {
-		for (i = 0; i < dir->nr_buffers; i++)
-			brelse(dir->bhs[i]);
+	adfs_dir_relse(dir);
 
-		if (&dir->bh[0] != dir->bhs)
-			kfree(dir->bhs);
-
-		dir->bhs = NULL;
-	}
-
-	dir->nr_buffers = 0;
-	dir->sb = NULL;
 	return ret;
 }
 
@@ -205,29 +195,9 @@ adfs_fplus_sync(struct adfs_dir *dir)
 	return err;
 }
 
-static void
-adfs_fplus_free(struct adfs_dir *dir)
-{
-	int i;
-
-	if (dir->bhs) {
-		for (i = 0; i < dir->nr_buffers; i++)
-			brelse(dir->bhs[i]);
-
-		if (&dir->bh[0] != dir->bhs)
-			kfree(dir->bhs);
-
-		dir->bhs = NULL;
-	}
-
-	dir->nr_buffers = 0;
-	dir->sb = NULL;
-}
-
 const struct adfs_dir_ops adfs_fplus_dir_ops = {
 	.read		= adfs_fplus_read,
 	.setpos		= adfs_fplus_setpos,
 	.getnext	= adfs_fplus_getnext,
 	.sync		= adfs_fplus_sync,
-	.free		= adfs_fplus_free
 };
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 14/41] fs/adfs: dir: add common directory sync method
  2019-12-09 11:07 [PATCH 00/41] fs/adfs updates for 5.6 Russell King - ARM Linux admin
                   ` (12 preceding siblings ...)
  2019-12-09 11:09 ` [PATCH 13/41] fs/adfs: dir: add common directory buffer release method Russell King
@ 2019-12-09 11:09 ` Russell King
  2019-12-09 11:09 ` [PATCH 15/41] fs/adfs: dir: add generic copy functions Russell King
                   ` (26 subsequent siblings)
  40 siblings, 0 replies; 47+ messages in thread
From: Russell King @ 2019-12-09 11:09 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel

adfs_fplus_sync() can be used for both directory formats since we now
have a common way to access the buffer heads, so move it into dir.c
and appropriately rename it.  Remove the directory-format specific
implementations.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
 fs/adfs/adfs.h      |  1 -
 fs/adfs/dir.c       | 23 ++++++++++++++++++-----
 fs/adfs/dir_f.c     | 17 -----------------
 fs/adfs/dir_fplus.c | 17 -----------------
 4 files changed, 18 insertions(+), 40 deletions(-)

diff --git a/fs/adfs/adfs.h b/fs/adfs/adfs.h
index 3bb6fd5b5eb0..5f1acee768f5 100644
--- a/fs/adfs/adfs.h
+++ b/fs/adfs/adfs.h
@@ -125,7 +125,6 @@ struct adfs_dir_ops {
 	int	(*update)(struct adfs_dir *dir, struct object_info *obj);
 	int	(*create)(struct adfs_dir *dir, struct object_info *obj);
 	int	(*remove)(struct adfs_dir *dir, struct object_info *obj);
-	int	(*sync)(struct adfs_dir *dir);
 };
 
 struct adfs_discmap {
diff --git a/fs/adfs/dir.c b/fs/adfs/dir.c
index f50302775504..16a2639d3ca5 100644
--- a/fs/adfs/dir.c
+++ b/fs/adfs/dir.c
@@ -38,6 +38,21 @@ static int adfs_dir_read(struct super_block *sb, u32 indaddr,
 	return ADFS_SB(sb)->s_dir->read(sb, indaddr, size, dir);
 }
 
+static int adfs_dir_sync(struct adfs_dir *dir)
+{
+	int err = 0;
+	int i;
+
+	for (i = dir->nr_buffers - 1; i >= 0; i--) {
+		struct buffer_head *bh = dir->bhs[i];
+		sync_dirty_buffer(bh);
+		if (buffer_req(bh) && !buffer_uptodate(bh))
+			err = -EIO;
+	}
+
+	return err;
+}
+
 void adfs_object_fixup(struct adfs_dir *dir, struct object_info *obj)
 {
 	unsigned int dots, i;
@@ -135,10 +150,8 @@ adfs_dir_update(struct super_block *sb, struct object_info *obj, int wait)
 	printk(KERN_INFO "adfs_dir_update: object %06x in dir %06x\n",
 		 obj->indaddr, obj->parent_id);
 
-	if (!ops->update) {
-		ret = -EINVAL;
-		goto out;
-	}
+	if (!ops->update)
+		return -EINVAL;
 
 	ret = adfs_dir_read(sb, obj->parent_id, 0, &dir);
 	if (ret)
@@ -149,7 +162,7 @@ adfs_dir_update(struct super_block *sb, struct object_info *obj, int wait)
 	write_unlock(&adfs_dir_lock);
 
 	if (wait) {
-		int err = ops->sync(&dir);
+		int err = adfs_dir_sync(&dir);
 		if (!ret)
 			ret = err;
 	}
diff --git a/fs/adfs/dir_f.c b/fs/adfs/dir_f.c
index e249fdb915fa..80ac261b9ec4 100644
--- a/fs/adfs/dir_f.c
+++ b/fs/adfs/dir_f.c
@@ -414,26 +414,9 @@ adfs_f_update(struct adfs_dir *dir, struct object_info *obj)
 #endif
 }
 
-static int
-adfs_f_sync(struct adfs_dir *dir)
-{
-	int err = 0;
-	int i;
-
-	for (i = dir->nr_buffers - 1; i >= 0; i--) {
-		struct buffer_head *bh = dir->bh[i];
-		sync_dirty_buffer(bh);
-		if (buffer_req(bh) && !buffer_uptodate(bh))
-			err = -EIO;
-	}
-
-	return err;
-}
-
 const struct adfs_dir_ops adfs_f_dir_ops = {
 	.read		= adfs_f_read,
 	.setpos		= adfs_f_setpos,
 	.getnext	= adfs_f_getnext,
 	.update		= adfs_f_update,
-	.sync		= adfs_f_sync,
 };
diff --git a/fs/adfs/dir_fplus.c b/fs/adfs/dir_fplus.c
index 25308b334dd3..1196c8962feb 100644
--- a/fs/adfs/dir_fplus.c
+++ b/fs/adfs/dir_fplus.c
@@ -179,25 +179,8 @@ adfs_fplus_getnext(struct adfs_dir *dir, struct object_info *obj)
 	return ret;
 }
 
-static int
-adfs_fplus_sync(struct adfs_dir *dir)
-{
-	int err = 0;
-	int i;
-
-	for (i = dir->nr_buffers - 1; i >= 0; i--) {
-		struct buffer_head *bh = dir->bhs[i];
-		sync_dirty_buffer(bh);
-		if (buffer_req(bh) && !buffer_uptodate(bh))
-			err = -EIO;
-	}
-
-	return err;
-}
-
 const struct adfs_dir_ops adfs_fplus_dir_ops = {
 	.read		= adfs_fplus_read,
 	.setpos		= adfs_fplus_setpos,
 	.getnext	= adfs_fplus_getnext,
-	.sync		= adfs_fplus_sync,
 };
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 15/41] fs/adfs: dir: add generic copy functions
  2019-12-09 11:07 [PATCH 00/41] fs/adfs updates for 5.6 Russell King - ARM Linux admin
                   ` (13 preceding siblings ...)
  2019-12-09 11:09 ` [PATCH 14/41] fs/adfs: dir: add common directory sync method Russell King
@ 2019-12-09 11:09 ` Russell King
  2019-12-09 11:09 ` [PATCH 16/41] fs/adfs: dir: add generic directory reading Russell King
                   ` (25 subsequent siblings)
  40 siblings, 0 replies; 47+ messages in thread
From: Russell King @ 2019-12-09 11:09 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel

Directories can span multiple buffers, and we currently open-code
memcpy access to these buffers, including dealing with entries that
are split across multiple buffers.  Such code exists in both
directory format implementations.

Provide common functions to allow data to be copied from/to the
directory buffers as if they were a contiguous set of buffers, and
use them when accessing directories.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
 fs/adfs/adfs.h      |  4 ++++
 fs/adfs/dir.c       | 50 ++++++++++++++++++++++++++++++++++++++++
 fs/adfs/dir_f.c     | 56 ++++++++-------------------------------------
 fs/adfs/dir_fplus.c | 47 ++++++++++---------------------------
 4 files changed, 75 insertions(+), 82 deletions(-)

diff --git a/fs/adfs/adfs.h b/fs/adfs/adfs.h
index 5f1acee768f5..92cbc4b1d902 100644
--- a/fs/adfs/adfs.h
+++ b/fs/adfs/adfs.h
@@ -165,6 +165,10 @@ extern const struct dentry_operations adfs_dentry_operations;
 extern const struct adfs_dir_ops adfs_f_dir_ops;
 extern const struct adfs_dir_ops adfs_fplus_dir_ops;
 
+int adfs_dir_copyfrom(void *dst, struct adfs_dir *dir, unsigned int offset,
+		      size_t len);
+int adfs_dir_copyto(struct adfs_dir *dir, unsigned int offset, const void *src,
+		    size_t len);
 void adfs_dir_relse(struct adfs_dir *dir);
 void adfs_object_fixup(struct adfs_dir *dir, struct object_info *obj);
 extern int adfs_dir_update(struct super_block *sb, struct object_info *obj,
diff --git a/fs/adfs/dir.c b/fs/adfs/dir.c
index 16a2639d3ca5..3c303074aa5e 100644
--- a/fs/adfs/dir.c
+++ b/fs/adfs/dir.c
@@ -14,6 +14,56 @@
  */
 static DEFINE_RWLOCK(adfs_dir_lock);
 
+int adfs_dir_copyfrom(void *dst, struct adfs_dir *dir, unsigned int offset,
+		      size_t len)
+{
+	struct super_block *sb = dir->sb;
+	unsigned int index, remain;
+
+	index = offset >> sb->s_blocksize_bits;
+	offset &= sb->s_blocksize - 1;
+	remain = sb->s_blocksize - offset;
+	if (index + (remain < len) >= dir->nr_buffers)
+		return -EINVAL;
+
+	if (remain < len) {
+		memcpy(dst, dir->bhs[index]->b_data + offset, remain);
+		dst += remain;
+		len -= remain;
+		index += 1;
+		offset = 0;
+	}
+
+	memcpy(dst, dir->bhs[index]->b_data + offset, len);
+
+	return 0;
+}
+
+int adfs_dir_copyto(struct adfs_dir *dir, unsigned int offset, const void *src,
+		    size_t len)
+{
+	struct super_block *sb = dir->sb;
+	unsigned int index, remain;
+
+	index = offset >> sb->s_blocksize_bits;
+	offset &= sb->s_blocksize - 1;
+	remain = sb->s_blocksize - offset;
+	if (index + (remain < len) >= dir->nr_buffers)
+		return -EINVAL;
+
+	if (remain < len) {
+		memcpy(dir->bhs[index]->b_data + offset, src, remain);
+		src += remain;
+		len -= remain;
+		index += 1;
+		offset = 0;
+	}
+
+	memcpy(dir->bhs[index]->b_data + offset, src, len);
+
+	return 0;
+}
+
 void adfs_dir_relse(struct adfs_dir *dir)
 {
 	unsigned int i;
diff --git a/fs/adfs/dir_f.c b/fs/adfs/dir_f.c
index 80ac261b9ec4..3c3b423577d2 100644
--- a/fs/adfs/dir_f.c
+++ b/fs/adfs/dir_f.c
@@ -224,24 +224,12 @@ adfs_obj2dir(struct adfs_direntry *de, struct object_info *obj)
 static int
 __adfs_dir_get(struct adfs_dir *dir, int pos, struct object_info *obj)
 {
-	struct super_block *sb = dir->sb;
 	struct adfs_direntry de;
-	int thissize, buffer, offset;
-
-	buffer = pos >> sb->s_blocksize_bits;
-
-	if (buffer > dir->nr_buffers)
-		return -EINVAL;
-
-	offset = pos & (sb->s_blocksize - 1);
-	thissize = sb->s_blocksize - offset;
-	if (thissize > 26)
-		thissize = 26;
+	int ret;
 
-	memcpy(&de, dir->bh[buffer]->b_data + offset, thissize);
-	if (thissize != 26)
-		memcpy(((char *)&de) + thissize, dir->bh[buffer + 1]->b_data,
-		       26 - thissize);
+	ret = adfs_dir_copyfrom(&de, dir, pos, 26);
+	if (ret)
+		return ret;
 
 	if (!de.dirobname[0])
 		return -ENOENT;
@@ -254,42 +242,16 @@ __adfs_dir_get(struct adfs_dir *dir, int pos, struct object_info *obj)
 static int
 __adfs_dir_put(struct adfs_dir *dir, int pos, struct object_info *obj)
 {
-	struct super_block *sb = dir->sb;
 	struct adfs_direntry de;
-	int thissize, buffer, offset;
-
-	buffer = pos >> sb->s_blocksize_bits;
-
-	if (buffer > dir->nr_buffers)
-		return -EINVAL;
-
-	offset = pos & (sb->s_blocksize - 1);
-	thissize = sb->s_blocksize - offset;
-	if (thissize > 26)
-		thissize = 26;
+	int ret;
 
-	/*
-	 * Get the entry in total
-	 */
-	memcpy(&de, dir->bh[buffer]->b_data + offset, thissize);
-	if (thissize != 26)
-		memcpy(((char *)&de) + thissize, dir->bh[buffer + 1]->b_data,
-		       26 - thissize);
+	ret = adfs_dir_copyfrom(&de, dir, pos, 26);
+	if (ret)
+		return ret;
 
-	/*
-	 * update it
-	 */
 	adfs_obj2dir(&de, obj);
 
-	/*
-	 * Put the new entry back
-	 */
-	memcpy(dir->bh[buffer]->b_data + offset, &de, thissize);
-	if (thissize != 26)
-		memcpy(dir->bh[buffer + 1]->b_data, ((char *)&de) + thissize,
-		       26 - thissize);
-
-	return 0;
+	return adfs_dir_copyto(dir, pos, &de, 26);
 }
 
 /*
diff --git a/fs/adfs/dir_fplus.c b/fs/adfs/dir_fplus.c
index 1196c8962feb..6a07c0dfcc93 100644
--- a/fs/adfs/dir_fplus.c
+++ b/fs/adfs/dir_fplus.c
@@ -112,34 +112,6 @@ adfs_fplus_setpos(struct adfs_dir *dir, unsigned int fpos)
 	return ret;
 }
 
-static void
-dir_memcpy(struct adfs_dir *dir, unsigned int offset, void *to, int len)
-{
-	struct super_block *sb = dir->sb;
-	unsigned int buffer, partial, remainder;
-
-	buffer = offset >> sb->s_blocksize_bits;
-	offset &= sb->s_blocksize - 1;
-
-	partial = sb->s_blocksize - offset;
-
-	if (partial >= len)
-		memcpy(to, dir->bhs[buffer]->b_data + offset, len);
-	else {
-		char *c = (char *)to;
-
-		remainder = len - partial;
-
-		memcpy(c,
-			dir->bhs[buffer]->b_data + offset,
-			partial);
-
-		memcpy(c + partial,
-			dir->bhs[buffer + 1]->b_data,
-			remainder);
-	}
-}
-
 static int
 adfs_fplus_getnext(struct adfs_dir *dir, struct object_info *obj)
 {
@@ -147,16 +119,19 @@ adfs_fplus_getnext(struct adfs_dir *dir, struct object_info *obj)
 		(struct adfs_bigdirheader *) dir->bhs[0]->b_data;
 	struct adfs_bigdirentry bde;
 	unsigned int offset;
-	int ret = -ENOENT;
+	int ret;
 
 	if (dir->pos >= le32_to_cpu(h->bigdirentries))
-		goto out;
+		return -ENOENT;
 
 	offset = offsetof(struct adfs_bigdirheader, bigdirname);
 	offset += ((le32_to_cpu(h->bigdirnamelen) + 4) & ~3);
 	offset += dir->pos * sizeof(struct adfs_bigdirentry);
 
-	dir_memcpy(dir, offset, &bde, sizeof(struct adfs_bigdirentry));
+	ret = adfs_dir_copyfrom(&bde, dir, offset,
+				sizeof(struct adfs_bigdirentry));
+	if (ret)
+		return ret;
 
 	obj->loadaddr = le32_to_cpu(bde.bigdirload);
 	obj->execaddr = le32_to_cpu(bde.bigdirexec);
@@ -170,13 +145,15 @@ adfs_fplus_getnext(struct adfs_dir *dir, struct object_info *obj)
 	offset += le32_to_cpu(h->bigdirentries) * sizeof(struct adfs_bigdirentry);
 	offset += le32_to_cpu(bde.bigdirobnameptr);
 
-	dir_memcpy(dir, offset, obj->name, obj->name_len);
+	ret = adfs_dir_copyfrom(obj->name, dir, offset, obj->name_len);
+	if (ret)
+		return ret;
+
 	adfs_object_fixup(dir, obj);
 
 	dir->pos += 1;
-	ret = 0;
-out:
-	return ret;
+
+	return 0;
 }
 
 const struct adfs_dir_ops adfs_fplus_dir_ops = {
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 16/41] fs/adfs: dir: add generic directory reading
  2019-12-09 11:07 [PATCH 00/41] fs/adfs updates for 5.6 Russell King - ARM Linux admin
                   ` (14 preceding siblings ...)
  2019-12-09 11:09 ` [PATCH 15/41] fs/adfs: dir: add generic copy functions Russell King
@ 2019-12-09 11:09 ` Russell King
  2019-12-09 11:09 ` [PATCH 17/41] fs/adfs: dir: add helper to read directory using inode Russell King
                   ` (24 subsequent siblings)
  40 siblings, 0 replies; 47+ messages in thread
From: Russell King @ 2019-12-09 11:09 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel

Both directory formats code the mechanics of fetching the directory
buffers using their own implementations.  Consolidate these into one
implementation.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
 fs/adfs/adfs.h      |  2 ++
 fs/adfs/dir.c       | 49 +++++++++++++++++++++++++++++
 fs/adfs/dir_f.c     | 24 +++-----------
 fs/adfs/dir_fplus.c | 76 ++++++++++++---------------------------------
 4 files changed, 74 insertions(+), 77 deletions(-)

diff --git a/fs/adfs/adfs.h b/fs/adfs/adfs.h
index 92cbc4b1d902..01d065937c01 100644
--- a/fs/adfs/adfs.h
+++ b/fs/adfs/adfs.h
@@ -170,6 +170,8 @@ int adfs_dir_copyfrom(void *dst, struct adfs_dir *dir, unsigned int offset,
 int adfs_dir_copyto(struct adfs_dir *dir, unsigned int offset, const void *src,
 		    size_t len);
 void adfs_dir_relse(struct adfs_dir *dir);
+int adfs_dir_read_buffers(struct super_block *sb, u32 indaddr,
+			  unsigned int size, struct adfs_dir *dir);
 void adfs_object_fixup(struct adfs_dir *dir, struct object_info *obj);
 extern int adfs_dir_update(struct super_block *sb, struct object_info *obj,
 			   int wait);
diff --git a/fs/adfs/dir.c b/fs/adfs/dir.c
index 3c303074aa5e..b8e2a909fa3f 100644
--- a/fs/adfs/dir.c
+++ b/fs/adfs/dir.c
@@ -78,6 +78,55 @@ void adfs_dir_relse(struct adfs_dir *dir)
 	dir->sb = NULL;
 }
 
+int adfs_dir_read_buffers(struct super_block *sb, u32 indaddr,
+			  unsigned int size, struct adfs_dir *dir)
+{
+	struct buffer_head **bhs;
+	unsigned int i, num;
+	int block;
+
+	num = ALIGN(size, sb->s_blocksize) >> sb->s_blocksize_bits;
+	if (num > ARRAY_SIZE(dir->bh)) {
+		/* We only allow one extension */
+		if (dir->bhs != dir->bh)
+			return -EINVAL;
+
+		bhs = kcalloc(num, sizeof(*bhs), GFP_KERNEL);
+		if (!bhs)
+			return -ENOMEM;
+
+		if (dir->nr_buffers)
+			memcpy(bhs, dir->bhs, dir->nr_buffers * sizeof(*bhs));
+
+		dir->bhs = bhs;
+	}
+
+	for (i = dir->nr_buffers; i < num; i++) {
+		block = __adfs_block_map(sb, indaddr, i);
+		if (!block) {
+			adfs_error(sb, "dir %06x has a hole at offset %u",
+				   indaddr, i);
+			goto error;
+		}
+
+		dir->bhs[i] = sb_bread(sb, block);
+		if (!dir->bhs[i]) {
+			adfs_error(sb,
+				   "dir %06x failed read at offset %u, mapped block 0x%08x",
+				   indaddr, i, block);
+			goto error;
+		}
+
+		dir->nr_buffers++;
+	}
+	return 0;
+
+error:
+	adfs_dir_relse(dir);
+
+	return -EIO;
+}
+
 static int adfs_dir_read(struct super_block *sb, u32 indaddr,
 			 unsigned int size, struct adfs_dir *dir)
 {
diff --git a/fs/adfs/dir_f.c b/fs/adfs/dir_f.c
index 3c3b423577d2..027ee714f42b 100644
--- a/fs/adfs/dir_f.c
+++ b/fs/adfs/dir_f.c
@@ -126,7 +126,7 @@ static int adfs_dir_read(struct super_block *sb, u32 indaddr,
 			 unsigned int size, struct adfs_dir *dir)
 {
 	const unsigned int blocksize_bits = sb->s_blocksize_bits;
-	int blk;
+	int ret;
 
 	/*
 	 * Directories which are not a multiple of 2048 bytes
@@ -135,24 +135,9 @@ static int adfs_dir_read(struct super_block *sb, u32 indaddr,
 	if (size & 2047)
 		goto bad_dir;
 
-	size >>= blocksize_bits;
-
-	for (blk = 0; blk < size; blk++) {
-		int phys;
-
-		phys = __adfs_block_map(sb, indaddr, blk);
-		if (!phys) {
-			adfs_error(sb, "dir %06x has a hole at offset %d",
-				   indaddr, blk);
-			goto release_buffers;
-		}
-
-		dir->bh[blk] = sb_bread(sb, phys);
-		if (!dir->bh[blk])
-			goto release_buffers;
-
-		dir->nr_buffers += 1;
-	}
+	ret = adfs_dir_read_buffers(sb, indaddr, size, dir);
+	if (ret)
+		return ret;
 
 	memcpy(&dir->dirhead, bufoff(dir->bh, 0), sizeof(dir->dirhead));
 	memcpy(&dir->dirtail, bufoff(dir->bh, 2007), sizeof(dir->dirtail));
@@ -172,7 +157,6 @@ static int adfs_dir_read(struct super_block *sb, u32 indaddr,
 
 bad_dir:
 	adfs_error(sb, "dir %06x is corrupted", indaddr);
-release_buffers:
 	adfs_dir_relse(dir);
 
 	return -EIO;
diff --git a/fs/adfs/dir_fplus.c b/fs/adfs/dir_fplus.c
index 6a07c0dfcc93..ae11236515d0 100644
--- a/fs/adfs/dir_fplus.c
+++ b/fs/adfs/dir_fplus.c
@@ -4,87 +4,49 @@
  *
  *  Copyright (C) 1997-1999 Russell King
  */
-#include <linux/slab.h>
 #include "adfs.h"
 #include "dir_fplus.h"
 
-static int
-adfs_fplus_read(struct super_block *sb, unsigned int id, unsigned int sz, struct adfs_dir *dir)
+static int adfs_fplus_read(struct super_block *sb, u32 indaddr,
+			   unsigned int size, struct adfs_dir *dir)
 {
 	struct adfs_bigdirheader *h;
 	struct adfs_bigdirtail *t;
-	unsigned long block;
-	unsigned int blk, size;
-	int ret = -EIO;
-
-	block = __adfs_block_map(sb, id, 0);
-	if (!block) {
-		adfs_error(sb, "dir object %X has a hole at offset 0", id);
-		goto out;
-	}
+	unsigned int dirsize;
+	int ret;
 
-	dir->bhs[0] = sb_bread(sb, block);
-	if (!dir->bhs[0])
-		goto out;
-	dir->nr_buffers += 1;
+	/* Read first buffer */
+	ret = adfs_dir_read_buffers(sb, indaddr, sb->s_blocksize, dir);
+	if (ret)
+		return ret;
 
 	h = (struct adfs_bigdirheader *)dir->bhs[0]->b_data;
-	size = le32_to_cpu(h->bigdirsize);
-	if (size != sz) {
+	dirsize = le32_to_cpu(h->bigdirsize);
+	if (dirsize != size) {
 		adfs_msg(sb, KERN_WARNING,
-			 "directory header size %X does not match directory size %X",
-			 size, sz);
+			 "dir %06x header size %X does not match directory size %X",
+			 indaddr, dirsize, size);
 	}
 
 	if (h->bigdirversion[0] != 0 || h->bigdirversion[1] != 0 ||
 	    h->bigdirversion[2] != 0 || size & 2047 ||
 	    h->bigdirstartname != cpu_to_le32(BIGDIRSTARTNAME)) {
-		adfs_error(sb, "dir %06x has malformed header", id);
+		adfs_error(sb, "dir %06x has malformed header", indaddr);
 		goto out;
 	}
 
-	size >>= sb->s_blocksize_bits;
-	if (size > ARRAY_SIZE(dir->bh)) {
-		/* this directory is too big for fixed bh set, must allocate */
-		struct buffer_head **bhs =
-			kcalloc(size, sizeof(struct buffer_head *),
-				GFP_KERNEL);
-		if (!bhs) {
-			adfs_msg(sb, KERN_ERR,
-				 "not enough memory for dir object %X (%d blocks)",
-				 id, size);
-			ret = -ENOMEM;
-			goto out;
-		}
-		dir->bhs = bhs;
-		/* copy over the pointer to the block that we've already read */
-		dir->bhs[0] = dir->bh[0];
-	}
-
-	for (blk = 1; blk < size; blk++) {
-		block = __adfs_block_map(sb, id, blk);
-		if (!block) {
-			adfs_error(sb, "dir object %X has a hole at offset %d", id, blk);
-			goto out;
-		}
-
-		dir->bhs[blk] = sb_bread(sb, block);
-		if (!dir->bhs[blk]) {
-			adfs_error(sb,	"dir object %x failed read for offset %d, mapped block %lX",
-				   id, blk, block);
-			goto out;
-		}
-
-		dir->nr_buffers += 1;
-	}
+	/* Read remaining buffers */
+	ret = adfs_dir_read_buffers(sb, indaddr, dirsize, dir);
+	if (ret)
+		return ret;
 
 	t = (struct adfs_bigdirtail *)
-		(dir->bhs[size - 1]->b_data + (sb->s_blocksize - 8));
+		(dir->bhs[dir->nr_buffers - 1]->b_data + (sb->s_blocksize - 8));
 
 	if (t->bigdirendname != cpu_to_le32(BIGDIRENDNAME) ||
 	    t->bigdirendmasseq != h->startmasseq ||
 	    t->reserved[0] != 0 || t->reserved[1] != 0) {
-		adfs_error(sb, "dir %06x has malformed tail", id);
+		adfs_error(sb, "dir %06x has malformed tail", indaddr);
 		goto out;
 	}
 
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 17/41] fs/adfs: dir: add helper to read directory using inode
  2019-12-09 11:07 [PATCH 00/41] fs/adfs updates for 5.6 Russell King - ARM Linux admin
                   ` (15 preceding siblings ...)
  2019-12-09 11:09 ` [PATCH 16/41] fs/adfs: dir: add generic directory reading Russell King
@ 2019-12-09 11:09 ` Russell King
  2019-12-09 11:09 ` [PATCH 18/41] fs/adfs: dir: add helper to mark directory buffers dirty Russell King
                   ` (23 subsequent siblings)
  40 siblings, 0 replies; 47+ messages in thread
From: Russell King @ 2019-12-09 11:09 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel

Add a helper to read a directory using the inode, which we do in two
places.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
 fs/adfs/dir.c | 32 ++++++++++++++++++++++----------
 1 file changed, 22 insertions(+), 10 deletions(-)

diff --git a/fs/adfs/dir.c b/fs/adfs/dir.c
index b8e2a909fa3f..882377e86041 100644
--- a/fs/adfs/dir.c
+++ b/fs/adfs/dir.c
@@ -137,6 +137,26 @@ static int adfs_dir_read(struct super_block *sb, u32 indaddr,
 	return ADFS_SB(sb)->s_dir->read(sb, indaddr, size, dir);
 }
 
+static int adfs_dir_read_inode(struct super_block *sb, struct inode *inode,
+			       struct adfs_dir *dir)
+{
+	int ret;
+
+	ret = adfs_dir_read(sb, inode->i_ino, inode->i_size, dir);
+	if (ret)
+		return ret;
+
+	if (ADFS_I(inode)->parent_id != dir->parent_id) {
+		adfs_error(sb,
+			   "parent directory id changed under me! (%06x but got %06x)\n",
+			   ADFS_I(inode)->parent_id, dir->parent_id);
+		adfs_dir_relse(dir);
+		ret = -EIO;
+	}
+
+	return ret;
+}
+
 static int adfs_dir_sync(struct adfs_dir *dir)
 {
 	int err = 0;
@@ -203,7 +223,7 @@ adfs_readdir(struct file *file, struct dir_context *ctx)
 	if (ctx->pos >> 32)
 		return 0;
 
-	ret = adfs_dir_read(sb, inode->i_ino, inode->i_size, &dir);
+	ret = adfs_dir_read_inode(sb, inode, &dir);
 	if (ret)
 		return ret;
 
@@ -304,18 +324,10 @@ static int adfs_dir_lookup_byname(struct inode *inode, const struct qstr *qstr,
 	u32 name_len;
 	int ret;
 
-	ret = adfs_dir_read(sb, inode->i_ino, inode->i_size, &dir);
+	ret = adfs_dir_read_inode(sb, inode, &dir);
 	if (ret)
 		goto out;
 
-	if (ADFS_I(inode)->parent_id != dir.parent_id) {
-		adfs_error(sb,
-			   "parent directory changed under me! (%06x but got %06x)\n",
-			   ADFS_I(inode)->parent_id, dir.parent_id);
-		ret = -EIO;
-		goto free_out;
-	}
-
 	obj->parent_id = inode->i_ino;
 
 	read_lock(&adfs_dir_lock);
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 18/41] fs/adfs: dir: add helper to mark directory buffers dirty
  2019-12-09 11:07 [PATCH 00/41] fs/adfs updates for 5.6 Russell King - ARM Linux admin
                   ` (16 preceding siblings ...)
  2019-12-09 11:09 ` [PATCH 17/41] fs/adfs: dir: add helper to read directory using inode Russell King
@ 2019-12-09 11:09 ` Russell King
  2019-12-09 11:09 ` [PATCH 19/41] fs/adfs: dir: update directory locking Russell King
                   ` (22 subsequent siblings)
  40 siblings, 0 replies; 47+ messages in thread
From: Russell King @ 2019-12-09 11:09 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel

Provide a helper for marking directory buffers dirty so they get
written back to disk.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
 fs/adfs/dir.c   | 12 ++++++++++++
 fs/adfs/dir_f.c |  5 +----
 2 files changed, 13 insertions(+), 4 deletions(-)

diff --git a/fs/adfs/dir.c b/fs/adfs/dir.c
index 882377e86041..e8aafc65d545 100644
--- a/fs/adfs/dir.c
+++ b/fs/adfs/dir.c
@@ -157,6 +157,15 @@ static int adfs_dir_read_inode(struct super_block *sb, struct inode *inode,
 	return ret;
 }
 
+static void adfs_dir_mark_dirty(struct adfs_dir *dir)
+{
+	unsigned int i;
+
+	/* Mark the buffers dirty */
+	for (i = 0; i < dir->nr_buffers; i++)
+		mark_buffer_dirty(dir->bhs[i]);
+}
+
 static int adfs_dir_sync(struct adfs_dir *dir)
 {
 	int err = 0;
@@ -280,6 +289,9 @@ adfs_dir_update(struct super_block *sb, struct object_info *obj, int wait)
 	ret = ops->update(&dir, obj);
 	write_unlock(&adfs_dir_lock);
 
+	if (ret == 0)
+		adfs_dir_mark_dirty(&dir);
+
 	if (wait) {
 		int err = adfs_dir_sync(&dir);
 		if (!ret)
diff --git a/fs/adfs/dir_f.c b/fs/adfs/dir_f.c
index 027ee714f42b..682df46d8d33 100644
--- a/fs/adfs/dir_f.c
+++ b/fs/adfs/dir_f.c
@@ -306,7 +306,7 @@ static int
 adfs_f_update(struct adfs_dir *dir, struct object_info *obj)
 {
 	struct super_block *sb = dir->sb;
-	int ret, i;
+	int ret;
 
 	ret = adfs_dir_find_entry(dir, obj->indaddr);
 	if (ret < 0) {
@@ -347,9 +347,6 @@ adfs_f_update(struct adfs_dir *dir, struct object_info *obj)
 		goto bad_dir;
 	}
 #endif
-	for (i = dir->nr_buffers - 1; i >= 0; i--)
-		mark_buffer_dirty(dir->bh[i]);
-
 	ret = 0;
 out:
 	return ret;
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 19/41] fs/adfs: dir: update directory locking
  2019-12-09 11:07 [PATCH 00/41] fs/adfs updates for 5.6 Russell King - ARM Linux admin
                   ` (17 preceding siblings ...)
  2019-12-09 11:09 ` [PATCH 18/41] fs/adfs: dir: add helper to mark directory buffers dirty Russell King
@ 2019-12-09 11:09 ` Russell King
  2019-12-09 11:09 ` [PATCH 20/41] fs/adfs: dir: modernise on-disk directory structures Russell King
                   ` (21 subsequent siblings)
  40 siblings, 0 replies; 47+ messages in thread
From: Russell King @ 2019-12-09 11:09 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel

Update directory locking such that it covers the validation of the
directory, which could fail if another thread is concurrently writing
to the same directory.  Since we may sleep, we need to use a rwsem
rather than a rw spinlock.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
 fs/adfs/dir.c | 55 +++++++++++++++++++++++++++------------------------
 1 file changed, 29 insertions(+), 26 deletions(-)

diff --git a/fs/adfs/dir.c b/fs/adfs/dir.c
index e8aafc65d545..ff9c921be31c 100644
--- a/fs/adfs/dir.c
+++ b/fs/adfs/dir.c
@@ -12,7 +12,7 @@
 /*
  * For future.  This should probably be per-directory.
  */
-static DEFINE_RWLOCK(adfs_dir_lock);
+static DECLARE_RWSEM(adfs_dir_rwsem);
 
 int adfs_dir_copyfrom(void *dst, struct adfs_dir *dir, unsigned int offset,
 		      size_t len)
@@ -232,26 +232,25 @@ adfs_readdir(struct file *file, struct dir_context *ctx)
 	if (ctx->pos >> 32)
 		return 0;
 
+	down_read(&adfs_dir_rwsem);
 	ret = adfs_dir_read_inode(sb, inode, &dir);
 	if (ret)
-		return ret;
+		goto unlock;
 
 	if (ctx->pos == 0) {
 		if (!dir_emit_dot(file, ctx))
-			goto free_out;
+			goto unlock_relse;
 		ctx->pos = 1;
 	}
 	if (ctx->pos == 1) {
 		if (!dir_emit(ctx, "..", 2, dir.parent_id, DT_DIR))
-			goto free_out;
+			goto unlock_relse;
 		ctx->pos = 2;
 	}
 
-	read_lock(&adfs_dir_lock);
-
 	ret = ops->setpos(&dir, ctx->pos - 2);
 	if (ret)
-		goto unlock_out;
+		goto unlock_relse;
 	while (ops->getnext(&dir, &obj) == 0) {
 		if (!dir_emit(ctx, obj.name, obj.name_len,
 			      obj.indaddr, DT_UNKNOWN))
@@ -259,12 +258,14 @@ adfs_readdir(struct file *file, struct dir_context *ctx)
 		ctx->pos++;
 	}
 
-unlock_out:
-	read_unlock(&adfs_dir_lock);
-
-free_out:
+unlock_relse:
+	up_read(&adfs_dir_rwsem);
 	adfs_dir_relse(&dir);
 	return ret;
+
+unlock:
+	up_read(&adfs_dir_rwsem);
+	return ret;
 }
 
 int
@@ -281,13 +282,13 @@ adfs_dir_update(struct super_block *sb, struct object_info *obj, int wait)
 	if (!ops->update)
 		return -EINVAL;
 
+	down_write(&adfs_dir_rwsem);
 	ret = adfs_dir_read(sb, obj->parent_id, 0, &dir);
 	if (ret)
-		goto out;
+		goto unlock;
 
-	write_lock(&adfs_dir_lock);
 	ret = ops->update(&dir, obj);
-	write_unlock(&adfs_dir_lock);
+	up_write(&adfs_dir_rwsem);
 
 	if (ret == 0)
 		adfs_dir_mark_dirty(&dir);
@@ -299,7 +300,10 @@ adfs_dir_update(struct super_block *sb, struct object_info *obj, int wait)
 	}
 
 	adfs_dir_relse(&dir);
-out:
+	return ret;
+
+unlock:
+	up_write(&adfs_dir_rwsem);
 #endif
 	return ret;
 }
@@ -336,17 +340,14 @@ static int adfs_dir_lookup_byname(struct inode *inode, const struct qstr *qstr,
 	u32 name_len;
 	int ret;
 
+	down_read(&adfs_dir_rwsem);
 	ret = adfs_dir_read_inode(sb, inode, &dir);
 	if (ret)
-		goto out;
-
-	obj->parent_id = inode->i_ino;
-
-	read_lock(&adfs_dir_lock);
+		goto unlock;
 
 	ret = ops->setpos(&dir, 0);
 	if (ret)
-		goto unlock_out;
+		goto unlock_relse;
 
 	ret = -ENOENT;
 	name = qstr->name;
@@ -357,13 +358,15 @@ static int adfs_dir_lookup_byname(struct inode *inode, const struct qstr *qstr,
 			break;
 		}
 	}
+	obj->parent_id = inode->i_ino;
 
-unlock_out:
-	read_unlock(&adfs_dir_lock);
-
-free_out:
+unlock_relse:
+	up_read(&adfs_dir_rwsem);
 	adfs_dir_relse(&dir);
-out:
+	return ret;
+
+unlock:
+	up_read(&adfs_dir_rwsem);
 	return ret;
 }
 
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 20/41] fs/adfs: dir: modernise on-disk directory structures
  2019-12-09 11:07 [PATCH 00/41] fs/adfs updates for 5.6 Russell King - ARM Linux admin
                   ` (18 preceding siblings ...)
  2019-12-09 11:09 ` [PATCH 19/41] fs/adfs: dir: update directory locking Russell King
@ 2019-12-09 11:09 ` Russell King
  2019-12-09 11:10 ` [PATCH 21/41] fs/adfs: dir: improve update failure handling Russell King
                   ` (20 subsequent siblings)
  40 siblings, 0 replies; 47+ messages in thread
From: Russell King @ 2019-12-09 11:09 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel

Use __u8 and pack the structures for on-disk directories.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
 fs/adfs/dir_f.h     | 52 ++++++++++++++++++++++++---------------------
 fs/adfs/dir_fplus.h |  6 +++---
 2 files changed, 31 insertions(+), 27 deletions(-)

diff --git a/fs/adfs/dir_f.h b/fs/adfs/dir_f.h
index 5aec332b90f5..a5393e6cf9f4 100644
--- a/fs/adfs/dir_f.h
+++ b/fs/adfs/dir_f.h
@@ -13,9 +13,9 @@
  * Directory header
  */
 struct adfs_dirheader {
-	unsigned char startmasseq;
-	unsigned char startname[4];
-};
+	__u8 startmasseq;
+	__u8 startname[4];
+} __attribute__((packed));
 
 #define ADFS_NEWDIR_SIZE	2048
 #define ADFS_NUM_DIR_ENTRIES	77
@@ -31,32 +31,36 @@ struct adfs_direntry {
 	__u8 dirlen[4];
 	__u8 dirinddiscadd[3];
 	__u8 newdiratts;
-};
+} __attribute__((packed));
 
 /*
  * Directory tail
  */
+struct adfs_olddirtail {
+	__u8 dirlastmask;
+	char dirname[10];
+	__u8 dirparent[3];
+	char dirtitle[19];
+	__u8 reserved[14];
+	__u8 endmasseq;
+	__u8 endname[4];
+	__u8 dircheckbyte;
+} __attribute__((packed));
+
+struct adfs_newdirtail {
+	__u8 dirlastmask;
+	__u8 reserved[2];
+	__u8 dirparent[3];
+	char dirtitle[19];
+	char dirname[10];
+	__u8 endmasseq;
+	__u8 endname[4];
+	__u8 dircheckbyte;
+} __attribute__((packed));
+
 union adfs_dirtail {
-	struct {
-		unsigned char dirlastmask;
-		char dirname[10];
-		unsigned char dirparent[3];
-		char dirtitle[19];
-		unsigned char reserved[14];
-		unsigned char endmasseq;
-		unsigned char endname[4];
-		unsigned char dircheckbyte;
-	} old;
-	struct {
-		unsigned char dirlastmask;
-		unsigned char reserved[2];
-		unsigned char dirparent[3];
-		char dirtitle[19];
-		char dirname[10];
-		unsigned char endmasseq;
-		unsigned char endname[4];
-		unsigned char dircheckbyte;
-	} new;
+	struct adfs_olddirtail old;
+	struct adfs_newdirtail new;
 };
 
 #endif
diff --git a/fs/adfs/dir_fplus.h b/fs/adfs/dir_fplus.h
index 4ec0931e36ad..d729b1591e5e 100644
--- a/fs/adfs/dir_fplus.h
+++ b/fs/adfs/dir_fplus.h
@@ -22,7 +22,7 @@ struct adfs_bigdirheader {
 	__le32	bigdirnamesize;
 	__le32	bigdirparent;
 	char	bigdirname[1];
-};
+} __attribute__((packed, aligned(4)));
 
 struct adfs_bigdirentry {
 	__le32	bigdirload;
@@ -32,11 +32,11 @@ struct adfs_bigdirentry {
 	__le32	bigdirattr;
 	__le32	bigdirobnamelen;
 	__le32	bigdirobnameptr;
-};
+} __attribute__((packed, aligned(4)));
 
 struct adfs_bigdirtail {
 	__le32	bigdirendname;
 	__u8	bigdirendmasseq;
 	__u8	reserved[2];
 	__u8	bigdircheckbyte;
-};
+} __attribute__((packed, aligned(4)));
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 21/41] fs/adfs: dir: improve update failure handling
  2019-12-09 11:07 [PATCH 00/41] fs/adfs updates for 5.6 Russell King - ARM Linux admin
                   ` (19 preceding siblings ...)
  2019-12-09 11:09 ` [PATCH 20/41] fs/adfs: dir: modernise on-disk directory structures Russell King
@ 2019-12-09 11:10 ` Russell King
  2019-12-09 11:10 ` [PATCH 22/41] fs/adfs: dir: improve compiler coverage in adfs_dir_update Russell King
                   ` (19 subsequent siblings)
  40 siblings, 0 replies; 47+ messages in thread
From: Russell King @ 2019-12-09 11:10 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel

When we update a directory, a number of errors may happen. If we failed
to find the entry to update, we can just release the directory buffers
as normal.

However, if we have some other error, we may have partially updated the
buffers, resulting in an invalid directory. In this case, we need to
discard the buffers to avoid writing the contents back to the media, and
later re-read the directory from the media.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
 fs/adfs/dir.c | 48 ++++++++++++++++++++++++++++++++++++------------
 1 file changed, 36 insertions(+), 12 deletions(-)

diff --git a/fs/adfs/dir.c b/fs/adfs/dir.c
index ff9c921be31c..5e5d344bae7c 100644
--- a/fs/adfs/dir.c
+++ b/fs/adfs/dir.c
@@ -64,12 +64,8 @@ int adfs_dir_copyto(struct adfs_dir *dir, unsigned int offset, const void *src,
 	return 0;
 }
 
-void adfs_dir_relse(struct adfs_dir *dir)
+static void __adfs_dir_cleanup(struct adfs_dir *dir)
 {
-	unsigned int i;
-
-	for (i = 0; i < dir->nr_buffers; i++)
-		brelse(dir->bhs[i]);
 	dir->nr_buffers = 0;
 
 	if (dir->bhs != dir->bh)
@@ -78,6 +74,26 @@ void adfs_dir_relse(struct adfs_dir *dir)
 	dir->sb = NULL;
 }
 
+void adfs_dir_relse(struct adfs_dir *dir)
+{
+	unsigned int i;
+
+	for (i = 0; i < dir->nr_buffers; i++)
+		brelse(dir->bhs[i]);
+
+	__adfs_dir_cleanup(dir);
+}
+
+static void adfs_dir_forget(struct adfs_dir *dir)
+{
+	unsigned int i;
+
+	for (i = 0; i < dir->nr_buffers; i++)
+		bforget(dir->bhs[i]);
+
+	__adfs_dir_cleanup(dir);
+}
+
 int adfs_dir_read_buffers(struct super_block *sb, u32 indaddr,
 			  unsigned int size, struct adfs_dir *dir)
 {
@@ -288,20 +304,28 @@ adfs_dir_update(struct super_block *sb, struct object_info *obj, int wait)
 		goto unlock;
 
 	ret = ops->update(&dir, obj);
+	if (ret)
+		goto forget;
 	up_write(&adfs_dir_rwsem);
 
-	if (ret == 0)
-		adfs_dir_mark_dirty(&dir);
+	adfs_dir_mark_dirty(&dir);
 
-	if (wait) {
-		int err = adfs_dir_sync(&dir);
-		if (!ret)
-			ret = err;
-	}
+	if (wait)
+		ret = adfs_dir_sync(&dir);
 
 	adfs_dir_relse(&dir);
 	return ret;
 
+	/*
+	 * If the updated failed because the entry wasn't found, we can
+	 * just release the buffers. If it was any other error, forget
+	 * the dirtied buffers so they aren't written back to the media.
+	 */
+forget:
+	if (ret == -ENOENT)
+		adfs_dir_relse(&dir);
+	else
+		adfs_dir_forget(&dir);
 unlock:
 	up_write(&adfs_dir_rwsem);
 #endif
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 22/41] fs/adfs: dir: improve compiler coverage in adfs_dir_update
  2019-12-09 11:07 [PATCH 00/41] fs/adfs updates for 5.6 Russell King - ARM Linux admin
                   ` (20 preceding siblings ...)
  2019-12-09 11:10 ` [PATCH 21/41] fs/adfs: dir: improve update failure handling Russell King
@ 2019-12-09 11:10 ` Russell King
  2019-12-09 11:10 ` [PATCH 23/41] fs/adfs: dir: switch to iterate_shared method Russell King
                   ` (18 subsequent siblings)
  40 siblings, 0 replies; 47+ messages in thread
From: Russell King @ 2019-12-09 11:10 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel

Get rid of the ifdef, using IS_ENABLED() instead to detect whether the
code should be callable.  This allows the compiler to always parse the
following code, reducing the chances of errors being missed.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
 fs/adfs/dir.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/fs/adfs/dir.c b/fs/adfs/dir.c
index 5e5d344bae7c..931eefb2375b 100644
--- a/fs/adfs/dir.c
+++ b/fs/adfs/dir.c
@@ -287,14 +287,16 @@ adfs_readdir(struct file *file, struct dir_context *ctx)
 int
 adfs_dir_update(struct super_block *sb, struct object_info *obj, int wait)
 {
-	int ret = -EINVAL;
-#ifdef CONFIG_ADFS_FS_RW
 	const struct adfs_dir_ops *ops = ADFS_SB(sb)->s_dir;
 	struct adfs_dir dir;
+	int ret;
 
 	printk(KERN_INFO "adfs_dir_update: object %06x in dir %06x\n",
 		 obj->indaddr, obj->parent_id);
 
+	if (!IS_ENABLED(CONFIG_ADFS_FS_RW))
+		return -EINVAL;
+
 	if (!ops->update)
 		return -EINVAL;
 
@@ -328,7 +330,7 @@ adfs_dir_update(struct super_block *sb, struct object_info *obj, int wait)
 		adfs_dir_forget(&dir);
 unlock:
 	up_write(&adfs_dir_rwsem);
-#endif
+
 	return ret;
 }
 
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 23/41] fs/adfs: dir: switch to iterate_shared method
  2019-12-09 11:07 [PATCH 00/41] fs/adfs updates for 5.6 Russell King - ARM Linux admin
                   ` (21 preceding siblings ...)
  2019-12-09 11:10 ` [PATCH 22/41] fs/adfs: dir: improve compiler coverage in adfs_dir_update Russell King
@ 2019-12-09 11:10 ` Russell King
  2019-12-09 11:10 ` [PATCH 24/41] fs/adfs: dir: add more efficient iterate() per-format method Russell King
                   ` (17 subsequent siblings)
  40 siblings, 0 replies; 47+ messages in thread
From: Russell King @ 2019-12-09 11:10 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel

There is nothing in our readdir (aka iterate) method that relies on
the directory inode being exclusively locked, so switch to using the
iterate_shared() hook rather than iterate().

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
 fs/adfs/dir.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/fs/adfs/dir.c b/fs/adfs/dir.c
index 931eefb2375b..2a8f5f1fd3d0 100644
--- a/fs/adfs/dir.c
+++ b/fs/adfs/dir.c
@@ -235,8 +235,7 @@ void adfs_object_fixup(struct adfs_dir *dir, struct object_info *obj)
 	}
 }
 
-static int
-adfs_readdir(struct file *file, struct dir_context *ctx)
+static int adfs_iterate(struct file *file, struct dir_context *ctx)
 {
 	struct inode *inode = file_inode(file);
 	struct super_block *sb = inode->i_sb;
@@ -399,7 +398,7 @@ static int adfs_dir_lookup_byname(struct inode *inode, const struct qstr *qstr,
 const struct file_operations adfs_dir_operations = {
 	.read		= generic_read_dir,
 	.llseek		= generic_file_llseek,
-	.iterate	= adfs_readdir,
+	.iterate_shared	= adfs_iterate,
 	.fsync		= generic_file_fsync,
 };
 
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 24/41] fs/adfs: dir: add more efficient iterate() per-format method
  2019-12-09 11:07 [PATCH 00/41] fs/adfs updates for 5.6 Russell King - ARM Linux admin
                   ` (22 preceding siblings ...)
  2019-12-09 11:10 ` [PATCH 23/41] fs/adfs: dir: switch to iterate_shared method Russell King
@ 2019-12-09 11:10 ` Russell King
  2019-12-09 11:10 ` [PATCH 25/41] fs/adfs: dir: use pointers to access directory head/tails Russell King
                   ` (16 subsequent siblings)
  40 siblings, 0 replies; 47+ messages in thread
From: Russell King @ 2019-12-09 11:10 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel

Rather than using setpos + getnext to iterate through the directory
entries, pass iterate() down to the dir format code to populate the
dirents.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
 fs/adfs/adfs.h      |  1 +
 fs/adfs/dir.c       | 16 ++--------------
 fs/adfs/dir_f.c     | 18 ++++++++++++++++++
 fs/adfs/dir_fplus.c | 21 +++++++++++++++++++++
 4 files changed, 42 insertions(+), 14 deletions(-)

diff --git a/fs/adfs/adfs.h b/fs/adfs/adfs.h
index 01d065937c01..cbf33f375e0b 100644
--- a/fs/adfs/adfs.h
+++ b/fs/adfs/adfs.h
@@ -120,6 +120,7 @@ struct object_info {
 struct adfs_dir_ops {
 	int	(*read)(struct super_block *sb, unsigned int indaddr,
 			unsigned int size, struct adfs_dir *dir);
+	int	(*iterate)(struct adfs_dir *dir, struct dir_context *ctx);
 	int	(*setpos)(struct adfs_dir *dir, unsigned int fpos);
 	int	(*getnext)(struct adfs_dir *dir, struct object_info *obj);
 	int	(*update)(struct adfs_dir *dir, struct object_info *obj);
diff --git a/fs/adfs/dir.c b/fs/adfs/dir.c
index 2a8f5f1fd3d0..7fda44464121 100644
--- a/fs/adfs/dir.c
+++ b/fs/adfs/dir.c
@@ -240,12 +240,8 @@ static int adfs_iterate(struct file *file, struct dir_context *ctx)
 	struct inode *inode = file_inode(file);
 	struct super_block *sb = inode->i_sb;
 	const struct adfs_dir_ops *ops = ADFS_SB(sb)->s_dir;
-	struct object_info obj;
 	struct adfs_dir dir;
-	int ret = 0;
-
-	if (ctx->pos >> 32)
-		return 0;
+	int ret;
 
 	down_read(&adfs_dir_rwsem);
 	ret = adfs_dir_read_inode(sb, inode, &dir);
@@ -263,15 +259,7 @@ static int adfs_iterate(struct file *file, struct dir_context *ctx)
 		ctx->pos = 2;
 	}
 
-	ret = ops->setpos(&dir, ctx->pos - 2);
-	if (ret)
-		goto unlock_relse;
-	while (ops->getnext(&dir, &obj) == 0) {
-		if (!dir_emit(ctx, obj.name, obj.name_len,
-			      obj.indaddr, DT_UNKNOWN))
-			break;
-		ctx->pos++;
-	}
+	ret = ops->iterate(&dir, ctx);
 
 unlock_relse:
 	up_read(&adfs_dir_rwsem);
diff --git a/fs/adfs/dir_f.c b/fs/adfs/dir_f.c
index 682df46d8d33..2e342871d6df 100644
--- a/fs/adfs/dir_f.c
+++ b/fs/adfs/dir_f.c
@@ -302,6 +302,23 @@ adfs_f_getnext(struct adfs_dir *dir, struct object_info *obj)
 	return ret;
 }
 
+static int adfs_f_iterate(struct adfs_dir *dir, struct dir_context *ctx)
+{
+	struct object_info obj;
+	int pos = 5 + (ctx->pos - 2) * 26;
+
+	while (ctx->pos < 2 + ADFS_NUM_DIR_ENTRIES) {
+		if (__adfs_dir_get(dir, pos, &obj))
+			break;
+		if (!dir_emit(ctx, obj.name, obj.name_len,
+			      obj.indaddr, DT_UNKNOWN))
+			break;
+		pos += 26;
+		ctx->pos++;
+	}
+	return 0;
+}
+
 static int
 adfs_f_update(struct adfs_dir *dir, struct object_info *obj)
 {
@@ -359,6 +376,7 @@ adfs_f_update(struct adfs_dir *dir, struct object_info *obj)
 
 const struct adfs_dir_ops adfs_f_dir_ops = {
 	.read		= adfs_f_read,
+	.iterate	= adfs_f_iterate,
 	.setpos		= adfs_f_setpos,
 	.getnext	= adfs_f_getnext,
 	.update		= adfs_f_update,
diff --git a/fs/adfs/dir_fplus.c b/fs/adfs/dir_fplus.c
index ae11236515d0..edcbaa94ecb9 100644
--- a/fs/adfs/dir_fplus.c
+++ b/fs/adfs/dir_fplus.c
@@ -118,8 +118,29 @@ adfs_fplus_getnext(struct adfs_dir *dir, struct object_info *obj)
 	return 0;
 }
 
+static int adfs_fplus_iterate(struct adfs_dir *dir, struct dir_context *ctx)
+{
+	struct object_info obj;
+
+	if ((ctx->pos - 2) >> 32)
+		return 0;
+
+	if (adfs_fplus_setpos(dir, ctx->pos - 2))
+		return 0;
+
+	while (!adfs_fplus_getnext(dir, &obj)) {
+		if (!dir_emit(ctx, obj.name, obj.name_len,
+			      obj.indaddr, DT_UNKNOWN))
+			break;
+		ctx->pos++;
+	}
+
+	return 0;
+}
+
 const struct adfs_dir_ops adfs_fplus_dir_ops = {
 	.read		= adfs_fplus_read,
+	.iterate	= adfs_fplus_iterate,
 	.setpos		= adfs_fplus_setpos,
 	.getnext	= adfs_fplus_getnext,
 };
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 25/41] fs/adfs: dir: use pointers to access directory head/tails
  2019-12-09 11:07 [PATCH 00/41] fs/adfs updates for 5.6 Russell King - ARM Linux admin
                   ` (23 preceding siblings ...)
  2019-12-09 11:10 ` [PATCH 24/41] fs/adfs: dir: add more efficient iterate() per-format method Russell King
@ 2019-12-09 11:10 ` Russell King
  2019-12-09 11:10 ` [PATCH 26/41] fs/adfs: newdir: factor out directory format validation Russell King
                   ` (15 subsequent siblings)
  40 siblings, 0 replies; 47+ messages in thread
From: Russell King @ 2019-12-09 11:10 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel

Add and use pointers in the adfs_dir structure to access the directory
head and tail structures, which will always be contiguous in a buffer.
This allows us to avoid memcpy()ing the data in the new directory code,
making it slightly more efficient.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
 fs/adfs/adfs.h      | 12 ++++++++----
 fs/adfs/dir_f.c     | 42 +++++++++++++++++-------------------------
 fs/adfs/dir_fplus.c | 11 ++++-------
 3 files changed, 29 insertions(+), 36 deletions(-)

diff --git a/fs/adfs/adfs.h b/fs/adfs/adfs.h
index cbf33f375e0b..1f431a42e14c 100644
--- a/fs/adfs/adfs.h
+++ b/fs/adfs/adfs.h
@@ -26,8 +26,6 @@ static inline u16 adfs_filetype(u32 loadaddr)
 #define ADFS_NDA_PUBLIC_READ	(1 << 5)
 #define ADFS_NDA_PUBLIC_WRITE	(1 << 6)
 
-#include "dir_f.h"
-
 /*
  * adfs file system inode data in memory
  */
@@ -98,8 +96,14 @@ struct adfs_dir {
 	unsigned int		pos;
 	__u32			parent_id;
 
-	struct adfs_dirheader	dirhead;
-	union  adfs_dirtail	dirtail;
+	union {
+		struct adfs_dirheader	*dirhead;
+		struct adfs_bigdirheader *bighead;
+	};
+	union {
+		struct adfs_newdirtail	*newtail;
+		struct adfs_bigdirtail	*bigtail;
+	};
 };
 
 /*
diff --git a/fs/adfs/dir_f.c b/fs/adfs/dir_f.c
index 2e342871d6df..7e56fcc21303 100644
--- a/fs/adfs/dir_f.c
+++ b/fs/adfs/dir_f.c
@@ -58,7 +58,7 @@ static inline void adfs_writeval(unsigned char *p, int len, unsigned int val)
 #define bufoff(_bh,_idx)			\
 	({ int _buf = _idx >> blocksize_bits;	\
 	   int _off = _idx - (_buf << blocksize_bits);\
-	  (u8 *)(_bh[_buf]->b_data + _off);	\
+	  (void *)(_bh[_buf]->b_data + _off);	\
 	})
 
 /*
@@ -139,18 +139,18 @@ static int adfs_dir_read(struct super_block *sb, u32 indaddr,
 	if (ret)
 		return ret;
 
-	memcpy(&dir->dirhead, bufoff(dir->bh, 0), sizeof(dir->dirhead));
-	memcpy(&dir->dirtail, bufoff(dir->bh, 2007), sizeof(dir->dirtail));
+	dir->dirhead = bufoff(dir->bh, 0);
+	dir->newtail = bufoff(dir->bh, 2007);
 
-	if (dir->dirhead.startmasseq != dir->dirtail.new.endmasseq ||
-	    memcmp(&dir->dirhead.startname, &dir->dirtail.new.endname, 4))
+	if (dir->dirhead->startmasseq != dir->newtail->endmasseq ||
+	    memcmp(&dir->dirhead->startname, &dir->newtail->endname, 4))
 		goto bad_dir;
 
-	if (memcmp(&dir->dirhead.startname, "Nick", 4) &&
-	    memcmp(&dir->dirhead.startname, "Hugo", 4))
+	if (memcmp(&dir->dirhead->startname, "Nick", 4) &&
+	    memcmp(&dir->dirhead->startname, "Hugo", 4))
 		goto bad_dir;
 
-	if (adfs_dir_checkbyte(dir) != dir->dirtail.new.dircheckbyte)
+	if (adfs_dir_checkbyte(dir) != dir->newtail->dircheckbyte)
 		goto bad_dir;
 
 	return 0;
@@ -275,7 +275,7 @@ static int adfs_f_read(struct super_block *sb, u32 indaddr, unsigned int size,
 	if (ret)
 		adfs_error(sb, "unable to read directory");
 	else
-		dir->parent_id = adfs_readval(dir->dirtail.new.dirparent, 3);
+		dir->parent_id = adfs_readval(dir->newtail->dirparent, 3);
 
 	return ret;
 }
@@ -322,7 +322,6 @@ static int adfs_f_iterate(struct adfs_dir *dir, struct dir_context *ctx)
 static int
 adfs_f_update(struct adfs_dir *dir, struct object_info *obj)
 {
-	struct super_block *sb = dir->sb;
 	int ret;
 
 	ret = adfs_dir_find_entry(dir, obj->indaddr);
@@ -336,33 +335,26 @@ adfs_f_update(struct adfs_dir *dir, struct object_info *obj)
 	/*
 	 * Increment directory sequence number
 	 */
-	dir->bh[0]->b_data[0] += 1;
-	dir->bh[dir->nr_buffers - 1]->b_data[sb->s_blocksize - 6] += 1;
+	dir->dirhead->startmasseq += 1;
+	dir->newtail->endmasseq += 1;
 
 	ret = adfs_dir_checkbyte(dir);
 	/*
 	 * Update directory check byte
 	 */
-	dir->bh[dir->nr_buffers - 1]->b_data[sb->s_blocksize - 1] = ret;
+	dir->newtail->dircheckbyte = ret;
 
 #if 1
-	{
-	const unsigned int blocksize_bits = sb->s_blocksize_bits;
-
-	memcpy(&dir->dirhead, bufoff(dir->bh, 0), sizeof(dir->dirhead));
-	memcpy(&dir->dirtail, bufoff(dir->bh, 2007), sizeof(dir->dirtail));
-
-	if (dir->dirhead.startmasseq != dir->dirtail.new.endmasseq ||
-	    memcmp(&dir->dirhead.startname, &dir->dirtail.new.endname, 4))
+	if (dir->dirhead->startmasseq != dir->newtail->endmasseq ||
+	    memcmp(&dir->dirhead->startname, &dir->newtail->endname, 4))
 		goto bad_dir;
 
-	if (memcmp(&dir->dirhead.startname, "Nick", 4) &&
-	    memcmp(&dir->dirhead.startname, "Hugo", 4))
+	if (memcmp(&dir->dirhead->startname, "Nick", 4) &&
+	    memcmp(&dir->dirhead->startname, "Hugo", 4))
 		goto bad_dir;
 
-	if (adfs_dir_checkbyte(dir) != dir->dirtail.new.dircheckbyte)
+	if (adfs_dir_checkbyte(dir) != dir->newtail->dircheckbyte)
 		goto bad_dir;
-	}
 #endif
 	ret = 0;
 out:
diff --git a/fs/adfs/dir_fplus.c b/fs/adfs/dir_fplus.c
index edcbaa94ecb9..6f2dbcf6819b 100644
--- a/fs/adfs/dir_fplus.c
+++ b/fs/adfs/dir_fplus.c
@@ -20,7 +20,7 @@ static int adfs_fplus_read(struct super_block *sb, u32 indaddr,
 	if (ret)
 		return ret;
 
-	h = (struct adfs_bigdirheader *)dir->bhs[0]->b_data;
+	dir->bighead = h = (void *)dir->bhs[0]->b_data;
 	dirsize = le32_to_cpu(h->bigdirsize);
 	if (dirsize != size) {
 		adfs_msg(sb, KERN_WARNING,
@@ -40,7 +40,7 @@ static int adfs_fplus_read(struct super_block *sb, u32 indaddr,
 	if (ret)
 		return ret;
 
-	t = (struct adfs_bigdirtail *)
+	dir->bigtail = t = (struct adfs_bigdirtail *)
 		(dir->bhs[dir->nr_buffers - 1]->b_data + (sb->s_blocksize - 8));
 
 	if (t->bigdirendname != cpu_to_le32(BIGDIRENDNAME) ||
@@ -62,11 +62,9 @@ static int adfs_fplus_read(struct super_block *sb, u32 indaddr,
 static int
 adfs_fplus_setpos(struct adfs_dir *dir, unsigned int fpos)
 {
-	struct adfs_bigdirheader *h =
-		(struct adfs_bigdirheader *) dir->bhs[0]->b_data;
 	int ret = -ENOENT;
 
-	if (fpos <= le32_to_cpu(h->bigdirentries)) {
+	if (fpos <= le32_to_cpu(dir->bighead->bigdirentries)) {
 		dir->pos = fpos;
 		ret = 0;
 	}
@@ -77,8 +75,7 @@ adfs_fplus_setpos(struct adfs_dir *dir, unsigned int fpos)
 static int
 adfs_fplus_getnext(struct adfs_dir *dir, struct object_info *obj)
 {
-	struct adfs_bigdirheader *h =
-		(struct adfs_bigdirheader *) dir->bhs[0]->b_data;
+	struct adfs_bigdirheader *h = dir->bighead;
 	struct adfs_bigdirentry bde;
 	unsigned int offset;
 	int ret;
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 26/41] fs/adfs: newdir: factor out directory format validation
  2019-12-09 11:07 [PATCH 00/41] fs/adfs updates for 5.6 Russell King - ARM Linux admin
                   ` (24 preceding siblings ...)
  2019-12-09 11:10 ` [PATCH 25/41] fs/adfs: dir: use pointers to access directory head/tails Russell King
@ 2019-12-09 11:10 ` Russell King
  2019-12-09 11:10 ` [PATCH 27/41] fs/adfs: newdir: improve directory validation Russell King
                   ` (14 subsequent siblings)
  40 siblings, 0 replies; 47+ messages in thread
From: Russell King @ 2019-12-09 11:10 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel

We have two locations where we validate the new directory format, so
factor this out to a helper.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
 fs/adfs/dir_f.c | 48 ++++++++++++++++++++----------------------------
 1 file changed, 20 insertions(+), 28 deletions(-)

diff --git a/fs/adfs/dir_f.c b/fs/adfs/dir_f.c
index 7e56fcc21303..196706d581bf 100644
--- a/fs/adfs/dir_f.c
+++ b/fs/adfs/dir_f.c
@@ -121,6 +121,21 @@ adfs_dir_checkbyte(const struct adfs_dir *dir)
 	return (dircheck ^ (dircheck >> 8) ^ (dircheck >> 16) ^ (dircheck >> 24)) & 0xff;
 }
 
+static int adfs_f_validate(struct adfs_dir *dir)
+{
+	struct adfs_dirheader *head = dir->dirhead;
+	struct adfs_newdirtail *tail = dir->newtail;
+
+	if (head->startmasseq != tail->endmasseq ||
+	    (memcmp(&head->startname, "Nick", 4) &&
+	     memcmp(&head->startname, "Hugo", 4)) ||
+	    memcmp(&head->startname, &tail->endname, 4) ||
+	    adfs_dir_checkbyte(dir) != tail->dircheckbyte)
+		return -EIO;
+
+	return 0;
+}
+
 /* Read and check that a directory is valid */
 static int adfs_dir_read(struct super_block *sb, u32 indaddr,
 			 unsigned int size, struct adfs_dir *dir)
@@ -142,15 +157,7 @@ static int adfs_dir_read(struct super_block *sb, u32 indaddr,
 	dir->dirhead = bufoff(dir->bh, 0);
 	dir->newtail = bufoff(dir->bh, 2007);
 
-	if (dir->dirhead->startmasseq != dir->newtail->endmasseq ||
-	    memcmp(&dir->dirhead->startname, &dir->newtail->endname, 4))
-		goto bad_dir;
-
-	if (memcmp(&dir->dirhead->startname, "Nick", 4) &&
-	    memcmp(&dir->dirhead->startname, "Hugo", 4))
-		goto bad_dir;
-
-	if (adfs_dir_checkbyte(dir) != dir->newtail->dircheckbyte)
+	if (adfs_f_validate(dir))
 		goto bad_dir;
 
 	return 0;
@@ -327,7 +334,7 @@ adfs_f_update(struct adfs_dir *dir, struct object_info *obj)
 	ret = adfs_dir_find_entry(dir, obj->indaddr);
 	if (ret < 0) {
 		adfs_error(dir->sb, "unable to locate entry to update");
-		goto out;
+		return ret;
 	}
 
 	__adfs_dir_put(dir, ret, obj);
@@ -344,26 +351,11 @@ adfs_f_update(struct adfs_dir *dir, struct object_info *obj)
 	 */
 	dir->newtail->dircheckbyte = ret;
 
-#if 1
-	if (dir->dirhead->startmasseq != dir->newtail->endmasseq ||
-	    memcmp(&dir->dirhead->startname, &dir->newtail->endname, 4))
-		goto bad_dir;
-
-	if (memcmp(&dir->dirhead->startname, "Nick", 4) &&
-	    memcmp(&dir->dirhead->startname, "Hugo", 4))
-		goto bad_dir;
+	ret = adfs_f_validate(dir);
+	if (ret)
+		adfs_error(dir->sb, "whoops!  I broke a directory!");
 
-	if (adfs_dir_checkbyte(dir) != dir->newtail->dircheckbyte)
-		goto bad_dir;
-#endif
-	ret = 0;
-out:
 	return ret;
-#if 1
-bad_dir:
-	adfs_error(dir->sb, "whoops!  I broke a directory!");
-	return -EIO;
-#endif
 }
 
 const struct adfs_dir_ops adfs_f_dir_ops = {
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 27/41] fs/adfs: newdir: improve directory validation
  2019-12-09 11:07 [PATCH 00/41] fs/adfs updates for 5.6 Russell King - ARM Linux admin
                   ` (25 preceding siblings ...)
  2019-12-09 11:10 ` [PATCH 26/41] fs/adfs: newdir: factor out directory format validation Russell King
@ 2019-12-09 11:10 ` Russell King
  2019-12-09 11:10 ` [PATCH 28/41] fs/adfs: newdir: merge adfs_dir_read() into adfs_f_read() Russell King
                   ` (13 subsequent siblings)
  40 siblings, 0 replies; 47+ messages in thread
From: Russell King @ 2019-12-09 11:10 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel

Check that the lastmask and reserved fields are all zero, as per the
documentation.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
 fs/adfs/dir_f.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/fs/adfs/dir_f.c b/fs/adfs/dir_f.c
index 196706d581bf..ebe8616ee533 100644
--- a/fs/adfs/dir_f.c
+++ b/fs/adfs/dir_f.c
@@ -127,6 +127,7 @@ static int adfs_f_validate(struct adfs_dir *dir)
 	struct adfs_newdirtail *tail = dir->newtail;
 
 	if (head->startmasseq != tail->endmasseq ||
+	    tail->dirlastmask || tail->reserved[0] || tail->reserved[1] ||
 	    (memcmp(&head->startname, "Nick", 4) &&
 	     memcmp(&head->startname, "Hugo", 4)) ||
 	    memcmp(&head->startname, &tail->endname, 4) ||
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 28/41] fs/adfs: newdir: merge adfs_dir_read() into adfs_f_read()
  2019-12-09 11:07 [PATCH 00/41] fs/adfs updates for 5.6 Russell King - ARM Linux admin
                   ` (26 preceding siblings ...)
  2019-12-09 11:10 ` [PATCH 27/41] fs/adfs: newdir: improve directory validation Russell King
@ 2019-12-09 11:10 ` Russell King
  2019-12-09 11:10 ` [PATCH 29/41] fs/adfs: newdir: clean up adfs_f_update() Russell King
                   ` (12 subsequent siblings)
  40 siblings, 0 replies; 47+ messages in thread
From: Russell King @ 2019-12-09 11:10 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel

adfs_dir_read() is only called from adfs_f_read(), so merge it into
that function.  As new directories are always 2048 bytes in size,
(which we rely on elsewhere) we can consolidate some of the code.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
 fs/adfs/dir_f.c | 33 +++++++--------------------------
 1 file changed, 7 insertions(+), 26 deletions(-)

diff --git a/fs/adfs/dir_f.c b/fs/adfs/dir_f.c
index ebe8616ee533..dbb4f1ef7bb7 100644
--- a/fs/adfs/dir_f.c
+++ b/fs/adfs/dir_f.c
@@ -138,20 +138,16 @@ static int adfs_f_validate(struct adfs_dir *dir)
 }
 
 /* Read and check that a directory is valid */
-static int adfs_dir_read(struct super_block *sb, u32 indaddr,
-			 unsigned int size, struct adfs_dir *dir)
+static int adfs_f_read(struct super_block *sb, u32 indaddr, unsigned int size,
+		       struct adfs_dir *dir)
 {
 	const unsigned int blocksize_bits = sb->s_blocksize_bits;
 	int ret;
 
-	/*
-	 * Directories which are not a multiple of 2048 bytes
-	 * are considered bad v2 [3.6]
-	 */
-	if (size & 2047)
-		goto bad_dir;
+	if (size && size != ADFS_NEWDIR_SIZE)
+		return -EIO;
 
-	ret = adfs_dir_read_buffers(sb, indaddr, size, dir);
+	ret = adfs_dir_read_buffers(sb, indaddr, ADFS_NEWDIR_SIZE, dir);
 	if (ret)
 		return ret;
 
@@ -161,6 +157,8 @@ static int adfs_dir_read(struct super_block *sb, u32 indaddr,
 	if (adfs_f_validate(dir))
 		goto bad_dir;
 
+	dir->parent_id = adfs_readval(dir->newtail->dirparent, 3);
+
 	return 0;
 
 bad_dir:
@@ -271,23 +269,6 @@ static int adfs_dir_find_entry(struct adfs_dir *dir, u32 indaddr)
 	return ret;
 }
 
-static int adfs_f_read(struct super_block *sb, u32 indaddr, unsigned int size,
-		       struct adfs_dir *dir)
-{
-	int ret;
-
-	if (size != ADFS_NEWDIR_SIZE)
-		return -EIO;
-
-	ret = adfs_dir_read(sb, indaddr, size, dir);
-	if (ret)
-		adfs_error(sb, "unable to read directory");
-	else
-		dir->parent_id = adfs_readval(dir->newtail->dirparent, 3);
-
-	return ret;
-}
-
 static int
 adfs_f_setpos(struct adfs_dir *dir, unsigned int fpos)
 {
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 29/41] fs/adfs: newdir: clean up adfs_f_update()
  2019-12-09 11:07 [PATCH 00/41] fs/adfs updates for 5.6 Russell King - ARM Linux admin
                   ` (27 preceding siblings ...)
  2019-12-09 11:10 ` [PATCH 28/41] fs/adfs: newdir: merge adfs_dir_read() into adfs_f_read() Russell King
@ 2019-12-09 11:10 ` Russell King
  2019-12-09 11:10 ` [PATCH 30/41] fs/adfs: newdir: split out directory commit from update Russell King
                   ` (11 subsequent siblings)
  40 siblings, 0 replies; 47+ messages in thread
From: Russell King @ 2019-12-09 11:10 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel

__adfs_dir_put() and adfs_dir_find_entry() are only called from
adfs_f_update(), so move them into this function, removing some
unnecessary entry copying by doing so.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
 fs/adfs/dir_f.c | 73 ++++++++++++++++---------------------------------
 1 file changed, 24 insertions(+), 49 deletions(-)

diff --git a/fs/adfs/dir_f.c b/fs/adfs/dir_f.c
index dbb4f1ef7bb7..36cfadb2b893 100644
--- a/fs/adfs/dir_f.c
+++ b/fs/adfs/dir_f.c
@@ -229,46 +229,6 @@ __adfs_dir_get(struct adfs_dir *dir, int pos, struct object_info *obj)
 	return 0;
 }
 
-static int
-__adfs_dir_put(struct adfs_dir *dir, int pos, struct object_info *obj)
-{
-	struct adfs_direntry de;
-	int ret;
-
-	ret = adfs_dir_copyfrom(&de, dir, pos, 26);
-	if (ret)
-		return ret;
-
-	adfs_obj2dir(&de, obj);
-
-	return adfs_dir_copyto(dir, pos, &de, 26);
-}
-
-/*
- * the caller is responsible for holding the necessary
- * locks.
- */
-static int adfs_dir_find_entry(struct adfs_dir *dir, u32 indaddr)
-{
-	int pos, ret;
-
-	ret = -ENOENT;
-
-	for (pos = 5; pos < ADFS_NUM_DIR_ENTRIES * 26 + 5; pos += 26) {
-		struct object_info obj;
-
-		if (!__adfs_dir_get(dir, pos, &obj))
-			break;
-
-		if (obj.indaddr == indaddr) {
-			ret = pos;
-			break;
-		}
-	}
-
-	return ret;
-}
-
 static int
 adfs_f_setpos(struct adfs_dir *dir, unsigned int fpos)
 {
@@ -308,18 +268,33 @@ static int adfs_f_iterate(struct adfs_dir *dir, struct dir_context *ctx)
 	return 0;
 }
 
-static int
-adfs_f_update(struct adfs_dir *dir, struct object_info *obj)
+static int adfs_f_update(struct adfs_dir *dir, struct object_info *obj)
 {
-	int ret;
+	struct adfs_direntry de;
+	int offset, ret;
 
-	ret = adfs_dir_find_entry(dir, obj->indaddr);
-	if (ret < 0) {
-		adfs_error(dir->sb, "unable to locate entry to update");
-		return ret;
-	}
+	offset = 5 - (int)sizeof(de);
+
+	do {
+		offset += sizeof(de);
+		ret = adfs_dir_copyfrom(&de, dir, offset, sizeof(de));
+		if (ret) {
+			adfs_error(dir->sb, "error reading directory entry");
+			return -ENOENT;
+		}
+		if (!de.dirobname[0]) {
+			adfs_error(dir->sb, "unable to locate entry to update");
+			return -ENOENT;
+		}
+	} while (adfs_readval(de.dirinddiscadd, 3) != obj->indaddr);
+
+	/* Update the directory entry with the new object state */
+	adfs_obj2dir(&de, obj);
 
-	__adfs_dir_put(dir, ret, obj);
+	/* Write the directory entry back to the directory */
+	ret = adfs_dir_copyto(dir, pos, &de, 26);
+	if (ret)
+		return ret;
  
 	/*
 	 * Increment directory sequence number
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 30/41] fs/adfs: newdir: split out directory commit from update
  2019-12-09 11:07 [PATCH 00/41] fs/adfs updates for 5.6 Russell King - ARM Linux admin
                   ` (28 preceding siblings ...)
  2019-12-09 11:10 ` [PATCH 29/41] fs/adfs: newdir: clean up adfs_f_update() Russell King
@ 2019-12-09 11:10 ` Russell King
  2019-12-09 11:10 ` [PATCH 31/41] fs/adfs: bigdir: factor out directory entry offset calculation Russell King
                   ` (10 subsequent siblings)
  40 siblings, 0 replies; 47+ messages in thread
From: Russell King @ 2019-12-09 11:10 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel

After changing a directory, we need to update the sequence numbers and
calculate the new check byte before the directory is scheduled to be
written back to the media.  Since this needs to happen for any change
to the directory, move this into a separate method.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
 fs/adfs/adfs.h  |  1 +
 fs/adfs/dir.c   |  4 ++++
 fs/adfs/dir_f.c | 26 +++++++++++++-------------
 3 files changed, 18 insertions(+), 13 deletions(-)

diff --git a/fs/adfs/adfs.h b/fs/adfs/adfs.h
index 1f431a42e14c..c05555252fec 100644
--- a/fs/adfs/adfs.h
+++ b/fs/adfs/adfs.h
@@ -130,6 +130,7 @@ struct adfs_dir_ops {
 	int	(*update)(struct adfs_dir *dir, struct object_info *obj);
 	int	(*create)(struct adfs_dir *dir, struct object_info *obj);
 	int	(*remove)(struct adfs_dir *dir, struct object_info *obj);
+	int	(*commit)(struct adfs_dir *dir);
 };
 
 struct adfs_discmap {
diff --git a/fs/adfs/dir.c b/fs/adfs/dir.c
index 7fda44464121..3d4bbe836fb5 100644
--- a/fs/adfs/dir.c
+++ b/fs/adfs/dir.c
@@ -293,6 +293,10 @@ adfs_dir_update(struct super_block *sb, struct object_info *obj, int wait)
 		goto unlock;
 
 	ret = ops->update(&dir, obj);
+	if (ret)
+		goto forget;
+
+	ret = ops->commit(&dir);
 	if (ret)
 		goto forget;
 	up_write(&adfs_dir_rwsem);
diff --git a/fs/adfs/dir_f.c b/fs/adfs/dir_f.c
index 36cfadb2b893..30d526fecc3f 100644
--- a/fs/adfs/dir_f.c
+++ b/fs/adfs/dir_f.c
@@ -292,25 +292,24 @@ static int adfs_f_update(struct adfs_dir *dir, struct object_info *obj)
 	adfs_obj2dir(&de, obj);
 
 	/* Write the directory entry back to the directory */
-	ret = adfs_dir_copyto(dir, pos, &de, 26);
-	if (ret)
-		return ret;
- 
-	/*
-	 * Increment directory sequence number
-	 */
+	return adfs_dir_copyto(dir, offset, &de, 26);
+}
+
+static int adfs_f_commit(struct adfs_dir *dir)
+{
+	int ret;
+
+	/* Increment directory sequence number */
 	dir->dirhead->startmasseq += 1;
 	dir->newtail->endmasseq += 1;
 
-	ret = adfs_dir_checkbyte(dir);
-	/*
-	 * Update directory check byte
-	 */
-	dir->newtail->dircheckbyte = ret;
+	/* Update directory check byte */
+	dir->newtail->dircheckbyte = adfs_dir_checkbyte(dir);
 
+	/* Make sure the directory still validates correctly */
 	ret = adfs_f_validate(dir);
 	if (ret)
-		adfs_error(dir->sb, "whoops!  I broke a directory!");
+		adfs_msg(dir->sb, KERN_ERR, "error: update broke directory");
 
 	return ret;
 }
@@ -321,4 +320,5 @@ const struct adfs_dir_ops adfs_f_dir_ops = {
 	.setpos		= adfs_f_setpos,
 	.getnext	= adfs_f_getnext,
 	.update		= adfs_f_update,
+	.commit		= adfs_f_commit,
 };
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 31/41] fs/adfs: bigdir: factor out directory entry offset calculation
  2019-12-09 11:07 [PATCH 00/41] fs/adfs updates for 5.6 Russell King - ARM Linux admin
                   ` (29 preceding siblings ...)
  2019-12-09 11:10 ` [PATCH 30/41] fs/adfs: newdir: split out directory commit from update Russell King
@ 2019-12-09 11:10 ` Russell King
  2019-12-09 11:10 ` [PATCH 32/41] fs/adfs: bigdir: extract directory validation Russell King
                   ` (9 subsequent siblings)
  40 siblings, 0 replies; 47+ messages in thread
From: Russell King @ 2019-12-09 11:10 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel

Factor out the directory entry byte offset calculation.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
 fs/adfs/dir_fplus.c | 17 +++++++++++------
 1 file changed, 11 insertions(+), 6 deletions(-)

diff --git a/fs/adfs/dir_fplus.c b/fs/adfs/dir_fplus.c
index 6f2dbcf6819b..393921f5121e 100644
--- a/fs/adfs/dir_fplus.c
+++ b/fs/adfs/dir_fplus.c
@@ -7,6 +7,15 @@
 #include "adfs.h"
 #include "dir_fplus.h"
 
+/* Return the byte offset to directory entry pos */
+static unsigned int adfs_fplus_offset(const struct adfs_bigdirheader *h,
+				      unsigned int pos)
+{
+	return offsetof(struct adfs_bigdirheader, bigdirname) +
+	       ALIGN(le32_to_cpu(h->bigdirnamelen), 4) +
+	       pos * sizeof(struct adfs_bigdirentry);
+}
+
 static int adfs_fplus_read(struct super_block *sb, u32 indaddr,
 			   unsigned int size, struct adfs_dir *dir)
 {
@@ -83,9 +92,7 @@ adfs_fplus_getnext(struct adfs_dir *dir, struct object_info *obj)
 	if (dir->pos >= le32_to_cpu(h->bigdirentries))
 		return -ENOENT;
 
-	offset = offsetof(struct adfs_bigdirheader, bigdirname);
-	offset += ((le32_to_cpu(h->bigdirnamelen) + 4) & ~3);
-	offset += dir->pos * sizeof(struct adfs_bigdirentry);
+	offset = adfs_fplus_offset(h, dir->pos);
 
 	ret = adfs_dir_copyfrom(&bde, dir, offset,
 				sizeof(struct adfs_bigdirentry));
@@ -99,9 +106,7 @@ adfs_fplus_getnext(struct adfs_dir *dir, struct object_info *obj)
 	obj->attr     = le32_to_cpu(bde.bigdirattr);
 	obj->name_len = le32_to_cpu(bde.bigdirobnamelen);
 
-	offset = offsetof(struct adfs_bigdirheader, bigdirname);
-	offset += ((le32_to_cpu(h->bigdirnamelen) + 4) & ~3);
-	offset += le32_to_cpu(h->bigdirentries) * sizeof(struct adfs_bigdirentry);
+	offset = adfs_fplus_offset(h, le32_to_cpu(h->bigdirentries));
 	offset += le32_to_cpu(bde.bigdirobnameptr);
 
 	ret = adfs_dir_copyfrom(obj->name, dir, offset, obj->name_len);
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 32/41] fs/adfs: bigdir: extract directory validation
  2019-12-09 11:07 [PATCH 00/41] fs/adfs updates for 5.6 Russell King - ARM Linux admin
                   ` (30 preceding siblings ...)
  2019-12-09 11:10 ` [PATCH 31/41] fs/adfs: bigdir: factor out directory entry offset calculation Russell King
@ 2019-12-09 11:10 ` Russell King
  2019-12-09 11:11 ` [PATCH 33/41] fs/adfs: bigdir: directory validation strengthening Russell King
                   ` (8 subsequent siblings)
  40 siblings, 0 replies; 47+ messages in thread
From: Russell King @ 2019-12-09 11:10 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel

Extract the directory validation from the directory reading function as
we will want to re-use this code.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
 fs/adfs/dir_fplus.c | 41 +++++++++++++++++++++++++++++++----------
 1 file changed, 31 insertions(+), 10 deletions(-)

diff --git a/fs/adfs/dir_fplus.c b/fs/adfs/dir_fplus.c
index 393921f5121e..b83a74e9ff6d 100644
--- a/fs/adfs/dir_fplus.c
+++ b/fs/adfs/dir_fplus.c
@@ -16,6 +16,30 @@ static unsigned int adfs_fplus_offset(const struct adfs_bigdirheader *h,
 	       pos * sizeof(struct adfs_bigdirentry);
 }
 
+static int adfs_fplus_validate_header(const struct adfs_bigdirheader *h)
+{
+	unsigned int size = le32_to_cpu(h->bigdirsize);
+
+	if (h->bigdirversion[0] != 0 || h->bigdirversion[1] != 0 ||
+	    h->bigdirversion[2] != 0 ||
+	    h->bigdirstartname != cpu_to_le32(BIGDIRSTARTNAME) ||
+	    size & 2047)
+		return -EIO;
+
+	return 0;
+}
+
+static int adfs_fplus_validate_tail(const struct adfs_bigdirheader *h,
+				    const struct adfs_bigdirtail *t)
+{
+	if (t->bigdirendname != cpu_to_le32(BIGDIRENDNAME) ||
+	    t->bigdirendmasseq != h->startmasseq ||
+	    t->reserved[0] != 0 || t->reserved[1] != 0)
+		return -EIO;
+
+	return 0;
+}
+
 static int adfs_fplus_read(struct super_block *sb, u32 indaddr,
 			   unsigned int size, struct adfs_dir *dir)
 {
@@ -30,6 +54,11 @@ static int adfs_fplus_read(struct super_block *sb, u32 indaddr,
 		return ret;
 
 	dir->bighead = h = (void *)dir->bhs[0]->b_data;
+	if (adfs_fplus_validate_header(h)) {
+		adfs_error(sb, "dir %06x has malformed header", indaddr);
+		goto out;
+	}
+
 	dirsize = le32_to_cpu(h->bigdirsize);
 	if (dirsize != size) {
 		adfs_msg(sb, KERN_WARNING,
@@ -37,13 +66,6 @@ static int adfs_fplus_read(struct super_block *sb, u32 indaddr,
 			 indaddr, dirsize, size);
 	}
 
-	if (h->bigdirversion[0] != 0 || h->bigdirversion[1] != 0 ||
-	    h->bigdirversion[2] != 0 || size & 2047 ||
-	    h->bigdirstartname != cpu_to_le32(BIGDIRSTARTNAME)) {
-		adfs_error(sb, "dir %06x has malformed header", indaddr);
-		goto out;
-	}
-
 	/* Read remaining buffers */
 	ret = adfs_dir_read_buffers(sb, indaddr, dirsize, dir);
 	if (ret)
@@ -52,9 +74,8 @@ static int adfs_fplus_read(struct super_block *sb, u32 indaddr,
 	dir->bigtail = t = (struct adfs_bigdirtail *)
 		(dir->bhs[dir->nr_buffers - 1]->b_data + (sb->s_blocksize - 8));
 
-	if (t->bigdirendname != cpu_to_le32(BIGDIRENDNAME) ||
-	    t->bigdirendmasseq != h->startmasseq ||
-	    t->reserved[0] != 0 || t->reserved[1] != 0) {
+	ret = adfs_fplus_validate_tail(h, t);
+	if (ret) {
 		adfs_error(sb, "dir %06x has malformed tail", indaddr);
 		goto out;
 	}
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 33/41] fs/adfs: bigdir: directory validation strengthening
  2019-12-09 11:07 [PATCH 00/41] fs/adfs updates for 5.6 Russell King - ARM Linux admin
                   ` (31 preceding siblings ...)
  2019-12-09 11:10 ` [PATCH 32/41] fs/adfs: bigdir: extract directory validation Russell King
@ 2019-12-09 11:11 ` Russell King
  2019-12-09 11:11 ` [PATCH 34/41] fs/adfs: bigdir: calculate and validate directory checkbyte Russell King
                   ` (7 subsequent siblings)
  40 siblings, 0 replies; 47+ messages in thread
From: Russell King @ 2019-12-09 11:11 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel

Strengthen the directory validation by ensuring that the header fields
contain sensible values that fit inside the directory, and limit the
directory size to 4MB as per RISC OS requirements.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
 fs/adfs/dir_fplus.c | 29 ++++++++++++++++++++++++++++-
 1 file changed, 28 insertions(+), 1 deletion(-)

diff --git a/fs/adfs/dir_fplus.c b/fs/adfs/dir_fplus.c
index b83a74e9ff6d..a2fa416fbb6d 100644
--- a/fs/adfs/dir_fplus.c
+++ b/fs/adfs/dir_fplus.c
@@ -19,11 +19,38 @@ static unsigned int adfs_fplus_offset(const struct adfs_bigdirheader *h,
 static int adfs_fplus_validate_header(const struct adfs_bigdirheader *h)
 {
 	unsigned int size = le32_to_cpu(h->bigdirsize);
+	unsigned int len;
 
 	if (h->bigdirversion[0] != 0 || h->bigdirversion[1] != 0 ||
 	    h->bigdirversion[2] != 0 ||
 	    h->bigdirstartname != cpu_to_le32(BIGDIRSTARTNAME) ||
-	    size & 2047)
+	    !size || size & 2047 || size > SZ_4M)
+		return -EIO;
+
+	size -= sizeof(struct adfs_bigdirtail) +
+		offsetof(struct adfs_bigdirheader, bigdirname);
+
+	/* Check that bigdirnamelen fits within the directory */
+	len = ALIGN(le32_to_cpu(h->bigdirnamelen), 4);
+	if (len > size)
+		return -EIO;
+
+	size -= len;
+
+	/* Check that bigdirnamesize fits within the directory */
+	len = le32_to_cpu(h->bigdirnamesize);
+	if (len > size)
+		return -EIO;
+
+	size -= len;
+
+	/*
+	 * Avoid division, we know that absolute maximum number of entries
+	 * can not be so large to cause overflow of the multiplication below.
+	 */
+	len = le32_to_cpu(h->bigdirentries);
+	if (len > SZ_4M / sizeof(struct adfs_bigdirentry) ||
+	    len * sizeof(struct adfs_bigdirentry) > size)
 		return -EIO;
 
 	return 0;
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 34/41] fs/adfs: bigdir: calculate and validate directory checkbyte
  2019-12-09 11:07 [PATCH 00/41] fs/adfs updates for 5.6 Russell King - ARM Linux admin
                   ` (32 preceding siblings ...)
  2019-12-09 11:11 ` [PATCH 33/41] fs/adfs: bigdir: directory validation strengthening Russell King
@ 2019-12-09 11:11 ` Russell King
  2019-12-09 11:11 ` [PATCH 35/41] fs/adfs: bigdir: implement directory update support Russell King
                   ` (6 subsequent siblings)
  40 siblings, 0 replies; 47+ messages in thread
From: Russell King @ 2019-12-09 11:11 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel

When reading a big directory, calculate the validate the directory
checkbyte to ensure that the directory contents are valid.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
 fs/adfs/dir_fplus.c | 38 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 38 insertions(+)

diff --git a/fs/adfs/dir_fplus.c b/fs/adfs/dir_fplus.c
index a2fa416fbb6d..4ab8987962f0 100644
--- a/fs/adfs/dir_fplus.c
+++ b/fs/adfs/dir_fplus.c
@@ -67,6 +67,39 @@ static int adfs_fplus_validate_tail(const struct adfs_bigdirheader *h,
 	return 0;
 }
 
+static u8 adfs_fplus_checkbyte(struct adfs_dir *dir)
+{
+	struct adfs_bigdirheader *h = dir->bighead;
+	struct adfs_bigdirtail *t = dir->bigtail;
+	unsigned int end, bs, bi, i;
+	__le32 *bp;
+	u32 dircheck;
+
+	end = adfs_fplus_offset(h, le32_to_cpu(h->bigdirentries)) +
+		le32_to_cpu(h->bigdirnamesize);
+
+	/* Accumulate the contents of the header, entries and names */
+	for (dircheck = 0, bi = 0; end; bi++) {
+		bp = (void *)dir->bhs[bi]->b_data;
+		bs = dir->bhs[bi]->b_size;
+		if (bs > end)
+			bs = end;
+
+		for (i = 0; i < bs; i += sizeof(u32))
+			dircheck = ror32(dircheck, 13) ^ le32_to_cpup(bp++);
+
+		end -= bs;
+	}
+
+	/* Accumulate the contents of the tail except for the check byte */
+	dircheck = ror32(dircheck, 13) ^ le32_to_cpu(t->bigdirendname);
+	dircheck = ror32(dircheck, 13) ^ t->bigdirendmasseq;
+	dircheck = ror32(dircheck, 13) ^ t->reserved[0];
+	dircheck = ror32(dircheck, 13) ^ t->reserved[1];
+
+	return dircheck ^ dircheck >> 8 ^ dircheck >> 16 ^ dircheck >> 24;
+}
+
 static int adfs_fplus_read(struct super_block *sb, u32 indaddr,
 			   unsigned int size, struct adfs_dir *dir)
 {
@@ -107,6 +140,11 @@ static int adfs_fplus_read(struct super_block *sb, u32 indaddr,
 		goto out;
 	}
 
+	if (adfs_fplus_checkbyte(dir) != t->bigdircheckbyte) {
+		adfs_error(sb, "dir %06x checkbyte mismatch\n", indaddr);
+		goto out;
+	}
+
 	dir->parent_id = le32_to_cpu(h->bigdirparent);
 	return 0;
 
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 35/41] fs/adfs: bigdir: implement directory update support
  2019-12-09 11:07 [PATCH 00/41] fs/adfs updates for 5.6 Russell King - ARM Linux admin
                   ` (33 preceding siblings ...)
  2019-12-09 11:11 ` [PATCH 34/41] fs/adfs: bigdir: calculate and validate directory checkbyte Russell King
@ 2019-12-09 11:11 ` Russell King
  2019-12-09 11:11 ` [PATCH 36/41] fs/adfs: super: fix inode dropping Russell King
                   ` (5 subsequent siblings)
  40 siblings, 0 replies; 47+ messages in thread
From: Russell King @ 2019-12-09 11:11 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel

Implement big directory entry update support in the same way that we
do for new directories.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
 fs/adfs/dir_fplus.c | 54 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 53 insertions(+), 1 deletion(-)

diff --git a/fs/adfs/dir_fplus.c b/fs/adfs/dir_fplus.c
index 4ab8987962f0..48ea299b6ece 100644
--- a/fs/adfs/dir_fplus.c
+++ b/fs/adfs/dir_fplus.c
@@ -120,7 +120,7 @@ static int adfs_fplus_read(struct super_block *sb, u32 indaddr,
 	}
 
 	dirsize = le32_to_cpu(h->bigdirsize);
-	if (dirsize != size) {
+	if (size && dirsize != size) {
 		adfs_msg(sb, KERN_WARNING,
 			 "dir %06x header size %X does not match directory size %X",
 			 indaddr, dirsize, size);
@@ -226,9 +226,61 @@ static int adfs_fplus_iterate(struct adfs_dir *dir, struct dir_context *ctx)
 	return 0;
 }
 
+static int adfs_fplus_update(struct adfs_dir *dir, struct object_info *obj)
+{
+	struct adfs_bigdirheader *h = dir->bighead;
+	struct adfs_bigdirentry bde;
+	int offset, end, ret;
+
+	offset = adfs_fplus_offset(h, 0) - sizeof(bde);
+	end = adfs_fplus_offset(h, le32_to_cpu(h->bigdirentries));
+
+	do {
+		offset += sizeof(bde);
+		if (offset >= end) {
+			adfs_error(dir->sb, "unable to locate entry to update");
+			return -ENOENT;
+		}
+		ret = adfs_dir_copyfrom(&bde, dir, offset, sizeof(bde));
+		if (ret) {
+			adfs_error(dir->sb, "error reading directory entry");
+			return -ENOENT;
+		}
+	} while (le32_to_cpu(bde.bigdirindaddr) != obj->indaddr);
+
+	bde.bigdirload    = cpu_to_le32(obj->loadaddr);
+	bde.bigdirexec    = cpu_to_le32(obj->execaddr);
+	bde.bigdirlen     = cpu_to_le32(obj->size);
+	bde.bigdirindaddr = cpu_to_le32(obj->indaddr);
+	bde.bigdirattr    = cpu_to_le32(obj->attr);
+
+	return adfs_dir_copyto(dir, offset, &bde, sizeof(bde));
+}
+
+static int adfs_fplus_commit(struct adfs_dir *dir)
+{
+	int ret;
+
+	/* Increment directory sequence number */
+	dir->bighead->startmasseq += 1;
+	dir->bigtail->bigdirendmasseq += 1;
+
+	/* Update directory check byte */
+	dir->bigtail->bigdircheckbyte = adfs_fplus_checkbyte(dir);
+
+	/* Make sure the directory still validates correctly */
+	ret = adfs_fplus_validate_header(dir->bighead);
+	if (ret == 0)
+		ret = adfs_fplus_validate_tail(dir->bighead, dir->bigtail);
+
+	return ret;
+}
+
 const struct adfs_dir_ops adfs_fplus_dir_ops = {
 	.read		= adfs_fplus_read,
 	.iterate	= adfs_fplus_iterate,
 	.setpos		= adfs_fplus_setpos,
 	.getnext	= adfs_fplus_getnext,
+	.update		= adfs_fplus_update,
+	.commit		= adfs_fplus_commit,
 };
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 36/41] fs/adfs: super: fix inode dropping
  2019-12-09 11:07 [PATCH 00/41] fs/adfs updates for 5.6 Russell King - ARM Linux admin
                   ` (34 preceding siblings ...)
  2019-12-09 11:11 ` [PATCH 35/41] fs/adfs: bigdir: implement directory update support Russell King
@ 2019-12-09 11:11 ` Russell King
  2019-12-09 11:11 ` [PATCH 37/41] fs/adfs: dir: remove debug in adfs_dir_update() Russell King
                   ` (4 subsequent siblings)
  40 siblings, 0 replies; 47+ messages in thread
From: Russell King @ 2019-12-09 11:11 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel

When we have write support enabled, we must not drop inodes before they
have been written back, otherwise we lose updates to the filesystem on
umount.  Keep the inodes around unless we are built in read-only mode,
or we are mounted read-only.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
 fs/adfs/super.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/fs/adfs/super.c b/fs/adfs/super.c
index b2455e9ab923..9c93122925cf 100644
--- a/fs/adfs/super.c
+++ b/fs/adfs/super.c
@@ -231,6 +231,12 @@ static void adfs_free_inode(struct inode *inode)
 	kmem_cache_free(adfs_inode_cachep, ADFS_I(inode));
 }
 
+static int adfs_drop_inode(struct inode *inode)
+{
+	/* always drop inodes if we are read-only */
+	return !IS_ENABLED(CONFIG_ADFS_FS_RW) || IS_RDONLY(inode);
+}
+
 static void init_once(void *foo)
 {
 	struct adfs_inode_info *ei = (struct adfs_inode_info *) foo;
@@ -263,7 +269,7 @@ static void destroy_inodecache(void)
 static const struct super_operations adfs_sops = {
 	.alloc_inode	= adfs_alloc_inode,
 	.free_inode	= adfs_free_inode,
-	.drop_inode	= generic_delete_inode,
+	.drop_inode	= adfs_drop_inode,
 	.write_inode	= adfs_write_inode,
 	.put_super	= adfs_put_super,
 	.statfs		= adfs_statfs,
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 37/41] fs/adfs: dir: remove debug in adfs_dir_update()
  2019-12-09 11:07 [PATCH 00/41] fs/adfs updates for 5.6 Russell King - ARM Linux admin
                   ` (35 preceding siblings ...)
  2019-12-09 11:11 ` [PATCH 36/41] fs/adfs: super: fix inode dropping Russell King
@ 2019-12-09 11:11 ` Russell King
  2019-12-09 11:11 ` [PATCH 38/41] fs/adfs: super: extract filesystem block probe Russell King
                   ` (3 subsequent siblings)
  40 siblings, 0 replies; 47+ messages in thread
From: Russell King @ 2019-12-09 11:11 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel

Remove the noisy debug in adfs_dir_update().

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
 fs/adfs/dir.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/fs/adfs/dir.c b/fs/adfs/dir.c
index 3d4bbe836fb5..dd940f17767d 100644
--- a/fs/adfs/dir.c
+++ b/fs/adfs/dir.c
@@ -278,9 +278,6 @@ adfs_dir_update(struct super_block *sb, struct object_info *obj, int wait)
 	struct adfs_dir dir;
 	int ret;
 
-	printk(KERN_INFO "adfs_dir_update: object %06x in dir %06x\n",
-		 obj->indaddr, obj->parent_id);
-
 	if (!IS_ENABLED(CONFIG_ADFS_FS_RW))
 		return -EINVAL;
 
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 38/41] fs/adfs: super: extract filesystem block probe
  2019-12-09 11:07 [PATCH 00/41] fs/adfs updates for 5.6 Russell King - ARM Linux admin
                   ` (36 preceding siblings ...)
  2019-12-09 11:11 ` [PATCH 37/41] fs/adfs: dir: remove debug in adfs_dir_update() Russell King
@ 2019-12-09 11:11 ` Russell King
  2019-12-09 11:11 ` [PATCH 39/41] fs/adfs: super: add support for E and E+ floppy image formats Russell King
                   ` (2 subsequent siblings)
  40 siblings, 0 replies; 47+ messages in thread
From: Russell King @ 2019-12-09 11:11 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel

Separate the filesystem block probing from the superblock filling so
we can support other ADFS filesystem formats, such as the single-zone
E and E+ floppy image formats which do not have a boot block.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
 fs/adfs/super.c | 149 +++++++++++++++++++++++++-----------------------
 1 file changed, 78 insertions(+), 71 deletions(-)

diff --git a/fs/adfs/super.c b/fs/adfs/super.c
index 9c93122925cf..4c06b2d5a861 100644
--- a/fs/adfs/super.c
+++ b/fs/adfs/super.c
@@ -277,13 +277,80 @@ static const struct super_operations adfs_sops = {
 	.show_options	= adfs_show_options,
 };
 
-static int adfs_fill_super(struct super_block *sb, void *data, int silent)
+static int adfs_probe(struct super_block *sb, unsigned int offset, int silent,
+		      int (*validate)(struct super_block *sb,
+				      struct buffer_head *bh,
+				      struct adfs_discrecord **bhp))
 {
+	struct adfs_sb_info *asb = ADFS_SB(sb);
 	struct adfs_discrecord *dr;
 	struct buffer_head *bh;
-	struct object_info root_obj;
+	unsigned int blocksize = BLOCK_SIZE;
+	int ret, try;
+
+	for (try = 0; try < 2; try++) {
+		/* try to set the requested block size */
+		if (sb->s_blocksize != blocksize &&
+		    !sb_set_blocksize(sb, blocksize)) {
+			if (!silent)
+				adfs_msg(sb, KERN_ERR,
+					 "error: unsupported blocksize");
+			return -EINVAL;
+		}
+
+		/* read the buffer */
+		bh = sb_bread(sb, offset >> sb->s_blocksize_bits);
+		if (!bh) {
+			adfs_msg(sb, KERN_ERR,
+				 "error: unable to read block %u, try %d",
+				 offset >> sb->s_blocksize_bits, try);
+			return -EIO;
+		}
+
+		/* validate it */
+		ret = validate(sb, bh, &dr);
+		if (ret) {
+			brelse(bh);
+			return ret;
+		}
+
+		/* does the block size match the filesystem block size? */
+		blocksize = 1 << dr->log2secsize;
+		if (sb->s_blocksize == blocksize) {
+			asb->s_map = adfs_read_map(sb, dr);
+			brelse(bh);
+			return PTR_ERR_OR_ZERO(asb->s_map);
+		}
+
+		brelse(bh);
+	}
+
+	return -EIO;
+}
+
+static int adfs_validate_bblk(struct super_block *sb, struct buffer_head *bh,
+			      struct adfs_discrecord **drp)
+{
+	struct adfs_discrecord *dr;
 	unsigned char *b_data;
-	unsigned int blocksize;
+
+	b_data = bh->b_data + (ADFS_DISCRECORD % sb->s_blocksize);
+	if (adfs_checkbblk(b_data))
+		return -EILSEQ;
+
+	/* Do some sanity checks on the ADFS disc record */
+	dr = (struct adfs_discrecord *)(b_data + ADFS_DR_OFFSET);
+	if (adfs_checkdiscrecord(dr))
+		return -EILSEQ;
+
+	*drp = dr;
+	return 0;
+}
+
+static int adfs_fill_super(struct super_block *sb, void *data, int silent)
+{
+	struct adfs_discrecord *dr;
+	struct object_info root_obj;
 	struct adfs_sb_info *asb;
 	struct inode *root;
 	int ret = -EINVAL;
@@ -308,72 +375,19 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent)
 	if (parse_options(sb, asb, data))
 		goto error;
 
-	sb_set_blocksize(sb, BLOCK_SIZE);
-	if (!(bh = sb_bread(sb, ADFS_DISCRECORD / BLOCK_SIZE))) {
-		adfs_msg(sb, KERN_ERR, "error: unable to read superblock");
-		ret = -EIO;
-		goto error;
-	}
-
-	b_data = bh->b_data + (ADFS_DISCRECORD % BLOCK_SIZE);
-
-	if (adfs_checkbblk(b_data)) {
-		ret = -EINVAL;
-		goto error_badfs;
-	}
-
-	dr = (struct adfs_discrecord *)(b_data + ADFS_DR_OFFSET);
-
-	/*
-	 * Do some sanity checks on the ADFS disc record
-	 */
-	if (adfs_checkdiscrecord(dr)) {
-		ret = -EINVAL;
-		goto error_badfs;
-	}
-
-	blocksize = 1 << dr->log2secsize;
-	brelse(bh);
-
-	if (sb_set_blocksize(sb, blocksize)) {
-		bh = sb_bread(sb, ADFS_DISCRECORD / sb->s_blocksize);
-		if (!bh) {
-			adfs_msg(sb, KERN_ERR,
-				 "error: couldn't read superblock on 2nd try.");
-			ret = -EIO;
-			goto error;
-		}
-		b_data = bh->b_data + (ADFS_DISCRECORD % sb->s_blocksize);
-		if (adfs_checkbblk(b_data)) {
-			adfs_msg(sb, KERN_ERR,
-				 "error: disc record mismatch, very weird!");
-			ret = -EINVAL;
-			goto error_free_bh;
-		}
-		dr = (struct adfs_discrecord *)(b_data + ADFS_DR_OFFSET);
-	} else {
+	/* Try to probe the filesystem boot block */
+	ret = adfs_probe(sb, ADFS_DISCRECORD, silent, adfs_validate_bblk);
+	if (ret == -EILSEQ) {
 		if (!silent)
 			adfs_msg(sb, KERN_ERR,
-				 "error: unsupported blocksize");
+				 "error: can't find an ADFS filesystem on dev %s.",
+				 sb->s_id);
 		ret = -EINVAL;
-		goto error;
 	}
+	if (ret)
+		goto error;
 
-	/*
-	 * blocksize on this device should now be set to the ADFS log2secsize
-	 */
-
-	asb->s_map = adfs_read_map(sb, dr);
-	if (IS_ERR(asb->s_map)) {
-		ret =  PTR_ERR(asb->s_map);
-		goto error_free_bh;
-	}
-
-	brelse(bh);
-
-	/*
-	 * set up enough so that we can read an inode
-	 */
+	/* set up enough so that we can read an inode */
 	sb->s_op = &adfs_sops;
 
 	dr = adfs_map_discrecord(asb->s_map);
@@ -417,13 +431,6 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent)
 	}
 	return 0;
 
-error_badfs:
-	if (!silent)
-		adfs_msg(sb, KERN_ERR,
-			 "error: can't find an ADFS filesystem on dev %s.",
-			 sb->s_id);
-error_free_bh:
-	brelse(bh);
 error:
 	sb->s_fs_info = NULL;
 	kfree(asb);
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 39/41] fs/adfs: super: add support for E and E+ floppy image formats
  2019-12-09 11:07 [PATCH 00/41] fs/adfs updates for 5.6 Russell King - ARM Linux admin
                   ` (37 preceding siblings ...)
  2019-12-09 11:11 ` [PATCH 38/41] fs/adfs: super: extract filesystem block probe Russell King
@ 2019-12-09 11:11 ` Russell King
  2019-12-09 11:11 ` [PATCH 40/41] fs/adfs: mostly divorse inode number from indirect disc address Russell King
  2019-12-09 11:11 ` [PATCH 41/41] Documentation: update adfs filesystem documentation Russell King
  40 siblings, 0 replies; 47+ messages in thread
From: Russell King @ 2019-12-09 11:11 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel

Add support for ADFS E and E+ floppy image formats, which, unlike their
hard disk variants, do not have a filesystem boot block - they have a
single map zone, with the map fragment stored at sector 0.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
 fs/adfs/super.c | 18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/fs/adfs/super.c b/fs/adfs/super.c
index 4c06b2d5a861..a3cc8ecb50da 100644
--- a/fs/adfs/super.c
+++ b/fs/adfs/super.c
@@ -347,6 +347,20 @@ static int adfs_validate_bblk(struct super_block *sb, struct buffer_head *bh,
 	return 0;
 }
 
+static int adfs_validate_dr0(struct super_block *sb, struct buffer_head *bh,
+			      struct adfs_discrecord **drp)
+{
+	struct adfs_discrecord *dr;
+
+	/* Do some sanity checks on the ADFS disc record */
+	dr = (struct adfs_discrecord *)(bh->b_data + 4);
+	if (adfs_checkdiscrecord(dr) || dr->nzones_high || dr->nzones != 1)
+		return -EILSEQ;
+
+	*drp = dr;
+	return 0;
+}
+
 static int adfs_fill_super(struct super_block *sb, void *data, int silent)
 {
 	struct adfs_discrecord *dr;
@@ -376,7 +390,9 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent)
 		goto error;
 
 	/* Try to probe the filesystem boot block */
-	ret = adfs_probe(sb, ADFS_DISCRECORD, silent, adfs_validate_bblk);
+	ret = adfs_probe(sb, ADFS_DISCRECORD, 1, adfs_validate_bblk);
+	if (ret == -EILSEQ)
+		ret = adfs_probe(sb, 0, silent, adfs_validate_dr0);
 	if (ret == -EILSEQ) {
 		if (!silent)
 			adfs_msg(sb, KERN_ERR,
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 40/41] fs/adfs: mostly divorse inode number from indirect disc address
  2019-12-09 11:07 [PATCH 00/41] fs/adfs updates for 5.6 Russell King - ARM Linux admin
                   ` (38 preceding siblings ...)
  2019-12-09 11:11 ` [PATCH 39/41] fs/adfs: super: add support for E and E+ floppy image formats Russell King
@ 2019-12-09 11:11 ` Russell King
  2019-12-09 11:11 ` [PATCH 41/41] Documentation: update adfs filesystem documentation Russell King
  40 siblings, 0 replies; 47+ messages in thread
From: Russell King @ 2019-12-09 11:11 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel

Avoid using the inode number as the indirect disc address, even though
these currently have the same value.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
 fs/adfs/adfs.h  | 1 +
 fs/adfs/dir.c   | 4 ++--
 fs/adfs/inode.c | 6 ++++--
 3 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/fs/adfs/adfs.h b/fs/adfs/adfs.h
index c05555252fec..699c4fa8b78b 100644
--- a/fs/adfs/adfs.h
+++ b/fs/adfs/adfs.h
@@ -32,6 +32,7 @@ static inline u16 adfs_filetype(u32 loadaddr)
 struct adfs_inode_info {
 	loff_t		mmu_private;
 	__u32		parent_id;	/* parent indirect disc address	*/
+	__u32		indaddr;	/* object indirect disc address	*/
 	__u32		loadaddr;	/* RISC OS load address		*/
 	__u32		execaddr;	/* RISC OS exec address		*/
 	unsigned int	attr;		/* RISC OS permissions		*/
diff --git a/fs/adfs/dir.c b/fs/adfs/dir.c
index dd940f17767d..77fbd196008f 100644
--- a/fs/adfs/dir.c
+++ b/fs/adfs/dir.c
@@ -158,7 +158,7 @@ static int adfs_dir_read_inode(struct super_block *sb, struct inode *inode,
 {
 	int ret;
 
-	ret = adfs_dir_read(sb, inode->i_ino, inode->i_size, dir);
+	ret = adfs_dir_read(sb, ADFS_I(inode)->indaddr, inode->i_size, dir);
 	if (ret)
 		return ret;
 
@@ -372,7 +372,7 @@ static int adfs_dir_lookup_byname(struct inode *inode, const struct qstr *qstr,
 			break;
 		}
 	}
-	obj->parent_id = inode->i_ino;
+	obj->parent_id = ADFS_I(inode)->indaddr;
 
 unlock_relse:
 	up_read(&adfs_dir_rwsem);
diff --git a/fs/adfs/inode.c b/fs/adfs/inode.c
index 212a56fc7911..32620f4a7623 100644
--- a/fs/adfs/inode.c
+++ b/fs/adfs/inode.c
@@ -20,7 +20,8 @@ adfs_get_block(struct inode *inode, sector_t block, struct buffer_head *bh,
 		if (block >= inode->i_blocks)
 			goto abort_toobig;
 
-		block = __adfs_block_map(inode->i_sb, inode->i_ino, block);
+		block = __adfs_block_map(inode->i_sb, ADFS_I(inode)->indaddr,
+					 block);
 		if (block)
 			map_bh(bh, inode->i_sb, block);
 		return 0;
@@ -259,6 +260,7 @@ adfs_iget(struct super_block *sb, struct object_info *obj)
 	 * for cross-directory renames.
 	 */
 	ADFS_I(inode)->parent_id = obj->parent_id;
+	ADFS_I(inode)->indaddr   = obj->indaddr;
 	ADFS_I(inode)->loadaddr  = obj->loadaddr;
 	ADFS_I(inode)->execaddr  = obj->execaddr;
 	ADFS_I(inode)->attr      = obj->attr;
@@ -353,7 +355,7 @@ int adfs_write_inode(struct inode *inode, struct writeback_control *wbc)
 	struct object_info obj;
 	int ret;
 
-	obj.indaddr	= inode->i_ino;
+	obj.indaddr	= ADFS_I(inode)->indaddr;
 	obj.name_len	= 0;
 	obj.parent_id	= ADFS_I(inode)->parent_id;
 	obj.loadaddr	= ADFS_I(inode)->loadaddr;
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 41/41] Documentation: update adfs filesystem documentation
  2019-12-09 11:07 [PATCH 00/41] fs/adfs updates for 5.6 Russell King - ARM Linux admin
                   ` (39 preceding siblings ...)
  2019-12-09 11:11 ` [PATCH 40/41] fs/adfs: mostly divorse inode number from indirect disc address Russell King
@ 2019-12-09 11:11 ` Russell King
  40 siblings, 0 replies; 47+ messages in thread
From: Russell King @ 2019-12-09 11:11 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel, Jonathan Corbet, linux-doc

Add an introduction to adfs to its documentation detailing which formats
are supported by the module.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
 Documentation/filesystems/adfs.txt | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/Documentation/filesystems/adfs.txt b/Documentation/filesystems/adfs.txt
index 5949766353f7..0baa8e8c1fc1 100644
--- a/Documentation/filesystems/adfs.txt
+++ b/Documentation/filesystems/adfs.txt
@@ -1,3 +1,27 @@
+Filesystems supported by ADFS
+-----------------------------
+
+The ADFS module supports the following Filecore formats which have:
+
+- new maps
+- new directories or big directories
+
+In terms of the named formats, this means we support:
+
+- E and E+, with or without boot block
+- F and F+
+
+We fully support reading files from these filesystems, and writing to
+existing files within their existing allocation.  Essentially, we do
+not support changing any of the filesystem metadata.
+
+This is intended to support loopback mounted Linux native filesystems
+on a RISC OS Filecore filesystem, but will allow the data within files
+to be changed.
+
+If write support (ADFS_FS_RW) is configured, we allow rudimentary
+directory updates, specifically updating the access mode and timestamp.
+
 Mount options for ADFS
 ----------------------
 
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* Re: [PATCH 01/41] fs/adfs: inode: update timestamps to centisecond precision
  2019-12-09 11:08 ` [PATCH 01/41] fs/adfs: inode: update timestamps to centisecond precision Russell King
@ 2019-12-09 13:54   ` Vyacheslav Dubeyko
  2019-12-09 14:03     ` Russell King - ARM Linux admin
  0 siblings, 1 reply; 47+ messages in thread
From: Vyacheslav Dubeyko @ 2019-12-09 13:54 UTC (permalink / raw)
  To: Russell King, Al Viro; +Cc: linux-fsdevel

On Mon, 2019-12-09 at 11:08 +0000, Russell King wrote:
> Despite ADFS timestamps having centi-second granularity, and Linux
> gaining fine-grained timestamp support in v2.5.48, fs/adfs was never
> updated.
> 
> Update fs/adfs to centi-second support, and ensure that the inode
> ctime
> always reflects what is written in underlying media.
> 
> Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
> ---
>  fs/adfs/inode.c | 40 ++++++++++++++++++++--------------------
>  fs/adfs/super.c |  2 ++
>  2 files changed, 22 insertions(+), 20 deletions(-)
> 
> diff --git a/fs/adfs/inode.c b/fs/adfs/inode.c
> index 124de75413a5..18a1d478669b 100644
> --- a/fs/adfs/inode.c
> +++ b/fs/adfs/inode.c
> @@ -158,6 +158,8 @@ adfs_mode2atts(struct super_block *sb, struct
> inode *inode)
>  	return attr;
>  }
>  
> +static const s64 nsec_unix_epoch_diff_risc_os_epoch =
> 2208988800000000000LL;
> +
>  /*
>   * Convert an ADFS time to Unix time.  ADFS has a 40-bit centi-
> second time
>   * referenced to 1 Jan 1900 (til 2248) so we need to discard
> 2208988800 seconds
> @@ -170,8 +172,6 @@ adfs_adfs2unix_time(struct timespec64 *tv, struct
> inode *inode)
>  	/* 01 Jan 1970 00:00:00 (Unix epoch) as nanoseconds since
>  	 * 01 Jan 1900 00:00:00 (RISC OS epoch)
>  	 */
> -	static const s64 nsec_unix_epoch_diff_risc_os_epoch =
> -							220898880000000
> 0000LL;
>  	s64 nsec;
>  
>  	if (!adfs_inode_is_stamped(inode))
> @@ -204,24 +204,23 @@ adfs_adfs2unix_time(struct timespec64 *tv,
> struct inode *inode)
>  	return;
>  }
>  
> -/*
> - * Convert an Unix time to ADFS time.  We only do this if the entry
> has a
> - * time/date stamp already.
> - */
> -static void
> -adfs_unix2adfs_time(struct inode *inode, unsigned int secs)
> +/* Convert an Unix time to ADFS time for an entry that is already
> stamped. */
> +static void adfs_unix2adfs_time(struct inode *inode,
> +				const struct timespec64 *ts)
>  {
> -	unsigned int high, low;
> +	s64 cs, nsec = timespec64_to_ns(ts);
>  
> -	if (adfs_inode_is_stamped(inode)) {
> -		/* convert 32-bit seconds to 40-bit centi-seconds */
> -		low  = (secs & 255) * 100;
> -		high = (secs / 256) * 100 + (low >> 8) + 0x336e996a;
> +	/* convert from Unix to RISC OS epoch */
> +	nsec += nsec_unix_epoch_diff_risc_os_epoch;
>  
> -		ADFS_I(inode)->loadaddr = (high >> 24) |
> -				(ADFS_I(inode)->loadaddr & ~0xff);
> -		ADFS_I(inode)->execaddr = (low & 255) | (high << 8);
> -	}
> +	/* convert from nanoseconds to centiseconds */
> +	cs = div_s64(nsec, 10000000);
> +
> +	cs = clamp_t(s64, cs, 0, 0xffffffffff);
> +
> +	ADFS_I(inode)->loadaddr &= ~0xff;
> +	ADFS_I(inode)->loadaddr |= (cs >> 32) & 0xff;
> +	ADFS_I(inode)->execaddr = cs;
>  }
>  
>  /*
> @@ -315,10 +314,11 @@ adfs_notify_change(struct dentry *dentry,
> struct iattr *attr)
>  	if (ia_valid & ATTR_SIZE)
>  		truncate_setsize(inode, attr->ia_size);
>  
> -	if (ia_valid & ATTR_MTIME) {
> -		inode->i_mtime = attr->ia_mtime;
> -		adfs_unix2adfs_time(inode, attr->ia_mtime.tv_sec);
> +	if (ia_valid & ATTR_MTIME && adfs_inode_is_stamped(inode)) {
> +		adfs_unix2adfs_time(inode, &attr->ia_mtime);
> +		adfs_adfs2unix_time(&inode->i_mtime, inode);
>  	}
> +
>  	/*
>  	 * FIXME: should we make these == to i_mtime since we don't
>  	 * have the ability to represent them in our filesystem?
> diff --git a/fs/adfs/super.c b/fs/adfs/super.c
> index 65b04ebb51c3..e0eea9adb4e6 100644
> --- a/fs/adfs/super.c
> +++ b/fs/adfs/super.c
> @@ -391,7 +391,9 @@ static int adfs_fill_super(struct super_block
> *sb, void *data, int silent)
>  	asb = kzalloc(sizeof(*asb), GFP_KERNEL);
>  	if (!asb)
>  		return -ENOMEM;
> +
>  	sb->s_fs_info = asb;
> +	sb->s_time_gran = 10000000;

I believe it's not easy to follow what this granularity means. Maybe,
it makes sense to introduce some constant and to add some comment?

Thanks,
Viacheslav Dubeyko.

>  
>  	/* set default options */
>  	asb->s_uid = GLOBAL_ROOT_UID;


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 01/41] fs/adfs: inode: update timestamps to centisecond precision
  2019-12-09 13:54   ` Vyacheslav Dubeyko
@ 2019-12-09 14:03     ` Russell King - ARM Linux admin
  2019-12-09 14:34       ` Vyacheslav Dubeyko
  0 siblings, 1 reply; 47+ messages in thread
From: Russell King - ARM Linux admin @ 2019-12-09 14:03 UTC (permalink / raw)
  To: Vyacheslav Dubeyko; +Cc: Al Viro, linux-fsdevel

On Mon, Dec 09, 2019 at 04:54:55PM +0300, Vyacheslav Dubeyko wrote:
> On Mon, 2019-12-09 at 11:08 +0000, Russell King wrote:
> > Despite ADFS timestamps having centi-second granularity, and Linux
> > gaining fine-grained timestamp support in v2.5.48, fs/adfs was never
> > updated.
> > 
> > Update fs/adfs to centi-second support, and ensure that the inode
> > ctime
> > always reflects what is written in underlying media.
> > 
> > Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
> > ---
> >  fs/adfs/inode.c | 40 ++++++++++++++++++++--------------------
> >  fs/adfs/super.c |  2 ++
> >  2 files changed, 22 insertions(+), 20 deletions(-)
> > 
> > diff --git a/fs/adfs/inode.c b/fs/adfs/inode.c
> > index 124de75413a5..18a1d478669b 100644
> > --- a/fs/adfs/inode.c
> > +++ b/fs/adfs/inode.c
> > @@ -158,6 +158,8 @@ adfs_mode2atts(struct super_block *sb, struct
> > inode *inode)
> >  	return attr;
> >  }
> >  
> > +static const s64 nsec_unix_epoch_diff_risc_os_epoch =
> > 2208988800000000000LL;
> > +
> >  /*
> >   * Convert an ADFS time to Unix time.  ADFS has a 40-bit centi-
> > second time
> >   * referenced to 1 Jan 1900 (til 2248) so we need to discard
> > 2208988800 seconds
> > @@ -170,8 +172,6 @@ adfs_adfs2unix_time(struct timespec64 *tv, struct
> > inode *inode)
> >  	/* 01 Jan 1970 00:00:00 (Unix epoch) as nanoseconds since
> >  	 * 01 Jan 1900 00:00:00 (RISC OS epoch)
> >  	 */
> > -	static const s64 nsec_unix_epoch_diff_risc_os_epoch =
> > -							220898880000000
> > 0000LL;
> >  	s64 nsec;
> >  
> >  	if (!adfs_inode_is_stamped(inode))
> > @@ -204,24 +204,23 @@ adfs_adfs2unix_time(struct timespec64 *tv,
> > struct inode *inode)
> >  	return;
> >  }
> >  
> > -/*
> > - * Convert an Unix time to ADFS time.  We only do this if the entry
> > has a
> > - * time/date stamp already.
> > - */
> > -static void
> > -adfs_unix2adfs_time(struct inode *inode, unsigned int secs)
> > +/* Convert an Unix time to ADFS time for an entry that is already
> > stamped. */
> > +static void adfs_unix2adfs_time(struct inode *inode,
> > +				const struct timespec64 *ts)
> >  {
> > -	unsigned int high, low;
> > +	s64 cs, nsec = timespec64_to_ns(ts);
> >  
> > -	if (adfs_inode_is_stamped(inode)) {
> > -		/* convert 32-bit seconds to 40-bit centi-seconds */
> > -		low  = (secs & 255) * 100;
> > -		high = (secs / 256) * 100 + (low >> 8) + 0x336e996a;
> > +	/* convert from Unix to RISC OS epoch */
> > +	nsec += nsec_unix_epoch_diff_risc_os_epoch;
> >  
> > -		ADFS_I(inode)->loadaddr = (high >> 24) |
> > -				(ADFS_I(inode)->loadaddr & ~0xff);
> > -		ADFS_I(inode)->execaddr = (low & 255) | (high << 8);
> > -	}
> > +	/* convert from nanoseconds to centiseconds */
> > +	cs = div_s64(nsec, 10000000);
> > +
> > +	cs = clamp_t(s64, cs, 0, 0xffffffffff);
> > +
> > +	ADFS_I(inode)->loadaddr &= ~0xff;
> > +	ADFS_I(inode)->loadaddr |= (cs >> 32) & 0xff;
> > +	ADFS_I(inode)->execaddr = cs;
> >  }
> >  
> >  /*
> > @@ -315,10 +314,11 @@ adfs_notify_change(struct dentry *dentry,
> > struct iattr *attr)
> >  	if (ia_valid & ATTR_SIZE)
> >  		truncate_setsize(inode, attr->ia_size);
> >  
> > -	if (ia_valid & ATTR_MTIME) {
> > -		inode->i_mtime = attr->ia_mtime;
> > -		adfs_unix2adfs_time(inode, attr->ia_mtime.tv_sec);
> > +	if (ia_valid & ATTR_MTIME && adfs_inode_is_stamped(inode)) {
> > +		adfs_unix2adfs_time(inode, &attr->ia_mtime);
> > +		adfs_adfs2unix_time(&inode->i_mtime, inode);
> >  	}
> > +
> >  	/*
> >  	 * FIXME: should we make these == to i_mtime since we don't
> >  	 * have the ability to represent them in our filesystem?
> > diff --git a/fs/adfs/super.c b/fs/adfs/super.c
> > index 65b04ebb51c3..e0eea9adb4e6 100644
> > --- a/fs/adfs/super.c
> > +++ b/fs/adfs/super.c
> > @@ -391,7 +391,9 @@ static int adfs_fill_super(struct super_block
> > *sb, void *data, int silent)
> >  	asb = kzalloc(sizeof(*asb), GFP_KERNEL);
> >  	if (!asb)
> >  		return -ENOMEM;
> > +
> >  	sb->s_fs_info = asb;
> > +	sb->s_time_gran = 10000000;
> 
> I believe it's not easy to follow what this granularity means. Maybe,
> it makes sense to introduce some constant and to add some comment?

Or simply name it "s_time_gran_ns" so the units are in the name.

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 12.1Mbps down 622kbps up
According to speedtest.net: 11.9Mbps down 500kbps up

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 01/41] fs/adfs: inode: update timestamps to centisecond precision
  2019-12-09 14:03     ` Russell King - ARM Linux admin
@ 2019-12-09 14:34       ` Vyacheslav Dubeyko
  2019-12-09 14:40         ` Russell King - ARM Linux admin
  0 siblings, 1 reply; 47+ messages in thread
From: Vyacheslav Dubeyko @ 2019-12-09 14:34 UTC (permalink / raw)
  To: Russell King - ARM Linux admin; +Cc: Al Viro, linux-fsdevel

On Mon, 2019-12-09 at 14:03 +0000, Russell King - ARM Linux admin
wrote:
> > > 
> On Mon, Dec 09, 2019 at 04:54:55PM +0300, Vyacheslav Dubeyko wrote:
> > On Mon, 2019-12-09 at 11:08 +0000, Russell King wrote:

<snipped>

> > >  	sb->s_fs_info = asb;
> > > +	sb->s_time_gran = 10000000;
> > 
> > I believe it's not easy to follow what this granularity means.
> > Maybe,
> > it makes sense to introduce some constant and to add some comment?
> 
> Or simply name it "s_time_gran_ns" so the units are in the name.
> 

Sounds good. :) But why namely 10000000?

Thanks,
Viacheslav Dubeyko.



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 01/41] fs/adfs: inode: update timestamps to centisecond precision
  2019-12-09 14:34       ` Vyacheslav Dubeyko
@ 2019-12-09 14:40         ` Russell King - ARM Linux admin
  2019-12-09 17:15           ` Matthew Wilcox
  0 siblings, 1 reply; 47+ messages in thread
From: Russell King - ARM Linux admin @ 2019-12-09 14:40 UTC (permalink / raw)
  To: Vyacheslav Dubeyko; +Cc: Al Viro, linux-fsdevel

On Mon, Dec 09, 2019 at 05:34:05PM +0300, Vyacheslav Dubeyko wrote:
> On Mon, 2019-12-09 at 14:03 +0000, Russell King - ARM Linux admin
> wrote:
> > > > 
> > On Mon, Dec 09, 2019 at 04:54:55PM +0300, Vyacheslav Dubeyko wrote:
> > > On Mon, 2019-12-09 at 11:08 +0000, Russell King wrote:
> 
> <snipped>
> 
> > > >  	sb->s_fs_info = asb;
> > > > +	sb->s_time_gran = 10000000;
> > > 
> > > I believe it's not easy to follow what this granularity means.
> > > Maybe,
> > > it makes sense to introduce some constant and to add some comment?
> > 
> > Or simply name it "s_time_gran_ns" so the units are in the name.
> > 
> 
> Sounds good. :) But why namely 10000000?

I don't know what you mean.

If you're asking, why "10000000", isn't it obvious if you read the
commit message?  adfs has "centi-second" granularity. s_time_gran
is in nanoseconds. There are 10000000 nanoseconds in a centisecond.

What do you expect?

#define ADFS_TIME_GRAN 10000000

	sb->s_time_gran = ADFS_TIME_GRAN;

?

How does that help - it just stupidly and needlessly obfuscates the
code.

The whole "use definitions for constants" is idiotic when a constant
is only used in one place - when it means you have to search through
more source code to find it's single definition. Sorry, I'm not
doing that and make readability *worse*.

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 12.1Mbps down 622kbps up
According to speedtest.net: 11.9Mbps down 500kbps up

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 01/41] fs/adfs: inode: update timestamps to centisecond precision
  2019-12-09 14:40         ` Russell King - ARM Linux admin
@ 2019-12-09 17:15           ` Matthew Wilcox
  0 siblings, 0 replies; 47+ messages in thread
From: Matthew Wilcox @ 2019-12-09 17:15 UTC (permalink / raw)
  To: Russell King - ARM Linux admin; +Cc: Vyacheslav Dubeyko, Al Viro, linux-fsdevel

On Mon, Dec 09, 2019 at 02:40:00PM +0000, Russell King - ARM Linux admin wrote:
> > Sounds good. :) But why namely 10000000?
> 
> I don't know what you mean.
> 
> If you're asking, why "10000000", isn't it obvious if you read the
> commit message?  adfs has "centi-second" granularity. s_time_gran
> is in nanoseconds. There are 10000000 nanoseconds in a centisecond.
> 
> What do you expect?
> 
> #define ADFS_TIME_GRAN 10000000
> 
> 	sb->s_time_gran = ADFS_TIME_GRAN;
> 
> ?
> 
> How does that help - it just stupidly and needlessly obfuscates the
> code.
> 
> The whole "use definitions for constants" is idiotic when a constant
> is only used in one place - when it means you have to search through
> more source code to find it's single definition. Sorry, I'm not
> doing that and make readability *worse*.

I'd find it more readable if you wrote it as 10 * 1000 * 1000.  Saves
trying to count zeroes.  I know C added the ability to spell that as
10'000'000, but I don't think all compiler versions support that yet.

Maybe this would be cleanest:

	sb->s_time_gran = NSEC_PER_SEC / 100;

This is definitely how not to do it:

include/acpi/actypes.h:#define ACPI_100NSEC_PER_SEC            10000000L


^ permalink raw reply	[flat|nested] 47+ messages in thread

end of thread, other threads:[~2019-12-09 17:16 UTC | newest]

Thread overview: 47+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-12-09 11:07 [PATCH 00/41] fs/adfs updates for 5.6 Russell King - ARM Linux admin
2019-12-09 11:08 ` [PATCH 01/41] fs/adfs: inode: update timestamps to centisecond precision Russell King
2019-12-09 13:54   ` Vyacheslav Dubeyko
2019-12-09 14:03     ` Russell King - ARM Linux admin
2019-12-09 14:34       ` Vyacheslav Dubeyko
2019-12-09 14:40         ` Russell King - ARM Linux admin
2019-12-09 17:15           ` Matthew Wilcox
2019-12-09 11:08 ` [PATCH 02/41] fs/adfs: inode: fix adfs_mode2atts() Russell King
2019-12-09 11:08 ` [PATCH 03/41] fs/adfs: map: move map reading and validation to map.c Russell King
2019-12-09 11:08 ` [PATCH 04/41] fs/adfs: map: rename adfs_map_free() to adfs_map_statfs() Russell King
2019-12-09 11:08 ` [PATCH 05/41] fs/adfs: map: break up adfs_read_map() Russell King
2019-12-09 11:08 ` [PATCH 06/41] fs/adfs: map: factor out map cleanup Russell King
2019-12-09 11:08 ` [PATCH 07/41] fs/adfs: map: incorporate map offsets into layout Russell King
2019-12-09 11:08 ` [PATCH 08/41] fs/adfs: map: use find_next_bit_le() rather than open coding it Russell King
2019-12-09 11:08 ` [PATCH 09/41] fs/adfs: map: move map-specific sb initialisation to map.c Russell King
2019-12-09 11:09 ` [PATCH 10/41] fs/adfs: map: fix map scanning Russell King
2019-12-09 11:09 ` [PATCH 11/41] fs/adfs: dir: rename bh_fplus to bhs Russell King
2019-12-09 11:09 ` [PATCH 12/41] fs/adfs: dir: add common dir object initialisation Russell King
2019-12-09 11:09 ` [PATCH 13/41] fs/adfs: dir: add common directory buffer release method Russell King
2019-12-09 11:09 ` [PATCH 14/41] fs/adfs: dir: add common directory sync method Russell King
2019-12-09 11:09 ` [PATCH 15/41] fs/adfs: dir: add generic copy functions Russell King
2019-12-09 11:09 ` [PATCH 16/41] fs/adfs: dir: add generic directory reading Russell King
2019-12-09 11:09 ` [PATCH 17/41] fs/adfs: dir: add helper to read directory using inode Russell King
2019-12-09 11:09 ` [PATCH 18/41] fs/adfs: dir: add helper to mark directory buffers dirty Russell King
2019-12-09 11:09 ` [PATCH 19/41] fs/adfs: dir: update directory locking Russell King
2019-12-09 11:09 ` [PATCH 20/41] fs/adfs: dir: modernise on-disk directory structures Russell King
2019-12-09 11:10 ` [PATCH 21/41] fs/adfs: dir: improve update failure handling Russell King
2019-12-09 11:10 ` [PATCH 22/41] fs/adfs: dir: improve compiler coverage in adfs_dir_update Russell King
2019-12-09 11:10 ` [PATCH 23/41] fs/adfs: dir: switch to iterate_shared method Russell King
2019-12-09 11:10 ` [PATCH 24/41] fs/adfs: dir: add more efficient iterate() per-format method Russell King
2019-12-09 11:10 ` [PATCH 25/41] fs/adfs: dir: use pointers to access directory head/tails Russell King
2019-12-09 11:10 ` [PATCH 26/41] fs/adfs: newdir: factor out directory format validation Russell King
2019-12-09 11:10 ` [PATCH 27/41] fs/adfs: newdir: improve directory validation Russell King
2019-12-09 11:10 ` [PATCH 28/41] fs/adfs: newdir: merge adfs_dir_read() into adfs_f_read() Russell King
2019-12-09 11:10 ` [PATCH 29/41] fs/adfs: newdir: clean up adfs_f_update() Russell King
2019-12-09 11:10 ` [PATCH 30/41] fs/adfs: newdir: split out directory commit from update Russell King
2019-12-09 11:10 ` [PATCH 31/41] fs/adfs: bigdir: factor out directory entry offset calculation Russell King
2019-12-09 11:10 ` [PATCH 32/41] fs/adfs: bigdir: extract directory validation Russell King
2019-12-09 11:11 ` [PATCH 33/41] fs/adfs: bigdir: directory validation strengthening Russell King
2019-12-09 11:11 ` [PATCH 34/41] fs/adfs: bigdir: calculate and validate directory checkbyte Russell King
2019-12-09 11:11 ` [PATCH 35/41] fs/adfs: bigdir: implement directory update support Russell King
2019-12-09 11:11 ` [PATCH 36/41] fs/adfs: super: fix inode dropping Russell King
2019-12-09 11:11 ` [PATCH 37/41] fs/adfs: dir: remove debug in adfs_dir_update() Russell King
2019-12-09 11:11 ` [PATCH 38/41] fs/adfs: super: extract filesystem block probe Russell King
2019-12-09 11:11 ` [PATCH 39/41] fs/adfs: super: add support for E and E+ floppy image formats Russell King
2019-12-09 11:11 ` [PATCH 40/41] fs/adfs: mostly divorse inode number from indirect disc address Russell King
2019-12-09 11:11 ` [PATCH 41/41] Documentation: update adfs filesystem documentation Russell King

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).