1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * linux/fs/adfs/map.c
41da177e4SLinus Torvalds *
51da177e4SLinus Torvalds * Copyright (C) 1997-2002 Russell King
61da177e4SLinus Torvalds */
7f75d398dSRussell King #include <linux/slab.h>
8e6160e46SRussell King #include <linux/statfs.h>
91da177e4SLinus Torvalds #include <asm/unaligned.h>
101da177e4SLinus Torvalds #include "adfs.h"
111da177e4SLinus Torvalds
121da177e4SLinus Torvalds /*
131da177e4SLinus Torvalds * The ADFS map is basically a set of sectors. Each sector is called a
141da177e4SLinus Torvalds * zone which contains a bitstream made up of variable sized fragments.
151da177e4SLinus Torvalds * Each bit refers to a set of bytes in the filesystem, defined by
161da177e4SLinus Torvalds * log2bpmb. This may be larger or smaller than the sector size, but
171da177e4SLinus Torvalds * the overall size it describes will always be a round number of
181da177e4SLinus Torvalds * sectors. A fragment id is always idlen bits long.
191da177e4SLinus Torvalds *
201da177e4SLinus Torvalds * < idlen > < n > <1>
211da177e4SLinus Torvalds * +---------+-------//---------+---+
221da177e4SLinus Torvalds * | frag id | 0000....000000 | 1 |
231da177e4SLinus Torvalds * +---------+-------//---------+---+
241da177e4SLinus Torvalds *
251da177e4SLinus Torvalds * The physical disk space used by a fragment is taken from the start of
261da177e4SLinus Torvalds * the fragment id up to and including the '1' bit - ie, idlen + n + 1
271da177e4SLinus Torvalds * bits.
281da177e4SLinus Torvalds *
291da177e4SLinus Torvalds * A fragment id can be repeated multiple times in the whole map for
301da177e4SLinus Torvalds * large or fragmented files. The first map zone a fragment starts in
311da177e4SLinus Torvalds * is given by fragment id / ids_per_zone - this allows objects to start
321da177e4SLinus Torvalds * from any zone on the disk.
331da177e4SLinus Torvalds *
341da177e4SLinus Torvalds * Free space is described by a linked list of fragments. Each free
351da177e4SLinus Torvalds * fragment describes free space in the same way as the other fragments,
361da177e4SLinus Torvalds * however, the frag id specifies an offset (in map bits) from the end
371da177e4SLinus Torvalds * of this fragment to the start of the next free fragment.
381da177e4SLinus Torvalds *
391da177e4SLinus Torvalds * Objects stored on the disk are allocated object ids (we use these as
401da177e4SLinus Torvalds * our inode numbers.) Object ids contain a fragment id and an optional
411da177e4SLinus Torvalds * offset. This allows a directory fragment to contain small files
421da177e4SLinus Torvalds * associated with that directory.
431da177e4SLinus Torvalds */
441da177e4SLinus Torvalds
451da177e4SLinus Torvalds /*
461da177e4SLinus Torvalds * For the future...
471da177e4SLinus Torvalds */
481da177e4SLinus Torvalds static DEFINE_RWLOCK(adfs_map_lock);
491da177e4SLinus Torvalds
501da177e4SLinus Torvalds /*
511da177e4SLinus Torvalds * This is fun. We need to load up to 19 bits from the map at an
5225985edcSLucas De Marchi * arbitrary bit alignment. (We're limited to 19 bits by F+ version 2).
531da177e4SLinus Torvalds */
541da177e4SLinus Torvalds #define GET_FRAG_ID(_map,_start,_idmask) \
551da177e4SLinus Torvalds ({ \
561da177e4SLinus Torvalds unsigned char *_m = _map + (_start >> 3); \
57224c8866SAl Viro u32 _frag = get_unaligned_le32(_m); \
581da177e4SLinus Torvalds _frag >>= (_start & 7); \
591da177e4SLinus Torvalds _frag & _idmask; \
601da177e4SLinus Torvalds })
611da177e4SLinus Torvalds
621da177e4SLinus Torvalds /*
631da177e4SLinus Torvalds * return the map bit offset of the fragment frag_id in the zone dm.
641da177e4SLinus Torvalds * Note that the loop is optimised for best asm code - look at the
651da177e4SLinus Torvalds * output of:
661da177e4SLinus Torvalds * gcc -D__KERNEL__ -O2 -I../../include -o - -S map.c
671da177e4SLinus Torvalds */
lookup_zone(const struct adfs_discmap * dm,const unsigned int idlen,const u32 frag_id,unsigned int * offset)685ed70bb4SRussell King static int lookup_zone(const struct adfs_discmap *dm, const unsigned int idlen,
695ed70bb4SRussell King const u32 frag_id, unsigned int *offset)
701da177e4SLinus Torvalds {
71197ba3c5SRussell King const unsigned int endbit = dm->dm_endbit;
721da177e4SLinus Torvalds const u32 idmask = (1 << idlen) - 1;
73197ba3c5SRussell King unsigned char *map = dm->dm_bh->b_data;
741da177e4SLinus Torvalds unsigned int start = dm->dm_startbit;
75*f93793fdSRussell King unsigned int freelink, fragend;
761da177e4SLinus Torvalds u32 frag;
771da177e4SLinus Torvalds
78*f93793fdSRussell King frag = GET_FRAG_ID(map, 8, idmask & 0x7fff);
79*f93793fdSRussell King freelink = frag ? 8 + frag : 0;
80*f93793fdSRussell King
811da177e4SLinus Torvalds do {
821da177e4SLinus Torvalds frag = GET_FRAG_ID(map, start, idmask);
831da177e4SLinus Torvalds
84792314f8SRussell King fragend = find_next_bit_le(map, endbit, start + idlen);
85792314f8SRussell King if (fragend >= endbit)
861da177e4SLinus Torvalds goto error;
87792314f8SRussell King
88*f93793fdSRussell King if (start == freelink) {
89*f93793fdSRussell King freelink += frag & 0x7fff;
90*f93793fdSRussell King } else if (frag == frag_id) {
91792314f8SRussell King unsigned int length = fragend + 1 - start;
92792314f8SRussell King
93792314f8SRussell King if (*offset < length)
94792314f8SRussell King return start + *offset;
95792314f8SRussell King *offset -= length;
961da177e4SLinus Torvalds }
971da177e4SLinus Torvalds
98792314f8SRussell King start = fragend + 1;
99792314f8SRussell King } while (start < endbit);
1001da177e4SLinus Torvalds return -1;
1011da177e4SLinus Torvalds
1021da177e4SLinus Torvalds error:
1031da177e4SLinus Torvalds printk(KERN_ERR "adfs: oversized fragment 0x%x at 0x%x-0x%x\n",
104792314f8SRussell King frag, start, fragend);
1051da177e4SLinus Torvalds return -1;
1061da177e4SLinus Torvalds }
1071da177e4SLinus Torvalds
1081da177e4SLinus Torvalds /*
1091da177e4SLinus Torvalds * Scan the free space map, for this zone, calculating the total
1101da177e4SLinus Torvalds * number of map bits in each free space fragment.
1111da177e4SLinus Torvalds *
1121da177e4SLinus Torvalds * Note: idmask is limited to 15 bits [3.2]
1131da177e4SLinus Torvalds */
1141da177e4SLinus Torvalds static unsigned int
scan_free_map(struct adfs_sb_info * asb,struct adfs_discmap * dm)1151da177e4SLinus Torvalds scan_free_map(struct adfs_sb_info *asb, struct adfs_discmap *dm)
1161da177e4SLinus Torvalds {
117197ba3c5SRussell King const unsigned int endbit = dm->dm_endbit;
1181da177e4SLinus Torvalds const unsigned int idlen = asb->s_idlen;
1191da177e4SLinus Torvalds const unsigned int frag_idlen = idlen <= 15 ? idlen : 15;
1201da177e4SLinus Torvalds const u32 idmask = (1 << frag_idlen) - 1;
1211da177e4SLinus Torvalds unsigned char *map = dm->dm_bh->b_data;
122792314f8SRussell King unsigned int start = 8, fragend;
1231da177e4SLinus Torvalds u32 frag;
1241da177e4SLinus Torvalds unsigned long total = 0;
1251da177e4SLinus Torvalds
1261da177e4SLinus Torvalds /*
1271da177e4SLinus Torvalds * get fragment id
1281da177e4SLinus Torvalds */
1291da177e4SLinus Torvalds frag = GET_FRAG_ID(map, start, idmask);
1301da177e4SLinus Torvalds
1311da177e4SLinus Torvalds /*
1321da177e4SLinus Torvalds * If the freelink is null, then no free fragments
1331da177e4SLinus Torvalds * exist in this zone.
1341da177e4SLinus Torvalds */
1351da177e4SLinus Torvalds if (frag == 0)
1361da177e4SLinus Torvalds return 0;
1371da177e4SLinus Torvalds
1381da177e4SLinus Torvalds do {
1391da177e4SLinus Torvalds start += frag;
1401da177e4SLinus Torvalds
1411da177e4SLinus Torvalds frag = GET_FRAG_ID(map, start, idmask);
1421da177e4SLinus Torvalds
143792314f8SRussell King fragend = find_next_bit_le(map, endbit, start + idlen);
144792314f8SRussell King if (fragend >= endbit)
1451da177e4SLinus Torvalds goto error;
1461da177e4SLinus Torvalds
147792314f8SRussell King total += fragend + 1 - start;
1481da177e4SLinus Torvalds } while (frag >= idlen + 1);
1491da177e4SLinus Torvalds
1501da177e4SLinus Torvalds if (frag != 0)
1511da177e4SLinus Torvalds printk(KERN_ERR "adfs: undersized free fragment\n");
1521da177e4SLinus Torvalds
1531da177e4SLinus Torvalds return total;
1541da177e4SLinus Torvalds error:
1551da177e4SLinus Torvalds printk(KERN_ERR "adfs: oversized free fragment\n");
1561da177e4SLinus Torvalds return 0;
1571da177e4SLinus Torvalds }
1581da177e4SLinus Torvalds
scan_map(struct adfs_sb_info * asb,unsigned int zone,const u32 frag_id,unsigned int mapoff)1595ed70bb4SRussell King static int scan_map(struct adfs_sb_info *asb, unsigned int zone,
1605ed70bb4SRussell King const u32 frag_id, unsigned int mapoff)
1611da177e4SLinus Torvalds {
1621da177e4SLinus Torvalds const unsigned int idlen = asb->s_idlen;
1631da177e4SLinus Torvalds struct adfs_discmap *dm, *dm_end;
1641da177e4SLinus Torvalds int result;
1651da177e4SLinus Torvalds
1661da177e4SLinus Torvalds dm = asb->s_map + zone;
1671da177e4SLinus Torvalds zone = asb->s_map_size;
1681da177e4SLinus Torvalds dm_end = asb->s_map + zone;
1691da177e4SLinus Torvalds
1701da177e4SLinus Torvalds do {
1711da177e4SLinus Torvalds result = lookup_zone(dm, idlen, frag_id, &mapoff);
1721da177e4SLinus Torvalds
1731da177e4SLinus Torvalds if (result != -1)
1741da177e4SLinus Torvalds goto found;
1751da177e4SLinus Torvalds
1761da177e4SLinus Torvalds dm ++;
1771da177e4SLinus Torvalds if (dm == dm_end)
1781da177e4SLinus Torvalds dm = asb->s_map;
1791da177e4SLinus Torvalds } while (--zone > 0);
1801da177e4SLinus Torvalds
1811da177e4SLinus Torvalds return -1;
1821da177e4SLinus Torvalds found:
1831da177e4SLinus Torvalds result -= dm->dm_startbit;
1841da177e4SLinus Torvalds result += dm->dm_startblk;
1851da177e4SLinus Torvalds
1861da177e4SLinus Torvalds return result;
1871da177e4SLinus Torvalds }
1881da177e4SLinus Torvalds
1891da177e4SLinus Torvalds /*
1901da177e4SLinus Torvalds * calculate the amount of free blocks in the map.
1911da177e4SLinus Torvalds *
1921da177e4SLinus Torvalds * n=1
1931da177e4SLinus Torvalds * total_free = E(free_in_zone_n)
1941da177e4SLinus Torvalds * nzones
1951da177e4SLinus Torvalds */
adfs_map_statfs(struct super_block * sb,struct kstatfs * buf)196e6160e46SRussell King void adfs_map_statfs(struct super_block *sb, struct kstatfs *buf)
1971da177e4SLinus Torvalds {
1981da177e4SLinus Torvalds struct adfs_sb_info *asb = ADFS_SB(sb);
199e6160e46SRussell King struct adfs_discrecord *dr = adfs_map_discrecord(asb->s_map);
2001da177e4SLinus Torvalds struct adfs_discmap *dm;
2011da177e4SLinus Torvalds unsigned int total = 0;
2021da177e4SLinus Torvalds unsigned int zone;
2031da177e4SLinus Torvalds
2041da177e4SLinus Torvalds dm = asb->s_map;
2051da177e4SLinus Torvalds zone = asb->s_map_size;
2061da177e4SLinus Torvalds
2071da177e4SLinus Torvalds do {
2081da177e4SLinus Torvalds total += scan_free_map(asb, dm++);
2091da177e4SLinus Torvalds } while (--zone > 0);
2101da177e4SLinus Torvalds
211e6160e46SRussell King buf->f_blocks = adfs_disc_size(dr) >> sb->s_blocksize_bits;
212e6160e46SRussell King buf->f_files = asb->s_ids_per_zone * asb->s_map_size;
213e6160e46SRussell King buf->f_bavail =
214e6160e46SRussell King buf->f_bfree = signed_asl(total, asb->s_map2blk);
2151da177e4SLinus Torvalds }
2161da177e4SLinus Torvalds
adfs_map_lookup(struct super_block * sb,u32 frag_id,unsigned int offset)2175ed70bb4SRussell King int adfs_map_lookup(struct super_block *sb, u32 frag_id, unsigned int offset)
2181da177e4SLinus Torvalds {
2191da177e4SLinus Torvalds struct adfs_sb_info *asb = ADFS_SB(sb);
2201da177e4SLinus Torvalds unsigned int zone, mapoff;
2211da177e4SLinus Torvalds int result;
2221da177e4SLinus Torvalds
2231da177e4SLinus Torvalds /*
2241da177e4SLinus Torvalds * map & root fragment is special - it starts in the center of the
2251da177e4SLinus Torvalds * disk. The other fragments start at zone (frag / ids_per_zone)
2261da177e4SLinus Torvalds */
2271da177e4SLinus Torvalds if (frag_id == ADFS_ROOT_FRAG)
2281da177e4SLinus Torvalds zone = asb->s_map_size >> 1;
2291da177e4SLinus Torvalds else
2301da177e4SLinus Torvalds zone = frag_id / asb->s_ids_per_zone;
2311da177e4SLinus Torvalds
2321da177e4SLinus Torvalds if (zone >= asb->s_map_size)
2331da177e4SLinus Torvalds goto bad_fragment;
2341da177e4SLinus Torvalds
2351da177e4SLinus Torvalds /* Convert sector offset to map offset */
2361da177e4SLinus Torvalds mapoff = signed_asl(offset, -asb->s_map2blk);
2371da177e4SLinus Torvalds
2381da177e4SLinus Torvalds read_lock(&adfs_map_lock);
2391da177e4SLinus Torvalds result = scan_map(asb, zone, frag_id, mapoff);
2401da177e4SLinus Torvalds read_unlock(&adfs_map_lock);
2411da177e4SLinus Torvalds
2421da177e4SLinus Torvalds if (result > 0) {
2431da177e4SLinus Torvalds unsigned int secoff;
2441da177e4SLinus Torvalds
2451da177e4SLinus Torvalds /* Calculate sector offset into map block */
2461da177e4SLinus Torvalds secoff = offset - signed_asl(mapoff, asb->s_map2blk);
2471da177e4SLinus Torvalds return secoff + signed_asl(result, asb->s_map2blk);
2481da177e4SLinus Torvalds }
2491da177e4SLinus Torvalds
2501da177e4SLinus Torvalds adfs_error(sb, "fragment 0x%04x at offset %d not found in map",
2511da177e4SLinus Torvalds frag_id, offset);
2521da177e4SLinus Torvalds return 0;
2531da177e4SLinus Torvalds
2541da177e4SLinus Torvalds bad_fragment:
2551da177e4SLinus Torvalds adfs_error(sb, "invalid fragment 0x%04x (zone = %d, max = %d)",
2561da177e4SLinus Torvalds frag_id, zone, asb->s_map_size);
2571da177e4SLinus Torvalds return 0;
2581da177e4SLinus Torvalds }
259f75d398dSRussell King
adfs_calczonecheck(struct super_block * sb,unsigned char * map)260f75d398dSRussell King static unsigned char adfs_calczonecheck(struct super_block *sb, unsigned char *map)
261f75d398dSRussell King {
262f75d398dSRussell King unsigned int v0, v1, v2, v3;
263f75d398dSRussell King int i;
264f75d398dSRussell King
265f75d398dSRussell King v0 = v1 = v2 = v3 = 0;
266f75d398dSRussell King for (i = sb->s_blocksize - 4; i; i -= 4) {
267f75d398dSRussell King v0 += map[i] + (v3 >> 8);
268f75d398dSRussell King v3 &= 0xff;
269f75d398dSRussell King v1 += map[i + 1] + (v0 >> 8);
270f75d398dSRussell King v0 &= 0xff;
271f75d398dSRussell King v2 += map[i + 2] + (v1 >> 8);
272f75d398dSRussell King v1 &= 0xff;
273f75d398dSRussell King v3 += map[i + 3] + (v2 >> 8);
274f75d398dSRussell King v2 &= 0xff;
275f75d398dSRussell King }
276f75d398dSRussell King v0 += v3 >> 8;
277f75d398dSRussell King v1 += map[1] + (v0 >> 8);
278f75d398dSRussell King v2 += map[2] + (v1 >> 8);
279f75d398dSRussell King v3 += map[3] + (v2 >> 8);
280f75d398dSRussell King
281f75d398dSRussell King return v0 ^ v1 ^ v2 ^ v3;
282f75d398dSRussell King }
283f75d398dSRussell King
adfs_checkmap(struct super_block * sb,struct adfs_discmap * dm)284f75d398dSRussell King static int adfs_checkmap(struct super_block *sb, struct adfs_discmap *dm)
285f75d398dSRussell King {
286f75d398dSRussell King unsigned char crosscheck = 0, zonecheck = 1;
287f75d398dSRussell King int i;
288f75d398dSRussell King
289f75d398dSRussell King for (i = 0; i < ADFS_SB(sb)->s_map_size; i++) {
290f75d398dSRussell King unsigned char *map;
291f75d398dSRussell King
292f75d398dSRussell King map = dm[i].dm_bh->b_data;
293f75d398dSRussell King
294f75d398dSRussell King if (adfs_calczonecheck(sb, map) != map[0]) {
295f75d398dSRussell King adfs_error(sb, "zone %d fails zonecheck", i);
296f75d398dSRussell King zonecheck = 0;
297f75d398dSRussell King }
298f75d398dSRussell King crosscheck ^= map[3];
299f75d398dSRussell King }
300f75d398dSRussell King if (crosscheck != 0xff)
301f75d398dSRussell King adfs_error(sb, "crosscheck != 0xff");
302f75d398dSRussell King return crosscheck == 0xff && zonecheck;
303f75d398dSRussell King }
304f75d398dSRussell King
3056092b6beSRussell King /*
3066092b6beSRussell King * Layout the map - the first zone contains a copy of the disc record,
3076092b6beSRussell King * and the last zone must be limited to the size of the filesystem.
3086092b6beSRussell King */
adfs_map_layout(struct adfs_discmap * dm,unsigned int nzones,struct adfs_discrecord * dr)3096092b6beSRussell King static void adfs_map_layout(struct adfs_discmap *dm, unsigned int nzones,
3106092b6beSRussell King struct adfs_discrecord *dr)
3116092b6beSRussell King {
3126092b6beSRussell King unsigned int zone, zone_size;
3136092b6beSRussell King u64 size;
3146092b6beSRussell King
3156092b6beSRussell King zone_size = (8 << dr->log2secsize) - le16_to_cpu(dr->zone_spare);
3166092b6beSRussell King
3176092b6beSRussell King dm[0].dm_bh = NULL;
3186092b6beSRussell King dm[0].dm_startblk = 0;
319197ba3c5SRussell King dm[0].dm_startbit = 32 + ADFS_DR_SIZE_BITS;
320197ba3c5SRussell King dm[0].dm_endbit = 32 + zone_size;
3216092b6beSRussell King
3226092b6beSRussell King for (zone = 1; zone < nzones; zone++) {
3236092b6beSRussell King dm[zone].dm_bh = NULL;
3246092b6beSRussell King dm[zone].dm_startblk = zone * zone_size - ADFS_DR_SIZE_BITS;
325197ba3c5SRussell King dm[zone].dm_startbit = 32;
326197ba3c5SRussell King dm[zone].dm_endbit = 32 + zone_size;
3276092b6beSRussell King }
3286092b6beSRussell King
3296092b6beSRussell King size = adfs_disc_size(dr) >> dr->log2bpmb;
3306092b6beSRussell King size -= (nzones - 1) * zone_size - ADFS_DR_SIZE_BITS;
331197ba3c5SRussell King dm[nzones - 1].dm_endbit = 32 + size;
3326092b6beSRussell King }
3336092b6beSRussell King
adfs_map_read(struct adfs_discmap * dm,struct super_block * sb,unsigned int map_addr,unsigned int nzones)3346092b6beSRussell King static int adfs_map_read(struct adfs_discmap *dm, struct super_block *sb,
3356092b6beSRussell King unsigned int map_addr, unsigned int nzones)
3366092b6beSRussell King {
3376092b6beSRussell King unsigned int zone;
3386092b6beSRussell King
3396092b6beSRussell King for (zone = 0; zone < nzones; zone++) {
3406092b6beSRussell King dm[zone].dm_bh = sb_bread(sb, map_addr + zone);
3416092b6beSRussell King if (!dm[zone].dm_bh)
3426092b6beSRussell King return -EIO;
3436092b6beSRussell King }
3446092b6beSRussell King
3456092b6beSRussell King return 0;
3466092b6beSRussell King }
3476092b6beSRussell King
adfs_map_relse(struct adfs_discmap * dm,unsigned int nzones)3486092b6beSRussell King static void adfs_map_relse(struct adfs_discmap *dm, unsigned int nzones)
3496092b6beSRussell King {
3506092b6beSRussell King unsigned int zone;
3516092b6beSRussell King
3526092b6beSRussell King for (zone = 0; zone < nzones; zone++)
3536092b6beSRussell King brelse(dm[zone].dm_bh);
3546092b6beSRussell King }
3556092b6beSRussell King
adfs_read_map(struct super_block * sb,struct adfs_discrecord * dr)356f75d398dSRussell King struct adfs_discmap *adfs_read_map(struct super_block *sb, struct adfs_discrecord *dr)
357f75d398dSRussell King {
3586092b6beSRussell King struct adfs_sb_info *asb = ADFS_SB(sb);
359f75d398dSRussell King struct adfs_discmap *dm;
360f75d398dSRussell King unsigned int map_addr, zone_size, nzones;
3616092b6beSRussell King int ret;
362f75d398dSRussell King
363f6f14a0dSRussell King nzones = dr->nzones | dr->nzones_high << 8;
364f75d398dSRussell King zone_size = (8 << dr->log2secsize) - le16_to_cpu(dr->zone_spare);
365f6f14a0dSRussell King
366f6f14a0dSRussell King asb->s_idlen = dr->idlen;
367f6f14a0dSRussell King asb->s_map_size = nzones;
368f6f14a0dSRussell King asb->s_map2blk = dr->log2bpmb - dr->log2secsize;
369f6f14a0dSRussell King asb->s_log2sharesize = dr->log2sharesize;
370f6f14a0dSRussell King asb->s_ids_per_zone = zone_size / (asb->s_idlen + 1);
371f6f14a0dSRussell King
372f75d398dSRussell King map_addr = (nzones >> 1) * zone_size -
373f75d398dSRussell King ((nzones > 1) ? ADFS_DR_SIZE_BITS : 0);
374f75d398dSRussell King map_addr = signed_asl(map_addr, asb->s_map2blk);
375f75d398dSRussell King
376f75d398dSRussell King dm = kmalloc_array(nzones, sizeof(*dm), GFP_KERNEL);
377f75d398dSRussell King if (dm == NULL) {
378f75d398dSRussell King adfs_error(sb, "not enough memory");
379f75d398dSRussell King return ERR_PTR(-ENOMEM);
380f75d398dSRussell King }
381f75d398dSRussell King
3826092b6beSRussell King adfs_map_layout(dm, nzones, dr);
383f75d398dSRussell King
3846092b6beSRussell King ret = adfs_map_read(dm, sb, map_addr, nzones);
3856092b6beSRussell King if (ret) {
386f75d398dSRussell King adfs_error(sb, "unable to read map");
387f75d398dSRussell King goto error_free;
388f75d398dSRussell King }
389f75d398dSRussell King
390f75d398dSRussell King if (adfs_checkmap(sb, dm))
391f75d398dSRussell King return dm;
392f75d398dSRussell King
393f75d398dSRussell King adfs_error(sb, "map corrupted");
394f75d398dSRussell King
395f75d398dSRussell King error_free:
3966092b6beSRussell King adfs_map_relse(dm, nzones);
397f75d398dSRussell King kfree(dm);
398f75d398dSRussell King return ERR_PTR(-EIO);
399f75d398dSRussell King }
4007b195267SRussell King
adfs_free_map(struct super_block * sb)4017b195267SRussell King void adfs_free_map(struct super_block *sb)
4027b195267SRussell King {
4037b195267SRussell King struct adfs_sb_info *asb = ADFS_SB(sb);
4047b195267SRussell King
4057b195267SRussell King adfs_map_relse(asb->s_map, asb->s_map_size);
4067b195267SRussell King kfree(asb->s_map);
4077b195267SRussell King }
408