summaryrefslogtreecommitdiffstats
path: root/fs/afs/xdr_fs.h
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2020-12-23 10:39:57 +0000
committerDavid Howells <dhowells@redhat.com>2021-01-04 12:25:19 +0000
commit366911cd762db02c2dd32fad1be96b72a66f205d (patch)
treef09fdfc5d7c4d61dfb2fd936dc0f5a1a107db1fd /fs/afs/xdr_fs.h
parent26982a89cad77c0efc1c0c79bee0e3d75e9281d4 (diff)
downloadlinux-366911cd762db02c2dd32fad1be96b72a66f205d.tar.bz2
afs: Fix directory entry size calculation
The number of dirent records used by an AFS directory entry should be calculated using the assumption that there is a 16-byte name field in the first block, rather than a 20-byte name field (which is actually the case). This miscalculation is historic and effectively standard, so we have to use it. The calculation we need to use is: 1 + (((strlen(name) + 1) + 15) >> 5) where we are adding one to the strlen() result to account for the NUL termination. Fix this by the following means: (1) Create an inline function to do the calculation for a given name length. (2) Use the function to calculate the number of records used for a dirent in afs_dir_iterate_block(). Use this to move the over-end check out of the loop since it only needs to be done once. Further use this to only go through the loop for the 2nd+ records composing an entry. The only test there now is for if the record is allocated - and we already checked the first block at the top of the outer loop. (3) Add a max name length check in afs_dir_iterate_block(). (4) Make afs_edit_dir_add() and afs_edit_dir_remove() use the function from (1) to calculate the number of blocks rather than doing it incorrectly themselves. Fixes: 63a4681ff39c ("afs: Locally edit directory data for mkdir/create/unlink/...") Fixes: ^1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: David Howells <dhowells@redhat.com> Tested-by: Marc Dionne <marc.dionne@auristor.com>
Diffstat (limited to 'fs/afs/xdr_fs.h')
-rw-r--r--fs/afs/xdr_fs.h14
1 files changed, 13 insertions, 1 deletions
diff --git a/fs/afs/xdr_fs.h b/fs/afs/xdr_fs.h
index c926430fd08a..8ca868164507 100644
--- a/fs/afs/xdr_fs.h
+++ b/fs/afs/xdr_fs.h
@@ -58,7 +58,8 @@ union afs_xdr_dirent {
/* When determining the number of dirent slots needed to
* represent a directory entry, name should be assumed to be 16
* bytes, due to a now-standardised (mis)calculation, but it is
- * in fact 20 bytes in size.
+ * in fact 20 bytes in size. afs_dir_calc_slots() should be
+ * used for this.
*
* For names longer than (16 or) 20 bytes, extra slots should
* be annexed to this one using the extended_name format.
@@ -101,4 +102,15 @@ struct afs_xdr_dir_page {
union afs_xdr_dir_block blocks[AFS_DIR_BLOCKS_PER_PAGE];
};
+/*
+ * Calculate the number of dirent slots required for any given name length.
+ * The calculation is made assuming the part of the name in the first slot is
+ * 16 bytes, rather than 20, but this miscalculation is now standardised.
+ */
+static inline unsigned int afs_dir_calc_slots(size_t name_len)
+{
+ name_len++; /* NUL-terminated */
+ return 1 + ((name_len + 15) / AFS_DIR_DIRENT_SIZE);
+}
+
#endif /* XDR_FS_H */