diff options
author | Russell King <rmk+kernel@armlinux.org.uk> | 2019-12-09 11:09:35 +0000 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2020-01-20 20:12:41 -0500 |
commit | 419a6e5e82ca0bdba0cc3624d969b65ae49d959b (patch) | |
tree | 2571e9fe0242dc1517f926097e52d17e67b280c6 /fs/adfs/dir.c | |
parent | a317120bf7f8306b594ee650ee14f08a0e599602 (diff) |
fs/adfs: dir: add generic directory reading
Both directory formats code the mechanics of fetching the directory
buffers using their own implementations. Consolidate these into one
implementation.
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/adfs/dir.c')
-rw-r--r-- | fs/adfs/dir.c | 49 |
1 files changed, 49 insertions, 0 deletions
diff --git a/fs/adfs/dir.c b/fs/adfs/dir.c index 3c303074aa5e..b8e2a909fa3f 100644 --- a/fs/adfs/dir.c +++ b/fs/adfs/dir.c @@ -78,6 +78,55 @@ void adfs_dir_relse(struct adfs_dir *dir) dir->sb = NULL; } +int adfs_dir_read_buffers(struct super_block *sb, u32 indaddr, + unsigned int size, struct adfs_dir *dir) +{ + struct buffer_head **bhs; + unsigned int i, num; + int block; + + num = ALIGN(size, sb->s_blocksize) >> sb->s_blocksize_bits; + if (num > ARRAY_SIZE(dir->bh)) { + /* We only allow one extension */ + if (dir->bhs != dir->bh) + return -EINVAL; + + bhs = kcalloc(num, sizeof(*bhs), GFP_KERNEL); + if (!bhs) + return -ENOMEM; + + if (dir->nr_buffers) + memcpy(bhs, dir->bhs, dir->nr_buffers * sizeof(*bhs)); + + dir->bhs = bhs; + } + + for (i = dir->nr_buffers; i < num; i++) { + block = __adfs_block_map(sb, indaddr, i); + if (!block) { + adfs_error(sb, "dir %06x has a hole at offset %u", + indaddr, i); + goto error; + } + + dir->bhs[i] = sb_bread(sb, block); + if (!dir->bhs[i]) { + adfs_error(sb, + "dir %06x failed read at offset %u, mapped block 0x%08x", + indaddr, i, block); + goto error; + } + + dir->nr_buffers++; + } + return 0; + +error: + adfs_dir_relse(dir); + + return -EIO; +} + static int adfs_dir_read(struct super_block *sb, u32 indaddr, unsigned int size, struct adfs_dir *dir) { |