fs/adfs updates for 5.6
Subsystems (2)
cover fs/adfs updates for 5.6
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(-)
Signature · 3 lines
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
PATCH 1/41 fs/adfs: inode: update timestamps to centisecond precision
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.
--- fs/adfs/inode.c | 40 ++++++++++++++++++++-------------------- fs/adfs/super.c | 2 ++ 2 files changed, 22 insertions(+), 20 deletions(-)
fs/adfs/inode.c +20 -20
@@ -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?
fs/adfs/super.c +2 -0
@@ -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 ;
Signature · 1 line
2.20.1
PATCH 2/41 fs/adfs: inode: fix adfs_mode2atts()
In reply to Russell King - ARM Linux adminFix 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.
--- fs/adfs/inode.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-)
fs/adfs/inode.c +9 -9
@@ -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); }
Signature · 1 line
2.20.1
PATCH 3/41 fs/adfs: map: move map reading and validation to map.c
In reply to Russell King - ARM Linux adminKeep all the map code together in map.c, rather than having some in super.c
--- fs/adfs/adfs.h | 1 + fs/adfs/map.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++ fs/adfs/super.c | 98 ------------------------------------------------ 3 files changed, 100 insertions(+), 98 deletions(-)
fs/adfs/adfs.h +1 -0
@@ -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 )
fs/adfs/map.c +99 -0
108 lines not on this page · raw message
fs/adfs/super.c +0 -98
110 lines not on this page · raw message
Signature · 1 line
2.20.1
PATCH 4/41 fs/adfs: map: rename adfs_map_free() to adfs_map_statfs()
In reply to Russell King - ARM Linux adminadfs_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.
--- fs/adfs/adfs.h | 2 +- fs/adfs/map.c | 10 +++++++--- fs/adfs/super.c | 7 ++----- 3 files changed, 10 insertions(+), 9 deletions(-)
fs/adfs/adfs.h +1 -1
@@ -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 */
fs/adfs/map.c +7 -3
@@ -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)
fs/adfs/super.c +2 -5
@@ -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 );
Signature · 1 line
2.20.1
PATCH 5/41 fs/adfs: map: break up adfs_read_map()
In reply to Russell King - ARM Linux adminSplit up adfs_read_map() into separate helpers to layout the map, read the map, and release the map buffers.
--- fs/adfs/map.c | 80 +++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 59 insertions(+), 21 deletions(-)
fs/adfs/map.c +59 -21
@@ -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_discrecorreturn 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 ); }
Signature · 1 line
2.20.1
PATCH 6/41 fs/adfs: map: factor out map cleanup
In reply to Russell King - ARM Linux adminWe have several places which deal with releasing the map buffers and freeing the map array. Provide a helper for this.
--- fs/adfs/adfs.h | 1 + fs/adfs/map.c | 8 ++++++++ fs/adfs/super.c | 10 ++-------- 3 files changed, 11 insertions(+), 8 deletions(-)
fs/adfs/adfs.h +1 -0
@@ -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 )
fs/adfs/map.c +8 -0
@@ -421,3 +421,11 @@ struct adfs_discmap *adfs_read_map(struct super_block *sb, struct adfs_discrecorkfree (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); +}
fs/adfs/super.c +2 -8
@@ -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;
Signature · 1 line
2.20.1
PATCH 7/41 fs/adfs: map: incorporate map offsets into layout
In reply to Russell King - ARM Linux adminlookup_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.
--- fs/adfs/map.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-)
fs/adfs/map.c +11 -11
@@ -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,
Signature · 1 line
2.20.1
PATCH 8/41 fs/adfs: map: use find_next_bit_le() rather than open coding it
In reply to Russell King - ARM Linux adminUse find_next_bit_le() to find the end of a fragment in the map rather than open-coding this functionality.
--- fs/adfs/map.c | 76 ++++++++++++++------------------------------------- 1 file changed, 21 insertions(+), 55 deletions(-)
fs/adfs/map.c +21 -55
@@ -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 )
Signature · 1 line
2.20.1
PATCH 9/41 fs/adfs: map: move map-specific sb initialisation to map.c
In reply to Russell King - ARM Linux adminMove map specific superblock initialisation to map.c, rather than having it spread into super.c.
--- fs/adfs/map.c | 13 +++++++++---- fs/adfs/super.c | 7 +------ 2 files changed, 10 insertions(+), 10 deletions(-)
fs/adfs/map.c +9 -4
@@ -355,14 +355,19 @@ struct adfs_discmap *adfs_read_map(struct super_block *sb, struct adfs_discrecorunsigned 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" );
fs/adfs/super.c +1 -6
@@ -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);
Signature · 1 line
2.20.1
PATCH 10/41 fs/adfs: map: fix map scanning
In reply to Russell King - ARM Linux adminWhen 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.
--- fs/adfs/map.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
fs/adfs/map.c +7 -2
@@ -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)
Signature · 1 line
2.20.1
PATCH 14/41 fs/adfs: dir: add common directory sync method
In reply to Russell King - ARM Linux adminadfs_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.
--- 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(-)
fs/adfs/adfs.h +0 -1
@@ -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 {
fs/adfs/dir.c +18 -5
@@ -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; }
fs/adfs/dir_f.c +0 -17
@@ -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, };
fs/adfs/dir_fplus.c +0 -17
@@ -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, };
Signature · 1 line
2.20.1
PATCH 15/41 fs/adfs: dir: add generic copy functions
In reply to Russell King - ARM Linux adminDirectories 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.
--- 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(-)
fs/adfs/adfs.h +4 -0
@@ -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,
fs/adfs/dir.c +50 -0
56 lines not on this page · raw message
fs/adfs/dir_f.c +9 -47
75 lines not on this page · raw message
fs/adfs/dir_fplus.c +12 -35
75 lines not on this page · raw message
Signature · 1 line
2.20.1
PATCH 16/41 fs/adfs: dir: add generic directory reading
In reply to Russell King - ARM Linux adminBoth directory formats code the mechanics of fetching the directory buffers using their own implementations. Consolidate these into one implementation.
--- 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(-)
fs/adfs/adfs.h +2 -0
@@ -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);
fs/adfs/dir.c +49 -0
55 lines not on this page · raw message
fs/adfs/dir_f.c +4 -20
@@ -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 ;
fs/adfs/dir_fplus.c +19 -57
106 lines not on this page · raw message
Signature · 1 line
2.20.1
PATCH 17/41 fs/adfs: dir: add helper to read directory using inode
In reply to Russell King - ARM Linux adminAdd a helper to read a directory using the inode, which we do in two places.
--- fs/adfs/dir.c | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-)
fs/adfs/dir.c +22 -10
@@ -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);
Signature · 1 line
2.20.1
PATCH 13/41 fs/adfs: dir: add common directory buffer release method
In reply to Russell King - ARM Linux adminWith 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.
--- 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(-)
fs/adfs/adfs.h +1 -1
@@ -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);
fs/adfs/dir.c +18 -3
@@ -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; }
fs/adfs/dir_f.c +4 -24
@@ -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 };
fs/adfs/dir_fplus.c +2 -32
@@ -15,7 +15,7 @@ adfs_fplus_read(struct super_block *sb, unsigned int id, unsigned int sz, structstruct 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, structreturn 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 };
Signature · 1 line
2.20.1
PATCH 12/41 fs/adfs: dir: add common dir object initialisation
In reply to Russell King - ARM Linux adminInitialise 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.
--- fs/adfs/dir.c | 16 +++++++++++++--- fs/adfs/dir_f.c | 3 --- fs/adfs/dir_fplus.c | 6 ------ 3 files changed, 13 insertions(+), 12 deletions(-)
fs/adfs/dir.c +13 -3
@@ -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;
fs/adfs/dir_f.c +0 -3
@@ -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;
fs/adfs/dir_fplus.c +0 -6
@@ -17,11 +17,6 @@ adfs_fplus_read(struct super_block *sb, unsigned int id, unsigned int sz, structunsigned 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:
Signature · 1 line
2.20.1
PATCH 18/41 fs/adfs: dir: add helper to mark directory buffers dirty
In reply to Russell King - ARM Linux adminProvide a helper for marking directory buffers dirty so they get written back to disk.
--- fs/adfs/dir.c | 12 ++++++++++++ fs/adfs/dir_f.c | 5 +---- 2 files changed, 13 insertions(+), 4 deletions(-)
fs/adfs/dir.c +12 -0
@@ -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)
fs/adfs/dir_f.c +1 -4
@@ -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;
Signature · 1 line
2.20.1
PATCH 19/41 fs/adfs: dir: update directory locking
In reply to Russell King - ARM Linux adminUpdate 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.
--- fs/adfs/dir.c | 55 +++++++++++++++++++++++++++------------------------ 1 file changed, 29 insertions(+), 26 deletions(-)
fs/adfs/dir.c +29 -26
@@ -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; }
Signature · 1 line
2.20.1
PATCH 11/41 fs/adfs: dir: rename bh_fplus to bhs
In reply to Russell King - ARM Linux adminRename bh_fplus to bhs in preparation to make some of the directory handling code sharable between implementations.
--- fs/adfs/adfs.h | 4 +--- fs/adfs/dir_fplus.c | 54 ++++++++++++++++++++++----------------------- 2 files changed, 28 insertions(+), 30 deletions(-)
fs/adfs/adfs.h +1 -3
@@ -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;
fs/adfs/dir_fplus.c +27 -27
147 lines not on this page · raw message
Signature · 1 line
2.20.1
PATCH 20/41 fs/adfs: dir: modernise on-disk directory structures
In reply to Russell King - ARM Linux adminUse __u8 and pack the structures for on-disk directories.
--- fs/adfs/dir_f.h | 52 ++++++++++++++++++++++++--------------------- fs/adfs/dir_fplus.h | 6 +++--- 2 files changed, 31 insertions(+), 27 deletions(-)
fs/adfs/dir_f.h +28 -24
@@ -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
fs/adfs/dir_fplus.h +3 -3
@@ -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 )));
Signature · 1 line
2.20.1
PATCH 21/41 fs/adfs: dir: improve update failure handling
In reply to Russell King - ARM Linux adminWhen 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.
--- fs/adfs/dir.c | 48 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 12 deletions(-)
fs/adfs/dir.c +36 -12
@@ -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
Signature · 1 line
2.20.1
PATCH 22/41 fs/adfs: dir: improve compiler coverage in adfs_dir_update
In reply to Russell King - ARM Linux adminGet 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.
--- fs/adfs/dir.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
fs/adfs/dir.c +5 -3
@@ -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; }
Signature · 1 line
2.20.1
PATCH 23/41 fs/adfs: dir: switch to iterate_shared method
In reply to Russell King - ARM Linux adminThere 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().
--- fs/adfs/dir.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
fs/adfs/dir.c +2 -3
@@ -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, };
Signature · 1 line
2.20.1
PATCH 24/41 fs/adfs: dir: add more efficient iterate() per-format method
In reply to Russell King - ARM Linux adminRather than using setpos + getnext to iterate through the directory entries, pass iterate() down to the dir format code to populate the dirents.
--- 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(-)
fs/adfs/adfs.h +1 -0
@@ -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);
fs/adfs/dir.c +2 -14
@@ -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);
fs/adfs/dir_f.c +18 -0
@@ -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,
fs/adfs/dir_fplus.c +21 -0
@@ -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, };
Signature · 1 line
2.20.1
PATCH 25/41 fs/adfs: dir: use pointers to access directory head/tails
In reply to Russell King - ARM Linux adminAdd 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.
--- fs/adfs/adfs.h | 12 ++++++++---- fs/adfs/dir_f.c | 42 +++++++++++++++++------------------------- fs/adfs/dir_fplus.c | 11 ++++------- 3 files changed, 29 insertions(+), 36 deletions(-)
fs/adfs/adfs.h +8 -4
@@ -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; + }; };/*
fs/adfs/dir_f.c +17 -25
89 lines not on this page · raw message
fs/adfs/dir_fplus.c +4 -7
@@ -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;
Signature · 1 line
2.20.1
PATCH 26/41 fs/adfs: newdir: factor out directory format validation
In reply to Russell King - ARM Linux adminWe have two locations where we validate the new directory format, so factor this out to a helper.
--- fs/adfs/dir_f.c | 48 ++++++++++++++++++++---------------------------- 1 file changed, 20 insertions(+), 28 deletions(-)
fs/adfs/dir_f.c +20 -28
@@ -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 = {
Signature · 1 line
2.20.1
PATCH 27/41 fs/adfs: newdir: improve directory validation
In reply to Russell King - ARM Linux adminCheck that the lastmask and reserved fields are all zero, as per the documentation.
--- fs/adfs/dir_f.c | 1 + 1 file changed, 1 insertion(+)
fs/adfs/dir_f.c +1 -0
@@ -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) ||
Signature · 1 line
2.20.1
PATCH 28/41 fs/adfs: newdir: merge adfs_dir_read() into adfs_f_read()
In reply to Russell King - ARM Linux adminadfs_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.
--- fs/adfs/dir_f.c | 33 +++++++-------------------------- 1 file changed, 7 insertions(+), 26 deletions(-)
fs/adfs/dir_f.c +7 -26
@@ -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) {
Signature · 1 line
2.20.1
PATCH 29/41 fs/adfs: newdir: clean up adfs_f_update()
In reply to Russell King - ARM Linux admin__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.
--- fs/adfs/dir_f.c | 73 ++++++++++++++++--------------------------------- 1 file changed, 24 insertions(+), 49 deletions(-)
fs/adfs/dir_f.c +24 -49
@@ -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
Signature · 1 line
2.20.1
PATCH 30/41 fs/adfs: newdir: split out directory commit from update
In reply to Russell King - ARM Linux adminAfter 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.
--- fs/adfs/adfs.h | 1 + fs/adfs/dir.c | 4 ++++ fs/adfs/dir_f.c | 26 +++++++++++++------------- 3 files changed, 18 insertions(+), 13 deletions(-)
fs/adfs/adfs.h +1 -0
@@ -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 {
fs/adfs/dir.c +4 -0
@@ -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);
fs/adfs/dir_f.c +13 -13
@@ -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, };
Signature · 1 line
2.20.1
PATCH 31/41 fs/adfs: bigdir: factor out directory entry offset calculation
In reply to Russell King - ARM Linux adminFactor out the directory entry byte offset calculation.
--- fs/adfs/dir_fplus.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-)
fs/adfs/dir_fplus.c +11 -6
@@ -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);
Signature · 1 line
2.20.1
PATCH 32/41 fs/adfs: bigdir: extract directory validation
In reply to Russell King - ARM Linux adminExtract the directory validation from the directory reading function as we will want to re-use this code.
--- fs/adfs/dir_fplus.c | 41 +++++++++++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 10 deletions(-)
fs/adfs/dir_fplus.c +31 -10
@@ -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; }
Signature · 1 line
2.20.1
PATCH 33/41 fs/adfs: bigdir: directory validation strengthening
In reply to Russell King - ARM Linux adminStrengthen 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.
--- fs/adfs/dir_fplus.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-)
fs/adfs/dir_fplus.c +28 -1
@@ -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 ;
Signature · 1 line
2.20.1
PATCH 34/41 fs/adfs: bigdir: calculate and validate directory checkbyte
In reply to Russell King - ARM Linux adminWhen reading a big directory, calculate the validate the directory checkbyte to ensure that the directory contents are valid.
--- fs/adfs/dir_fplus.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+)
fs/adfs/dir_fplus.c +38 -0
@@ -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 ;
Signature · 1 line
2.20.1
PATCH 35/41 fs/adfs: bigdir: implement directory update support
In reply to Russell King - ARM Linux adminImplement big directory entry update support in the same way that we do for new directories.
--- fs/adfs/dir_fplus.c | 54 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-)
fs/adfs/dir_fplus.c +53 -1
@@ -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, };
Signature · 1 line
2.20.1
PATCH 36/41 fs/adfs: super: fix inode dropping
In reply to Russell King - ARM Linux adminWhen 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.
--- fs/adfs/super.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
fs/adfs/super.c +7 -1
@@ -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,
Signature · 1 line
2.20.1
PATCH 37/41 fs/adfs: dir: remove debug in adfs_dir_update()
In reply to Russell King - ARM Linux adminRemove the noisy debug in adfs_dir_update().
--- fs/adfs/dir.c | 3 --- 1 file changed, 3 deletions(-)
fs/adfs/dir.c +0 -3
@@ -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 ;
Signature · 1 line
2.20.1
PATCH 38/41 fs/adfs: super: extract filesystem block probe
In reply to Russell King - ARM Linux adminSeparate 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.
--- fs/adfs/super.c | 149 +++++++++++++++++++++++++----------------------- 1 file changed, 78 insertions(+), 71 deletions(-)
fs/adfs/super.c +78 -71
@@ -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);
Signature · 1 line
2.20.1
PATCH 39/41 fs/adfs: super: add support for E and E+ floppy image formats
In reply to Russell King - ARM Linux adminAdd 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.
--- fs/adfs/super.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-)
fs/adfs/super.c +17 -1
@@ -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,
Signature · 1 line
2.20.1
PATCH 40/41 fs/adfs: mostly divorse inode number from indirect disc address
In reply to Russell King - ARM Linux adminAvoid using the inode number as the indirect disc address, even though these currently have the same value.
--- fs/adfs/adfs.h | 1 + fs/adfs/dir.c | 4 ++-- fs/adfs/inode.c | 6 ++++-- 3 files changed, 7 insertions(+), 4 deletions(-)
fs/adfs/adfs.h +1 -0
@@ -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 */
fs/adfs/dir.c +2 -2
@@ -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);
fs/adfs/inode.c +4 -2
@@ -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;
Signature · 1 line
2.20.1
PATCH 41/41 Documentation: update adfs filesystem documentation
In reply to Russell King - ARM Linux adminAdd an introduction to adfs to its documentation detailing which formats are supported by the module.
--- Documentation/filesystems/adfs.txt | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+)
Documentation/filesystems/adfs.txt +24 -0
@@ -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 ----------------------
Signature · 1 line
2.20.1
Re: [PATCH 01/41] fs/adfs: inode: update timestamps to centisecond precision
In reply to Russell KingQuoted 105 lines · Russell King
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 <[email protected]>--- fs/adfs/inode.c | 40 ++++++++++++++++++++-------------------- fs/adfs/super.c | 2 ++ 2 files changed, 22 insertions(+), 20 deletions(-)fs/adfs/inode.c +2
-0@@ -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 secondsfs/adfs/inode.c +0
-2@@ -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;fs/adfs/inode.c +0
-2if (!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.
- */fs/adfs/inode.c +1
-2-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. */
fs/adfs/inode.c +17
-12+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 fs/adfs/inode.c +0
-0* have the ability to represent them in our filesystem? fs/adfs/super.c +0
-0
fs/adfs/super.c static int adfs_fill_super(struct super_block · line 397
Quoted 7 lines
fs/adfs/super.c +2
-0@@ -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.
Quoted 3 lines
fs/adfs/super.c +0
-0/* set default options */ asb->s_uid =GLOBAL_ROOT_UID ;
Re: [PATCH 01/41] fs/adfs: inode: update timestamps to centisecond precision
Quoted 108 lines · Vyacheslav Dubeyko
Quoted 107 lines · Russell King
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 <[email protected]>--- fs/adfs/inode.c | 40 ++++++++++++++++++++-------------------- fs/adfs/super.c | 2 ++ 2 files changed, 22 insertions(+), 20 deletions(-)fs/adfs/inode.c +2
-0@@ -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 secondsfs/adfs/inode.c +0
-2@@ -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;fs/adfs/inode.c +0
-2if (!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.
- */fs/adfs/inode.c +1
-2-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. */
fs/adfs/inode.c +17
-12+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 fs/adfs/inode.c +0
-0* have the ability to represent them in our filesystem? fs/adfs/super.c +0
-0@@ -391,7 +391,9 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent) asb =kzalloc (sizeof (*asb),GFP_KERNEL );
Quoted 8 lines
fs/adfs/super.c static int adfs_fill_super(struct super_block *sb, void *data, int silent) · line 396
Quoted 5 lines
fs/adfs/super.c +2
-0if (!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.
Signature · 3 lines
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
Re: [PATCH 01/41] fs/adfs: inode: update timestamps to centisecond precision
Quoted 3 lines · Russell King - ARM Linux admin
Quoted 1 line
Quoted 1 line
Quoted 1 line · Vyacheslav Dubeyko
On Mon, 2019-12-09 at 11:08 +0000, Russell King wrote:
<snipped>
Quoted 9 lines
Quoted 6 lines
fs/adfs/super.c static int adfs_fill_super(struct super_block *sb, void *data, int silent) · line 396
Quoted 2 lines
fs/adfs/super.c +1
-0sb->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.
Re: [PATCH 01/41] fs/adfs: inode: update timestamps to centisecond precision
Quoted 15 lines · Vyacheslav Dubeyko
Quoted 3 lines · Russell King - ARM Linux admin
Quoted 1 line
Quoted 1 line
Quoted 1 line · Vyacheslav Dubeyko
On Mon, 2019-12-09 at 11:08 +0000, Russell King wrote:
<snipped>
Quoted 7 lines
Quoted 6 lines
fs/adfs/super.c static int adfs_fill_super(struct super_block *sb, void *data, int silent) · line 396
Quoted 2 lines
fs/adfs/super.c +1
-0sb->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?
Quoted 4 lines
Quoted 2 lines
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*.
Signature · 3 lines
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
Re: [PATCH 01/41] fs/adfs: inode: update timestamps to centisecond precision
Quoted 16 lines · Russell King - ARM Linux admin
Quoted 1 line
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_granis in nanoseconds. There are 10000000 nanoseconds in a centisecond.What do you expect?
#define
ADFS_TIME_GRAN10000000sb->s_time_gran = ADFS_TIME_GRAN;?
Quoted 7 lines
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