linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 01/12] fs/adfs: correct disc record structure
       [not found] <20190604111943.GA15281@rmk-PC.armlinux.org.uk>
@ 2019-06-04 13:49 ` Russell King
  2019-06-04 13:49 ` [PATCH 02/12] fs/adfs: add helper to get discrecord from map Russell King
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 12+ messages in thread
From: Russell King @ 2019-06-04 13:49 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel

Fill in some padding in the disc record structure, and add GCC
packed and aligned attributes to ensure that it is correctly
laid out.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
 include/uapi/linux/adfs_fs.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/include/uapi/linux/adfs_fs.h b/include/uapi/linux/adfs_fs.h
index 151d93e27ed4..f1a7d67a7323 100644
--- a/include/uapi/linux/adfs_fs.h
+++ b/include/uapi/linux/adfs_fs.h
@@ -29,17 +29,17 @@ struct adfs_discrecord {
     __u8  log2sharesize:4;
     __u8  unused40:4;
     __u8  big_flag:1;
-    __u8  unused41:1;
+    __u8  unused41:7;
     __u8  nzones_high;
+    __u8  reserved43;
     __le32 format_version;
     __le32 root_size;
     __u8  unused52[60 - 52];
-};
+} __attribute__((packed, aligned(4)));
 
 #define ADFS_DISCRECORD		(0xc00)
 #define ADFS_DR_OFFSET		(0x1c0)
 #define ADFS_DR_SIZE		 60
 #define ADFS_DR_SIZE_BITS	(ADFS_DR_SIZE << 3)
 
-
 #endif /* _UAPI_ADFS_FS_H */
-- 
2.7.4


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

* [PATCH 02/12] fs/adfs: add helper to get discrecord from map
       [not found] <20190604111943.GA15281@rmk-PC.armlinux.org.uk>
  2019-06-04 13:49 ` [PATCH 01/12] fs/adfs: correct disc record structure Russell King
@ 2019-06-04 13:49 ` Russell King
  2019-06-04 13:49 ` [PATCH 03/12] fs/adfs: add helper to get filesystem size Russell King
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 12+ messages in thread
From: Russell King @ 2019-06-04 13:49 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel

Add a helper to get the disc record from the map, rather than open
coding this in adfs_fill_super().

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

diff --git a/fs/adfs/adfs.h b/fs/adfs/adfs.h
index 804c6a77c5db..5a72a0ea03bd 100644
--- a/fs/adfs/adfs.h
+++ b/fs/adfs/adfs.h
@@ -1,4 +1,5 @@
 /* SPDX-License-Identifier: GPL-2.0 */
+#include <linux/buffer_head.h>
 #include <linux/fs.h>
 #include <linux/adfs_fs.h>
 
@@ -18,8 +19,6 @@
 
 #include "dir_f.h"
 
-struct buffer_head;
-
 /*
  * adfs file system inode data in memory
  */
@@ -195,3 +194,10 @@ __adfs_block_map(struct super_block *sb, unsigned int object_id,
 
 	return adfs_map_lookup(sb, object_id >> 8, block);
 }
+
+/* Return the disc record from the map */
+static inline
+struct adfs_discrecord *adfs_map_discrecord(struct adfs_discmap *dm)
+{
+	return (void *)(dm[0].dm_bh->b_data + 4);
+}
diff --git a/fs/adfs/dir_f.c b/fs/adfs/dir_f.c
index 033884541a63..811f36aaa700 100644
--- a/fs/adfs/dir_f.c
+++ b/fs/adfs/dir_f.c
@@ -9,7 +9,6 @@
  *
  *  E and F format directory handling
  */
-#include <linux/buffer_head.h>
 #include "adfs.h"
 #include "dir_f.h"
 
diff --git a/fs/adfs/dir_fplus.c b/fs/adfs/dir_fplus.c
index 97b9f28f459b..12ab34dad815 100644
--- a/fs/adfs/dir_fplus.c
+++ b/fs/adfs/dir_fplus.c
@@ -7,7 +7,6 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-#include <linux/buffer_head.h>
 #include <linux/slab.h>
 #include "adfs.h"
 #include "dir_fplus.h"
diff --git a/fs/adfs/map.c b/fs/adfs/map.c
index 6935f05202ac..5f2d9d775305 100644
--- a/fs/adfs/map.c
+++ b/fs/adfs/map.c
@@ -7,7 +7,6 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-#include <linux/buffer_head.h>
 #include <asm/unaligned.h>
 #include "adfs.h"
 
diff --git a/fs/adfs/super.c b/fs/adfs/super.c
index 7e099a7a4eb1..75000165f4d1 100644
--- a/fs/adfs/super.c
+++ b/fs/adfs/super.c
@@ -9,7 +9,6 @@
  */
 #include <linux/module.h>
 #include <linux/init.h>
-#include <linux/buffer_head.h>
 #include <linux/parser.h>
 #include <linux/mount.h>
 #include <linux/seq_file.h>
@@ -469,7 +468,7 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent)
 	 */
 	sb->s_op = &adfs_sops;
 
-	dr = (struct adfs_discrecord *)(asb->s_map[0].dm_bh->b_data + 4);
+	dr = adfs_map_discrecord(asb->s_map);
 
 	root_obj.parent_id = root_obj.file_id = le32_to_cpu(dr->root);
 	root_obj.name_len  = 0;
-- 
2.7.4


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

* [PATCH 03/12] fs/adfs: add helper to get filesystem size
       [not found] <20190604111943.GA15281@rmk-PC.armlinux.org.uk>
  2019-06-04 13:49 ` [PATCH 01/12] fs/adfs: correct disc record structure Russell King
  2019-06-04 13:49 ` [PATCH 02/12] fs/adfs: add helper to get discrecord from map Russell King
@ 2019-06-04 13:49 ` Russell King
  2019-06-04 13:49 ` [PATCH 04/12] fs/adfs: use format_version from disc_record Russell King
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 12+ messages in thread
From: Russell King @ 2019-06-04 13:49 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel

Add a helper to get the filesystem size from the disc record and
eliminate the "s_size" member of the adfs superblock structure.

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

diff --git a/fs/adfs/adfs.h b/fs/adfs/adfs.h
index 5a72a0ea03bd..ab13b5dd34a3 100644
--- a/fs/adfs/adfs.h
+++ b/fs/adfs/adfs.h
@@ -58,7 +58,6 @@ struct adfs_sb_info {
 	__u32		s_ids_per_zone;	/* max. no ids in one zone */
 	__u32		s_idlen;	/* length of ID in map */
 	__u32		s_map_size;	/* sector size of a map	*/
-	unsigned long	s_size;		/* total size (in blocks) of this fs */
 	signed int	s_map2blk;	/* shift left by this for map->sector*/
 	unsigned int	s_log2sharesize;/* log2 share size */
 	__le32		s_version;	/* disc format version */
@@ -201,3 +200,9 @@ struct adfs_discrecord *adfs_map_discrecord(struct adfs_discmap *dm)
 {
 	return (void *)(dm[0].dm_bh->b_data + 4);
 }
+
+static inline u64 adfs_disc_size(const struct adfs_discrecord *dr)
+{
+	return (u64)le32_to_cpu(dr->disc_size_high) << 32 |
+		    le32_to_cpu(dr->disc_size);
+}
diff --git a/fs/adfs/super.c b/fs/adfs/super.c
index 75000165f4d1..90b9cbcdb4db 100644
--- a/fs/adfs/super.c
+++ b/fs/adfs/super.c
@@ -220,12 +220,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);
 
 	buf->f_type    = ADFS_SUPER_MAGIC;
 	buf->f_namelen = sbi->s_namelen;
 	buf->f_bsize   = sb->s_blocksize;
-	buf->f_blocks  = sbi->s_size;
+	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);
@@ -335,8 +336,7 @@ static struct adfs_discmap *adfs_read_map(struct super_block *sb, struct adfs_di
 	i = zone - 1;
 	dm[0].dm_startblk = 0;
 	dm[0].dm_startbit = ADFS_DR_SIZE_BITS;
-	dm[i].dm_endbit   = (le32_to_cpu(dr->disc_size_high) << (32 - dr->log2bpmb)) +
-			    (le32_to_cpu(dr->disc_size) >> dr->log2bpmb) +
+	dm[i].dm_endbit   = (adfs_disc_size(dr) >> dr->log2bpmb) +
 			    (ADFS_DR_SIZE_BITS - i * zone_size);
 
 	if (adfs_checkmap(sb, dm))
@@ -352,16 +352,6 @@ static struct adfs_discmap *adfs_read_map(struct super_block *sb, struct adfs_di
 	return ERR_PTR(-EIO);
 }
 
-static inline unsigned long adfs_discsize(struct adfs_discrecord *dr, int block_bits)
-{
-	unsigned long discsize;
-
-	discsize  = le32_to_cpu(dr->disc_size_high) << (32 - block_bits);
-	discsize |= le32_to_cpu(dr->disc_size) >> block_bits;
-
-	return discsize;
-}
-
 static int adfs_fill_super(struct super_block *sb, void *data, int silent)
 {
 	struct adfs_discrecord *dr;
@@ -451,7 +441,6 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent)
 	asb->s_idlen		= dr->idlen;
 	asb->s_map_size		= dr->nzones | (dr->nzones_high << 8);
 	asb->s_map2blk		= dr->log2bpmb - dr->log2secsize;
-	asb->s_size    		= adfs_discsize(dr, sb->s_blocksize_bits);
 	asb->s_version 		= dr->format_version;
 	asb->s_log2sharesize	= dr->log2sharesize;
 
-- 
2.7.4


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

* [PATCH 04/12] fs/adfs: use format_version from disc_record
       [not found] <20190604111943.GA15281@rmk-PC.armlinux.org.uk>
                   ` (2 preceding siblings ...)
  2019-06-04 13:49 ` [PATCH 03/12] fs/adfs: add helper to get filesystem size Russell King
@ 2019-06-04 13:49 ` Russell King
  2019-06-04 13:49 ` [PATCH 05/12] fs/adfs: use %pV for error messages Russell King
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 12+ messages in thread
From: Russell King @ 2019-06-04 13:49 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel

We only use the format version in one place during filesystem mount, so
it is pointless storing it in the superblock structure.  Also, we should
be using the version from the disc record in the map rather than the
boot block.

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

diff --git a/fs/adfs/adfs.h b/fs/adfs/adfs.h
index ab13b5dd34a3..1c31861aa115 100644
--- a/fs/adfs/adfs.h
+++ b/fs/adfs/adfs.h
@@ -60,7 +60,6 @@ struct adfs_sb_info {
 	__u32		s_map_size;	/* sector size of a map	*/
 	signed int	s_map2blk;	/* shift left by this for map->sector*/
 	unsigned int	s_log2sharesize;/* log2 share size */
-	__le32		s_version;	/* disc format version */
 	unsigned int	s_namelen;	/* maximum number of characters in name	 */
 };
 
diff --git a/fs/adfs/super.c b/fs/adfs/super.c
index 90b9cbcdb4db..26b4b66df2c7 100644
--- a/fs/adfs/super.c
+++ b/fs/adfs/super.c
@@ -441,7 +441,6 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent)
 	asb->s_idlen		= dr->idlen;
 	asb->s_map_size		= dr->nzones | (dr->nzones_high << 8);
 	asb->s_map2blk		= dr->log2bpmb - dr->log2secsize;
-	asb->s_version 		= dr->format_version;
 	asb->s_log2sharesize	= dr->log2sharesize;
 
 	asb->s_map = adfs_read_map(sb, dr);
@@ -473,7 +472,7 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent)
 	 * If this is a F+ disk with variable length directories,
 	 * get the root_size from the disc record.
 	 */
-	if (asb->s_version) {
+	if (dr->format_version) {
 		root_obj.size = le32_to_cpu(dr->root_size);
 		asb->s_dir     = &adfs_fplus_dir_ops;
 		asb->s_namelen = ADFS_FPLUS_NAME_LEN;
-- 
2.7.4


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

* [PATCH 05/12] fs/adfs: use %pV for error messages
       [not found] <20190604111943.GA15281@rmk-PC.armlinux.org.uk>
                   ` (3 preceding siblings ...)
  2019-06-04 13:49 ` [PATCH 04/12] fs/adfs: use format_version from disc_record Russell King
@ 2019-06-04 13:49 ` Russell King
  2019-06-04 13:49 ` [PATCH 06/12] fs/adfs: clean up error message printing Russell King
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 12+ messages in thread
From: Russell King @ 2019-06-04 13:49 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel

Rather than using vsnprintf() with a temporary buffer on the stack, use
%pV to print error messages.

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

diff --git a/fs/adfs/super.c b/fs/adfs/super.c
index 26b4b66df2c7..f35db5d64c17 100644
--- a/fs/adfs/super.c
+++ b/fs/adfs/super.c
@@ -24,16 +24,18 @@
 
 void __adfs_error(struct super_block *sb, const char *function, const char *fmt, ...)
 {
-	char error_buf[128];
+	struct va_format vaf;
 	va_list args;
 
 	va_start(args, fmt);
-	vsnprintf(error_buf, sizeof(error_buf), fmt, args);
-	va_end(args);
+	vaf.fmt = fmt;
+	vaf.va = &args;
 
-	printk(KERN_CRIT "ADFS-fs error (device %s)%s%s: %s\n",
+	printk(KERN_CRIT "ADFS-fs error (device %s)%s%s: %pV\n",
 		sb->s_id, function ? ": " : "",
-		function ? function : "", error_buf);
+		function ? function : "", &vaf);
+
+	va_end(args);
 }
 
 static int adfs_checkdiscrecord(struct adfs_discrecord *dr)
-- 
2.7.4


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

* [PATCH 06/12] fs/adfs: clean up error message printing
       [not found] <20190604111943.GA15281@rmk-PC.armlinux.org.uk>
                   ` (4 preceding siblings ...)
  2019-06-04 13:49 ` [PATCH 05/12] fs/adfs: use %pV for error messages Russell King
@ 2019-06-04 13:49 ` Russell King
  2019-06-04 13:49 ` [PATCH 07/12] fs/adfs: clean up indirect disc addresses and fragment IDs Russell King
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 12+ messages in thread
From: Russell King @ 2019-06-04 13:49 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel

Overhaul our message printing:

- provide a consistent way to print messages:
  - filesystem corruption should be reported via adfs_error()
  - everything else should use adfs_msg()
- clean up the error message printing when mounting a filesystem
- fix the messages printed by the big directory format code to only
  use adfs_error() when there is filesystem corruption, otherwise
  use adfs_msg().

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

diff --git a/fs/adfs/adfs.h b/fs/adfs/adfs.h
index 1c31861aa115..1e8865588a59 100644
--- a/fs/adfs/adfs.h
+++ b/fs/adfs/adfs.h
@@ -142,6 +142,7 @@ __printf(3, 4)
 void __adfs_error(struct super_block *sb, const char *function,
 		  const char *fmt, ...);
 #define adfs_error(sb, fmt...) __adfs_error(sb, __func__, fmt)
+void adfs_msg(struct super_block *sb, const char *pfx, const char *fmt, ...);
 
 /* super.c */
 
diff --git a/fs/adfs/dir_fplus.c b/fs/adfs/dir_fplus.c
index 12ab34dad815..02c54d85e77f 100644
--- a/fs/adfs/dir_fplus.c
+++ b/fs/adfs/dir_fplus.c
@@ -39,17 +39,15 @@ adfs_fplus_read(struct super_block *sb, unsigned int id, unsigned int sz, struct
 	h = (struct adfs_bigdirheader *)dir->bh_fplus[0]->b_data;
 	size = le32_to_cpu(h->bigdirsize);
 	if (size != sz) {
-		printk(KERN_WARNING "adfs: adfs_fplus_read:"
-					" directory header size %X\n"
-					" does not match directory size %X\n",
-					size, sz);
+		adfs_msg(sb, KERN_WARNING,
+			 "directory header size %X does not match directory size %X",
+			 size, sz);
 	}
 
 	if (h->bigdirversion[0] != 0 || h->bigdirversion[1] != 0 ||
 	    h->bigdirversion[2] != 0 || size & 2047 ||
 	    h->bigdirstartname != cpu_to_le32(BIGDIRSTARTNAME)) {
-		printk(KERN_WARNING "adfs: dir object %X has"
-					" malformed dir header\n", id);
+		adfs_error(sb, "dir %06x has malformed header", id);
 		goto out;
 	}
 
@@ -60,9 +58,10 @@ adfs_fplus_read(struct super_block *sb, unsigned int id, unsigned int sz, struct
 			kcalloc(size, sizeof(struct buffer_head *),
 				GFP_KERNEL);
 		if (!bh_fplus) {
+			adfs_msg(sb, KERN_ERR,
+				 "not enough memory for dir object %X (%d blocks)",
+				 id, size);
 			ret = -ENOMEM;
-			adfs_error(sb, "not enough memory for"
-					" dir object %X (%d blocks)", id, size);
 			goto out;
 		}
 		dir->bh_fplus = bh_fplus;
@@ -93,8 +92,7 @@ adfs_fplus_read(struct super_block *sb, unsigned int id, unsigned int sz, struct
 	if (t->bigdirendname != cpu_to_le32(BIGDIRENDNAME) ||
 	    t->bigdirendmasseq != h->startmasseq ||
 	    t->reserved[0] != 0 || t->reserved[1] != 0) {
-		printk(KERN_WARNING "adfs: dir object %X has "
-					"malformed dir end\n", id);
+		adfs_error(sb, "dir %06x has malformed tail", id);
 		goto out;
 	}
 
diff --git a/fs/adfs/super.c b/fs/adfs/super.c
index f35db5d64c17..6087d263cb4d 100644
--- a/fs/adfs/super.c
+++ b/fs/adfs/super.c
@@ -38,6 +38,18 @@ void __adfs_error(struct super_block *sb, const char *function, const char *fmt,
 	va_end(args);
 }
 
+void adfs_msg(struct super_block *sb, const char *pfx, const char *fmt, ...)
+{
+	struct va_format vaf;
+	va_list args;
+
+	va_start(args, fmt);
+	vaf.fmt = fmt;
+	vaf.va = &args;
+	printk("%sADFS-fs (%s): %pV\n", pfx, sb->s_id, &vaf);
+	va_end(args);
+}
+
 static int adfs_checkdiscrecord(struct adfs_discrecord *dr)
 {
 	int i;
@@ -203,8 +215,9 @@ static int parse_options(struct super_block *sb, char *options)
 			asb->s_ftsuffix = option;
 			break;
 		default:
-			printk("ADFS-fs: unrecognised mount option \"%s\" "
-					"or missing value\n", p);
+			adfs_msg(sb, KERN_ERR,
+				 "unrecognised mount option \"%s\" or missing value",
+				 p);
 			return -EINVAL;
 		}
 	}
@@ -383,7 +396,7 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent)
 
 	sb_set_blocksize(sb, BLOCK_SIZE);
 	if (!(bh = sb_bread(sb, ADFS_DISCRECORD / BLOCK_SIZE))) {
-		adfs_error(sb, "unable to read superblock");
+		adfs_msg(sb, KERN_ERR, "error: unable to read superblock");
 		ret = -EIO;
 		goto error;
 	}
@@ -391,11 +404,8 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent)
 	b_data = bh->b_data + (ADFS_DISCRECORD % BLOCK_SIZE);
 
 	if (adfs_checkbblk(b_data)) {
-		if (!silent)
-			printk("VFS: Can't find an adfs filesystem on dev "
-				"%s.\n", sb->s_id);
 		ret = -EINVAL;
-		goto error_free_bh;
+		goto error_badfs;
 	}
 
 	dr = (struct adfs_discrecord *)(b_data + ADFS_DR_OFFSET);
@@ -404,33 +414,31 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent)
 	 * Do some sanity checks on the ADFS disc record
 	 */
 	if (adfs_checkdiscrecord(dr)) {
-		if (!silent)
-			printk("VPS: Can't find an adfs filesystem on dev "
-				"%s.\n", sb->s_id);
 		ret = -EINVAL;
-		goto error_free_bh;
+		goto error_badfs;
 	}
 
 	brelse(bh);
 	if (sb_set_blocksize(sb, 1 << dr->log2secsize)) {
 		bh = sb_bread(sb, ADFS_DISCRECORD / sb->s_blocksize);
 		if (!bh) {
-			adfs_error(sb, "couldn't read superblock on "
-				"2nd try.");
+			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_error(sb, "disc record mismatch, very weird!");
+			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 {
 		if (!silent)
-			printk(KERN_ERR "VFS: Unsupported blocksize on dev "
-				"%s.\n", sb->s_id);
+			adfs_msg(sb, KERN_ERR,
+				 "error: unsupported blocksize");
 		ret = -EINVAL;
 		goto error;
 	}
@@ -503,6 +511,11 @@ 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:
-- 
2.7.4


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

* [PATCH 07/12] fs/adfs: clean up indirect disc addresses and fragment IDs
       [not found] <20190604111943.GA15281@rmk-PC.armlinux.org.uk>
                   ` (5 preceding siblings ...)
  2019-06-04 13:49 ` [PATCH 06/12] fs/adfs: clean up error message printing Russell King
@ 2019-06-04 13:49 ` Russell King
  2019-06-04 13:50 ` [PATCH 08/12] fs/adfs: super: correct superblock flags Russell King
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 12+ messages in thread
From: Russell King @ 2019-06-04 13:49 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel

We use a variety of different names for the indirect disc address of
the current object, use a variety of different types, and print it in
a variety of different ways. Bring some consistency to this by naming
it "indaddr", use u32 or __u32 as the type since it fits in 32-bits,
and always print it with %06x (with no leading hex prefix.)

When printing it was a directory identifer, use "dir %06x" otherwise
use "object %06x".

Do the same for fragment IDs and the parent indirect disc addresses.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
 fs/adfs/adfs.h      | 22 +++++++++++-----------
 fs/adfs/dir.c       |  9 +++++----
 fs/adfs/dir_f.c     | 37 ++++++++++++++++---------------------
 fs/adfs/dir_fplus.c |  2 +-
 fs/adfs/inode.c     |  4 ++--
 fs/adfs/map.c       | 14 +++++---------
 fs/adfs/super.c     |  2 +-
 7 files changed, 41 insertions(+), 49 deletions(-)

diff --git a/fs/adfs/adfs.h b/fs/adfs/adfs.h
index 1e8865588a59..9eb9bea1cef2 100644
--- a/fs/adfs/adfs.h
+++ b/fs/adfs/adfs.h
@@ -24,7 +24,7 @@
  */
 struct adfs_inode_info {
 	loff_t		mmu_private;
-	unsigned long	parent_id;	/* object id of parent		*/
+	__u32		parent_id;	/* parent indirect disc address	*/
 	__u32		loadaddr;	/* RISC OS load address		*/
 	__u32		execaddr;	/* RISC OS exec address		*/
 	unsigned int	filetype;	/* RISC OS file type		*/
@@ -86,7 +86,7 @@ struct adfs_dir {
 	struct buffer_head	**bh_fplus;
 
 	unsigned int		pos;
-	unsigned int		parent_id;
+	__u32			parent_id;
 
 	struct adfs_dirheader	dirhead;
 	union  adfs_dirtail	dirtail;
@@ -98,7 +98,7 @@ struct adfs_dir {
 #define ADFS_MAX_NAME_LEN	(256 + 4) /* +4 for ,xyz hex filetype suffix */
 struct object_info {
 	__u32		parent_id;		/* parent object id	*/
-	__u32		file_id;		/* object id		*/
+	__u32		indaddr;		/* indirect disc addr	*/
 	__u32		loadaddr;		/* load address		*/
 	__u32		execaddr;		/* execution address	*/
 	__u32		size;			/* size			*/
@@ -111,7 +111,8 @@ struct object_info {
 };
 
 struct adfs_dir_ops {
-	int	(*read)(struct super_block *sb, unsigned int id, unsigned int sz, struct adfs_dir *dir);
+	int	(*read)(struct super_block *sb, unsigned int indaddr,
+			unsigned int size, struct adfs_dir *dir);
 	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);
@@ -134,7 +135,7 @@ int adfs_write_inode(struct inode *inode, struct writeback_control *wbc);
 int adfs_notify_change(struct dentry *dentry, struct iattr *attr);
 
 /* map.c */
-extern int adfs_map_lookup(struct super_block *sb, unsigned int frag_id, unsigned int offset);
+int adfs_map_lookup(struct super_block *sb, u32 frag_id, unsigned int offset);
 extern unsigned int adfs_map_free(struct super_block *sb);
 
 /* Misc */
@@ -180,18 +181,17 @@ static inline __u32 signed_asl(__u32 val, signed int shift)
  *
  * The root directory ID should always be looked up in the map [3.4]
  */
-static inline int
-__adfs_block_map(struct super_block *sb, unsigned int object_id,
-		 unsigned int block)
+static inline int __adfs_block_map(struct super_block *sb, u32 indaddr,
+				   unsigned int block)
 {
-	if (object_id & 255) {
+	if (indaddr & 255) {
 		unsigned int off;
 
-		off = (object_id & 255) - 1;
+		off = (indaddr & 255) - 1;
 		block += off << ADFS_SB(sb)->s_log2sharesize;
 	}
 
-	return adfs_map_lookup(sb, object_id >> 8, block);
+	return adfs_map_lookup(sb, indaddr >> 8, block);
 }
 
 /* Return the disc record from the map */
diff --git a/fs/adfs/dir.c b/fs/adfs/dir.c
index fe39310c1a0a..01ffd47c7461 100644
--- a/fs/adfs/dir.c
+++ b/fs/adfs/dir.c
@@ -95,7 +95,7 @@ adfs_readdir(struct file *file, struct dir_context *ctx)
 		goto unlock_out;
 	while (ops->getnext(&dir, &obj) == 0) {
 		if (!dir_emit(ctx, obj.name, obj.name_len,
-			    obj.file_id, DT_UNKNOWN))
+			      obj.indaddr, DT_UNKNOWN))
 			break;
 		ctx->pos++;
 	}
@@ -116,8 +116,8 @@ adfs_dir_update(struct super_block *sb, struct object_info *obj, int wait)
 	const struct adfs_dir_ops *ops = ADFS_SB(sb)->s_dir;
 	struct adfs_dir dir;
 
-	printk(KERN_INFO "adfs_dir_update: object %06X in dir %06X\n",
-		 obj->file_id, obj->parent_id);
+	printk(KERN_INFO "adfs_dir_update: object %06x in dir %06x\n",
+		 obj->indaddr, obj->parent_id);
 
 	if (!ops->update) {
 		ret = -EINVAL;
@@ -181,7 +181,8 @@ static int adfs_dir_lookup_byname(struct inode *inode, const struct qstr *qstr,
 		goto out;
 
 	if (ADFS_I(inode)->parent_id != dir.parent_id) {
-		adfs_error(sb, "parent directory changed under me! (%lx but got %x)\n",
+		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;
diff --git a/fs/adfs/dir_f.c b/fs/adfs/dir_f.c
index 811f36aaa700..1eb82a4de655 100644
--- a/fs/adfs/dir_f.c
+++ b/fs/adfs/dir_f.c
@@ -120,12 +120,9 @@ adfs_dir_checkbyte(const struct adfs_dir *dir)
 	return (dircheck ^ (dircheck >> 8) ^ (dircheck >> 16) ^ (dircheck >> 24)) & 0xff;
 }
 
-/*
- * Read and check that a directory is valid
- */
-static int
-adfs_dir_read(struct super_block *sb, unsigned long object_id,
-	      unsigned int size, 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)
 {
 	const unsigned int blocksize_bits = sb->s_blocksize_bits;
 	int blk = 0;
@@ -145,10 +142,10 @@ adfs_dir_read(struct super_block *sb, unsigned long object_id,
 	for (blk = 0; blk < size; blk++) {
 		int phys;
 
-		phys = __adfs_block_map(sb, object_id, blk);
+		phys = __adfs_block_map(sb, indaddr, blk);
 		if (!phys) {
-			adfs_error(sb, "dir object %lX has a hole at offset %d",
-				   object_id, blk);
+			adfs_error(sb, "dir %06x has a hole at offset %d",
+				   indaddr, blk);
 			goto release_buffers;
 		}
 
@@ -176,8 +173,7 @@ adfs_dir_read(struct super_block *sb, unsigned long object_id,
 	return 0;
 
 bad_dir:
-	adfs_error(sb, "corrupted directory fragment %lX",
-		   object_id);
+	adfs_error(sb, "dir %06x is corrupted", indaddr);
 release_buffers:
 	for (blk -= 1; blk >= 0; blk -= 1)
 		brelse(dir->bh[blk]);
@@ -204,7 +200,7 @@ adfs_dir2obj(struct adfs_dir *dir, struct object_info *obj,
 	}
 
 	obj->name_len =	name_len;
-	obj->file_id  = adfs_readval(de->dirinddiscadd, 3);
+	obj->indaddr  = adfs_readval(de->dirinddiscadd, 3);
 	obj->loadaddr = adfs_readval(de->dirload, 4);
 	obj->execaddr = adfs_readval(de->direxec, 4);
 	obj->size     = adfs_readval(de->dirlen,  4);
@@ -219,7 +215,7 @@ adfs_dir2obj(struct adfs_dir *dir, struct object_info *obj,
 static inline void
 adfs_obj2dir(struct adfs_direntry *de, struct object_info *obj)
 {
-	adfs_writeval(de->dirinddiscadd, 3, obj->file_id);
+	adfs_writeval(de->dirinddiscadd, 3, obj->indaddr);
 	adfs_writeval(de->dirload, 4, obj->loadaddr);
 	adfs_writeval(de->direxec, 4, obj->execaddr);
 	adfs_writeval(de->dirlen,  4, obj->size);
@@ -305,8 +301,7 @@ __adfs_dir_put(struct adfs_dir *dir, int pos, struct object_info *obj)
  * the caller is responsible for holding the necessary
  * locks.
  */
-static int
-adfs_dir_find_entry(struct adfs_dir *dir, unsigned long object_id)
+static int adfs_dir_find_entry(struct adfs_dir *dir, u32 indaddr)
 {
 	int pos, ret;
 
@@ -318,7 +313,7 @@ adfs_dir_find_entry(struct adfs_dir *dir, unsigned long object_id)
 		if (!__adfs_dir_get(dir, pos, &obj))
 			break;
 
-		if (obj.file_id == object_id) {
+		if (obj.indaddr == indaddr) {
 			ret = pos;
 			break;
 		}
@@ -327,15 +322,15 @@ adfs_dir_find_entry(struct adfs_dir *dir, unsigned long object_id)
 	return ret;
 }
 
-static int
-adfs_f_read(struct super_block *sb, unsigned int id, unsigned int sz, struct adfs_dir *dir)
+static int adfs_f_read(struct super_block *sb, u32 indaddr, unsigned int size,
+		       struct adfs_dir *dir)
 {
 	int ret;
 
-	if (sz != ADFS_NEWDIR_SIZE)
+	if (size != ADFS_NEWDIR_SIZE)
 		return -EIO;
 
-	ret = adfs_dir_read(sb, id, sz, dir);
+	ret = adfs_dir_read(sb, indaddr, size, dir);
 	if (ret)
 		adfs_error(sb, "unable to read directory");
 	else
@@ -372,7 +367,7 @@ adfs_f_update(struct adfs_dir *dir, struct object_info *obj)
 	struct super_block *sb = dir->sb;
 	int ret, i;
 
-	ret = adfs_dir_find_entry(dir, obj->file_id);
+	ret = adfs_dir_find_entry(dir, obj->indaddr);
 	if (ret < 0) {
 		adfs_error(dir->sb, "unable to locate entry to update");
 		goto out;
diff --git a/fs/adfs/dir_fplus.c b/fs/adfs/dir_fplus.c
index 02c54d85e77f..973282fc4758 100644
--- a/fs/adfs/dir_fplus.c
+++ b/fs/adfs/dir_fplus.c
@@ -180,7 +180,7 @@ adfs_fplus_getnext(struct adfs_dir *dir, struct object_info *obj)
 	obj->loadaddr = le32_to_cpu(bde.bigdirload);
 	obj->execaddr = le32_to_cpu(bde.bigdirexec);
 	obj->size     = le32_to_cpu(bde.bigdirlen);
-	obj->file_id  = le32_to_cpu(bde.bigdirindaddr);
+	obj->indaddr  = le32_to_cpu(bde.bigdirindaddr);
 	obj->attr     = le32_to_cpu(bde.bigdirattr);
 	obj->name_len = le32_to_cpu(bde.bigdirobnamelen);
 
diff --git a/fs/adfs/inode.c b/fs/adfs/inode.c
index 66621e96f9af..5f5af660b02e 100644
--- a/fs/adfs/inode.c
+++ b/fs/adfs/inode.c
@@ -250,7 +250,7 @@ adfs_iget(struct super_block *sb, struct object_info *obj)
 
 	inode->i_uid	 = ADFS_SB(sb)->s_uid;
 	inode->i_gid	 = ADFS_SB(sb)->s_gid;
-	inode->i_ino	 = obj->file_id;
+	inode->i_ino	 = obj->indaddr;
 	inode->i_size	 = obj->size;
 	set_nlink(inode, 2);
 	inode->i_blocks	 = (inode->i_size + sb->s_blocksize - 1) >>
@@ -358,7 +358,7 @@ int adfs_write_inode(struct inode *inode, struct writeback_control *wbc)
 	struct object_info obj;
 	int ret;
 
-	obj.file_id	= inode->i_ino;
+	obj.indaddr	= inode->i_ino;
 	obj.name_len	= 0;
 	obj.parent_id	= ADFS_I(inode)->parent_id;
 	obj.loadaddr	= ADFS_I(inode)->loadaddr;
diff --git a/fs/adfs/map.c b/fs/adfs/map.c
index 5f2d9d775305..e8f70f7c384e 100644
--- a/fs/adfs/map.c
+++ b/fs/adfs/map.c
@@ -66,9 +66,8 @@ static DEFINE_RWLOCK(adfs_map_lock);
  * output of:
  *  gcc -D__KERNEL__ -O2 -I../../include -o - -S map.c
  */
-static int
-lookup_zone(const struct adfs_discmap *dm, const unsigned int idlen,
-	    const unsigned int frag_id, unsigned int *offset)
+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 u32 idmask = (1 << idlen) - 1;
@@ -187,9 +186,8 @@ scan_free_map(struct adfs_sb_info *asb, struct adfs_discmap *dm)
 	return 0;
 }
 
-static int
-scan_map(struct adfs_sb_info *asb, unsigned int zone,
-	 const unsigned int frag_id, unsigned int mapoff)
+static int scan_map(struct adfs_sb_info *asb, unsigned int zone,
+		    const u32 frag_id, unsigned int mapoff)
 {
 	const unsigned int idlen = asb->s_idlen;
 	struct adfs_discmap *dm, *dm_end;
@@ -243,9 +241,7 @@ adfs_map_free(struct super_block *sb)
 	return signed_asl(total, asb->s_map2blk);
 }
 
-int
-adfs_map_lookup(struct super_block *sb, unsigned int frag_id,
-		unsigned int offset)
+int adfs_map_lookup(struct super_block *sb, u32 frag_id, unsigned int offset)
 {
 	struct adfs_sb_info *asb = ADFS_SB(sb);
 	unsigned int zone, mapoff;
diff --git a/fs/adfs/super.c b/fs/adfs/super.c
index 6087d263cb4d..0beaecd7be3b 100644
--- a/fs/adfs/super.c
+++ b/fs/adfs/super.c
@@ -468,7 +468,7 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent)
 
 	dr = adfs_map_discrecord(asb->s_map);
 
-	root_obj.parent_id = root_obj.file_id = le32_to_cpu(dr->root);
+	root_obj.parent_id = root_obj.indaddr = le32_to_cpu(dr->root);
 	root_obj.name_len  = 0;
 	/* Set root object date as 01 Jan 1987 00:00:00 */
 	root_obj.loadaddr  = 0xfff0003f;
-- 
2.7.4


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

* [PATCH 08/12] fs/adfs: super: correct superblock flags
       [not found] <20190604111943.GA15281@rmk-PC.armlinux.org.uk>
                   ` (6 preceding siblings ...)
  2019-06-04 13:49 ` [PATCH 07/12] fs/adfs: clean up indirect disc addresses and fragment IDs Russell King
@ 2019-06-04 13:50 ` Russell King
  2019-06-04 13:50 ` [PATCH 09/12] fs/adfs: super: safely update options on remount Russell King
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 12+ messages in thread
From: Russell King @ 2019-06-04 13:50 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel

We don't support atime updates of any kind, and we ought to set the
read-only bit if we are compiled without write support.

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

diff --git a/fs/adfs/super.c b/fs/adfs/super.c
index 0beaecd7be3b..1e6afc324f61 100644
--- a/fs/adfs/super.c
+++ b/fs/adfs/super.c
@@ -19,6 +19,8 @@
 #include "dir_f.h"
 #include "dir_fplus.h"
 
+#define ADFS_SB_FLAGS SB_NOATIME
+
 #define ADFS_DEFAULT_OWNER_MASK S_IRWXU
 #define ADFS_DEFAULT_OTHER_MASK (S_IRWXG | S_IRWXO)
 
@@ -227,7 +229,7 @@ static int parse_options(struct super_block *sb, char *options)
 static int adfs_remount(struct super_block *sb, int *flags, char *data)
 {
 	sync_filesystem(sb);
-	*flags |= SB_NODIRATIME;
+	*flags |= ADFS_SB_FLAGS;
 	return parse_options(sb, data);
 }
 
@@ -377,7 +379,7 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent)
 	struct inode *root;
 	int ret = -EINVAL;
 
-	sb->s_flags |= SB_NODIRATIME;
+	sb->s_flags |= ADFS_SB_FLAGS;
 
 	asb = kzalloc(sizeof(*asb), GFP_KERNEL);
 	if (!asb)
-- 
2.7.4


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

* [PATCH 09/12] fs/adfs: super: safely update options on remount
       [not found] <20190604111943.GA15281@rmk-PC.armlinux.org.uk>
                   ` (7 preceding siblings ...)
  2019-06-04 13:50 ` [PATCH 08/12] fs/adfs: super: correct superblock flags Russell King
@ 2019-06-04 13:50 ` Russell King
  2019-06-04 13:50 ` [PATCH 10/12] fs/adfs: super: fix use-after-free bug Russell King
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 12+ messages in thread
From: Russell King @ 2019-06-04 13:50 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel

Only update the options on remount if we successfully parse all options,
rather than updating those we've managed to parse.

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

diff --git a/fs/adfs/super.c b/fs/adfs/super.c
index 1e6afc324f61..c17ece0a3b61 100644
--- a/fs/adfs/super.c
+++ b/fs/adfs/super.c
@@ -170,10 +170,10 @@ static const match_table_t tokens = {
 	{Opt_err, NULL}
 };
 
-static int parse_options(struct super_block *sb, char *options)
+static int parse_options(struct super_block *sb, struct adfs_sb_info *asb,
+			 char *options)
 {
 	char *p;
-	struct adfs_sb_info *asb = ADFS_SB(sb);
 	int option;
 
 	if (!options)
@@ -228,9 +228,18 @@ static int parse_options(struct super_block *sb, char *options)
 
 static int adfs_remount(struct super_block *sb, int *flags, char *data)
 {
+	struct adfs_sb_info temp_asb;
+	int ret;
+
 	sync_filesystem(sb);
 	*flags |= ADFS_SB_FLAGS;
-	return parse_options(sb, data);
+
+	temp_asb = *ADFS_SB(sb);
+	ret = parse_options(sb, &temp_asb, data);
+	if (ret == 0)
+		*ADFS_SB(sb) = temp_asb;
+
+	return ret;
 }
 
 static int adfs_statfs(struct dentry *dentry, struct kstatfs *buf)
@@ -393,7 +402,7 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent)
 	asb->s_other_mask = ADFS_DEFAULT_OTHER_MASK;
 	asb->s_ftsuffix = 0;
 
-	if (parse_options(sb, data))
+	if (parse_options(sb, asb, data))
 		goto error;
 
 	sb_set_blocksize(sb, BLOCK_SIZE);
-- 
2.7.4


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

* [PATCH 10/12] fs/adfs: super: fix use-after-free bug
       [not found] <20190604111943.GA15281@rmk-PC.armlinux.org.uk>
                   ` (8 preceding siblings ...)
  2019-06-04 13:50 ` [PATCH 09/12] fs/adfs: super: safely update options on remount Russell King
@ 2019-06-04 13:50 ` Russell King
  2019-06-04 13:50 ` [PATCH 11/12] fs/adfs: super: limit idlen according to directory type Russell King
  2019-06-04 13:50 ` [PATCH 12/12] fs/adfs: add time stamp and file type helpers Russell King
  11 siblings, 0 replies; 12+ messages in thread
From: Russell King @ 2019-06-04 13:50 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel

Fix a use-after-free bug during filesystem initialisation, where we
access the disc record (which is stored in a buffer) after we have
released the buffer.

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

diff --git a/fs/adfs/super.c b/fs/adfs/super.c
index c17ece0a3b61..c370b8618469 100644
--- a/fs/adfs/super.c
+++ b/fs/adfs/super.c
@@ -384,6 +384,7 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent)
 	struct buffer_head *bh;
 	struct object_info root_obj;
 	unsigned char *b_data;
+	unsigned int blocksize;
 	struct adfs_sb_info *asb;
 	struct inode *root;
 	int ret = -EINVAL;
@@ -429,8 +430,10 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent)
 		goto error_badfs;
 	}
 
+	blocksize = 1 << dr->log2secsize;
 	brelse(bh);
-	if (sb_set_blocksize(sb, 1 << dr->log2secsize)) {
+
+	if (sb_set_blocksize(sb, blocksize)) {
 		bh = sb_bread(sb, ADFS_DISCRECORD / sb->s_blocksize);
 		if (!bh) {
 			adfs_msg(sb, KERN_ERR,
-- 
2.7.4


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

* [PATCH 11/12] fs/adfs: super: limit idlen according to directory type
       [not found] <20190604111943.GA15281@rmk-PC.armlinux.org.uk>
                   ` (9 preceding siblings ...)
  2019-06-04 13:50 ` [PATCH 10/12] fs/adfs: super: fix use-after-free bug Russell King
@ 2019-06-04 13:50 ` Russell King
  2019-06-04 13:50 ` [PATCH 12/12] fs/adfs: add time stamp and file type helpers Russell King
  11 siblings, 0 replies; 12+ messages in thread
From: Russell King @ 2019-06-04 13:50 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel

Limit idlen according to the directory type, as idlen (the size of a
fragment ID) can not be more than 16 with the "new directory" layout.

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

diff --git a/fs/adfs/super.c b/fs/adfs/super.c
index c370b8618469..4529f53b1708 100644
--- a/fs/adfs/super.c
+++ b/fs/adfs/super.c
@@ -54,6 +54,7 @@ void adfs_msg(struct super_block *sb, const char *pfx, const char *fmt, ...)
 
 static int adfs_checkdiscrecord(struct adfs_discrecord *dr)
 {
+	unsigned int max_idlen;
 	int i;
 
 	/* sector size must be 256, 512 or 1024 bytes */
@@ -73,8 +74,13 @@ static int adfs_checkdiscrecord(struct adfs_discrecord *dr)
 	if (le32_to_cpu(dr->disc_size_high) >> dr->log2secsize)
 		return 1;
 
-	/* idlen must be no greater than 19 v2 [1.0] */
-	if (dr->idlen > 19)
+	/*
+	 * Maximum idlen is limited to 16 bits for new directories by
+	 * the three-byte storage of an indirect disc address.  For
+	 * big directories, idlen must be no greater than 19 v2 [1.0]
+	 */
+	max_idlen = dr->format_version ? 19 : 16;
+	if (dr->idlen > max_idlen)
 		return 1;
 
 	/* reserved bytes should be zero */
-- 
2.7.4


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

* [PATCH 12/12] fs/adfs: add time stamp and file type helpers
       [not found] <20190604111943.GA15281@rmk-PC.armlinux.org.uk>
                   ` (10 preceding siblings ...)
  2019-06-04 13:50 ` [PATCH 11/12] fs/adfs: super: limit idlen according to directory type Russell King
@ 2019-06-04 13:50 ` Russell King
  11 siblings, 0 replies; 12+ messages in thread
From: Russell King @ 2019-06-04 13:50 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel

Add some helpers to check whether the inode has a time stamp and file
type, and to parse the file type from the load address.

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

diff --git a/fs/adfs/adfs.h b/fs/adfs/adfs.h
index 9eb9bea1cef2..b7e844d2f321 100644
--- a/fs/adfs/adfs.h
+++ b/fs/adfs/adfs.h
@@ -9,6 +9,15 @@
 #define ADFS_BAD_FRAG		 1
 #define ADFS_ROOT_FRAG		 2
 
+#define ADFS_FILETYPE_NONE	((u16)~0)
+
+/* RISC OS 12-bit filetype is stored in load_address[19:8] */
+static inline u16 adfs_filetype(u32 loadaddr)
+{
+	return (loadaddr & 0xfff00000) == 0xfff00000 ?
+	       (loadaddr >> 8) & 0xfff : ADFS_FILETYPE_NONE;
+}
+
 #define ADFS_NDA_OWNER_READ	(1 << 0)
 #define ADFS_NDA_OWNER_WRITE	(1 << 1)
 #define ADFS_NDA_LOCKED		(1 << 2)
@@ -27,12 +36,20 @@ struct adfs_inode_info {
 	__u32		parent_id;	/* parent indirect disc address	*/
 	__u32		loadaddr;	/* RISC OS load address		*/
 	__u32		execaddr;	/* RISC OS exec address		*/
-	unsigned int	filetype;	/* RISC OS file type		*/
 	unsigned int	attr;		/* RISC OS permissions		*/
-	unsigned int	stamped:1;	/* RISC OS file has date/time	*/
 	struct inode vfs_inode;
 };
 
+static inline struct adfs_inode_info *ADFS_I(struct inode *inode)
+{
+	return container_of(inode, struct adfs_inode_info, vfs_inode);
+}
+
+static inline bool adfs_inode_is_stamped(struct inode *inode)
+{
+	return (ADFS_I(inode)->loadaddr & 0xfff00000) == 0xfff00000;
+}
+
 /*
  * Forward-declare this
  */
@@ -68,11 +85,6 @@ static inline struct adfs_sb_info *ADFS_SB(struct super_block *sb)
 	return sb->s_fs_info;
 }
 
-static inline struct adfs_inode_info *ADFS_I(struct inode *inode)
-{
-	return container_of(inode, struct adfs_inode_info, vfs_inode);
-}
-
 /*
  * Directory handling
  */
@@ -105,9 +117,6 @@ struct object_info {
 	__u8		attr;			/* RISC OS attributes	*/
 	unsigned int	name_len;		/* name length		*/
 	char		name[ADFS_MAX_NAME_LEN];/* file name		*/
-
-	/* RISC OS file type (12-bit: derived from loadaddr) */
-	__u16		filetype;
 };
 
 struct adfs_dir_ops {
diff --git a/fs/adfs/dir.c b/fs/adfs/dir.c
index 01ffd47c7461..77503d12f7ee 100644
--- a/fs/adfs/dir.c
+++ b/fs/adfs/dir.c
@@ -38,20 +38,14 @@ void adfs_object_fixup(struct adfs_dir *dir, struct object_info *obj)
 	if (obj->name_len <= 2 && dots == obj->name_len)
 		obj->name[0] = '^';
 
-	obj->filetype = -1;
-
 	/*
-	 * object is a file and is filetyped and timestamped?
-	 * RISC OS 12-bit filetype is stored in load_address[19:8]
+	 * If the object is a file, and the user requested the ,xyz hex
+	 * filetype suffix to the name, check the filetype and append.
 	 */
-	if ((0 == (obj->attr & ADFS_NDA_DIRECTORY)) &&
-	    (0xfff00000 == (0xfff00000 & obj->loadaddr))) {
-		obj->filetype = (__u16) ((0x000fff00 & obj->loadaddr) >> 8);
-
-		/* optionally append the ,xyz hex filetype suffix */
-		if (ADFS_SB(dir->sb)->s_ftsuffix) {
-			__u16 filetype = obj->filetype;
+	if (!(obj->attr & ADFS_NDA_DIRECTORY) && ADFS_SB(dir->sb)->s_ftsuffix) {
+		u16 filetype = adfs_filetype(obj->loadaddr);
 
+		if (filetype != ADFS_FILETYPE_NONE) {
 			obj->name[obj->name_len++] = ',';
 			obj->name[obj->name_len++] = hex_asc_lo(filetype >> 8);
 			obj->name[obj->name_len++] = hex_asc_lo(filetype >> 4);
diff --git a/fs/adfs/inode.c b/fs/adfs/inode.c
index 5f5af660b02e..d61c7453a4c3 100644
--- a/fs/adfs/inode.c
+++ b/fs/adfs/inode.c
@@ -97,7 +97,7 @@ adfs_atts2mode(struct super_block *sb, struct inode *inode)
 		return S_IFDIR | S_IXUGO | mode;
 	}
 
-	switch (ADFS_I(inode)->filetype) {
+	switch (adfs_filetype(ADFS_I(inode)->loadaddr)) {
 	case 0xfc0:	/* LinkFS */
 		return S_IFLNK|S_IRWXUGO;
 
@@ -177,7 +177,7 @@ adfs_adfs2unix_time(struct timespec64 *tv, struct inode *inode)
 							2208988800000000000LL;
 	s64 nsec;
 
-	if (ADFS_I(inode)->stamped == 0)
+	if (!adfs_inode_is_stamped(inode))
 		goto cur_time;
 
 	high = ADFS_I(inode)->loadaddr & 0xFF; /* top 8 bits of timestamp */
@@ -216,7 +216,7 @@ adfs_unix2adfs_time(struct inode *inode, unsigned int secs)
 {
 	unsigned int high, low;
 
-	if (ADFS_I(inode)->stamped) {
+	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;
@@ -266,8 +266,6 @@ adfs_iget(struct super_block *sb, struct object_info *obj)
 	ADFS_I(inode)->loadaddr  = obj->loadaddr;
 	ADFS_I(inode)->execaddr  = obj->execaddr;
 	ADFS_I(inode)->attr      = obj->attr;
-	ADFS_I(inode)->filetype  = obj->filetype;
-	ADFS_I(inode)->stamped   = ((obj->loadaddr & 0xfff00000) == 0xfff00000);
 
 	inode->i_mode	 = adfs_atts2mode(sb, inode);
 	adfs_adfs2unix_time(&inode->i_mtime, inode);
diff --git a/fs/adfs/super.c b/fs/adfs/super.c
index 4529f53b1708..b71476f6e564 100644
--- a/fs/adfs/super.c
+++ b/fs/adfs/super.c
@@ -496,7 +496,6 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent)
 	root_obj.size	   = ADFS_NEWDIR_SIZE;
 	root_obj.attr	   = ADFS_NDA_DIRECTORY   | ADFS_NDA_OWNER_READ |
 			     ADFS_NDA_OWNER_WRITE | ADFS_NDA_PUBLIC_READ;
-	root_obj.filetype  = -1;
 
 	/*
 	 * If this is a F+ disk with variable length directories,
-- 
2.7.4


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

end of thread, other threads:[~2019-06-04 13:50 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <20190604111943.GA15281@rmk-PC.armlinux.org.uk>
2019-06-04 13:49 ` [PATCH 01/12] fs/adfs: correct disc record structure Russell King
2019-06-04 13:49 ` [PATCH 02/12] fs/adfs: add helper to get discrecord from map Russell King
2019-06-04 13:49 ` [PATCH 03/12] fs/adfs: add helper to get filesystem size Russell King
2019-06-04 13:49 ` [PATCH 04/12] fs/adfs: use format_version from disc_record Russell King
2019-06-04 13:49 ` [PATCH 05/12] fs/adfs: use %pV for error messages Russell King
2019-06-04 13:49 ` [PATCH 06/12] fs/adfs: clean up error message printing Russell King
2019-06-04 13:49 ` [PATCH 07/12] fs/adfs: clean up indirect disc addresses and fragment IDs Russell King
2019-06-04 13:50 ` [PATCH 08/12] fs/adfs: super: correct superblock flags Russell King
2019-06-04 13:50 ` [PATCH 09/12] fs/adfs: super: safely update options on remount Russell King
2019-06-04 13:50 ` [PATCH 10/12] fs/adfs: super: fix use-after-free bug Russell King
2019-06-04 13:50 ` [PATCH 11/12] fs/adfs: super: limit idlen according to directory type Russell King
2019-06-04 13:50 ` [PATCH 12/12] fs/adfs: add time stamp and file type helpers 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).