~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/fs/adfs/map.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  *  linux/fs/adfs/map.c
  3  *
  4  *  Copyright (C) 1997-1999 Russell King
  5  *
  6  * This program is free software; you can redistribute it and/or modify
  7  * it under the terms of the GNU General Public License version 2 as
  8  * published by the Free Software Foundation.
  9  */
 10 #include <linux/version.h>
 11 #include <linux/errno.h>
 12 #include <linux/fs.h>
 13 #include <linux/adfs_fs.h>
 14 #include <linux/spinlock.h>
 15 
 16 #include "adfs.h"
 17 
 18 /*
 19  * For the future...
 20  */
 21 static rwlock_t adfs_map_lock;
 22 
 23 /*
 24  * return the map bit offset of the fragment frag_id in
 25  * the zone dm.
 26  * Note that the loop is optimised for best asm code -
 27  * look at the output of:
 28  *  gcc -D__KERNEL__ -O2 -I../../include -o - -S map.c
 29  */
 30 static int
 31 lookup_zone(const struct adfs_discmap *dm, const unsigned int idlen,
 32             const unsigned int frag_id, unsigned int *offset)
 33 {
 34         const unsigned int mapsize = dm->dm_endbit;
 35         const unsigned int idmask = (1 << idlen) - 1;
 36         unsigned long *map = ((unsigned long *)dm->dm_bh->b_data) + 1;
 37         unsigned int start = dm->dm_startbit;
 38         unsigned int mapptr;
 39 
 40         do {
 41                 unsigned long frag;
 42 
 43                 /*
 44                  * get fragment id
 45                  */
 46                 {
 47                         unsigned long v2;
 48                         unsigned int tmp;
 49 
 50                         tmp = start >> 5;
 51 
 52                         frag = le32_to_cpu(map[tmp]);
 53                         v2   = le32_to_cpu(map[tmp + 1]);
 54 
 55                         tmp  = start & 31;
 56 
 57                         frag = (frag >> tmp) | (v2 << (32 - tmp));
 58 
 59                         frag &= idmask;
 60                 }
 61 
 62                 mapptr = start + idlen;
 63 
 64                 /*
 65                  * find end of fragment
 66                  */
 67                 {
 68                         unsigned long v2;
 69 
 70                         while ((v2 = map[mapptr >> 5] >> (mapptr & 31)) == 0) {
 71                                 mapptr = (mapptr & ~31) + 32;
 72                                 if (mapptr >= mapsize)
 73                                         goto error;
 74                         }
 75 
 76                         mapptr += 1 + ffz(~v2);
 77                 }
 78 
 79                 if (frag == frag_id)
 80                         goto found;
 81 again:
 82                 start = mapptr;
 83         } while (mapptr < mapsize);
 84 
 85 error:
 86         return -1;
 87 
 88 found:
 89         {
 90                 int length = mapptr - start;
 91                 if (*offset >= length) {
 92                         *offset -= length;
 93                         goto again;
 94                 }
 95         }
 96         return start + *offset;
 97 }
 98 
 99 /*
100  * Scan the free space map, for this zone, calculating the total
101  * number of map bits in each free space fragment.
102  *
103  * Note: idmask is limited to 15 bits [3.2]
104  */
105 static unsigned int
106 scan_free_map(struct adfs_sb_info *asb, struct adfs_discmap *dm)
107 {
108         const unsigned int mapsize = dm->dm_endbit + 32;
109         const unsigned int idlen  = asb->s_idlen;
110         const unsigned int frag_idlen = idlen <= 15 ? idlen : 15;
111         const unsigned int idmask = (1 << frag_idlen) - 1;
112         unsigned long *map = (unsigned long *)dm->dm_bh->b_data;
113         unsigned int start = 8, mapptr;
114         unsigned long frag;
115         unsigned long total = 0;
116 
117         /*
118          * get fragment id
119          */
120         {
121                 unsigned long v2;
122                 unsigned int tmp;
123 
124                 tmp = start >> 5;
125 
126                 frag = le32_to_cpu(map[tmp]);
127                 v2   = le32_to_cpu(map[tmp + 1]);
128 
129                 tmp  = start & 31;
130 
131                 frag = (frag >> tmp) | (v2 << (32 - tmp));
132 
133                 frag &= idmask;
134         }
135 
136         /*
137          * If the freelink is null, then no free fragments
138          * exist in this zone.
139          */
140         if (frag == 0)
141                 return 0;
142 
143         do {
144                 start += frag;
145 
146                 /*
147                  * get fragment id
148                  */
149                 {
150                         unsigned long v2;
151                         unsigned int tmp;
152 
153                         tmp = start >> 5;
154 
155                         frag = le32_to_cpu(map[tmp]);
156                         v2   = le32_to_cpu(map[tmp + 1]);
157 
158                         tmp  = start & 31;
159 
160                         frag = (frag >> tmp) | (v2 << (32 - tmp));
161 
162                         frag &= idmask;
163                 }
164 
165                 mapptr = start + idlen;
166 
167                 /*
168                  * find end of fragment
169                  */
170                 {
171                         unsigned long v2;
172 
173                         while ((v2 = map[mapptr >> 5] >> (mapptr & 31)) == 0) {
174                                 mapptr = (mapptr & ~31) + 32;
175                                 if (mapptr >= mapsize)
176                                         goto error;
177                         }
178 
179                         mapptr += 1 + ffz(~v2);
180                 }
181 
182                 total += mapptr - start;
183         } while (frag >= idlen + 1);
184 
185         if (frag != 0)
186                 printk(KERN_ERR "adfs: undersized free fragment\n");
187 
188         return total;
189 error:
190         printk(KERN_ERR "adfs: oversized free fragment\n");
191         return 0;
192 }
193 
194 static int
195 scan_map(struct adfs_sb_info *asb, unsigned int zone,
196          const unsigned int frag_id, unsigned int mapoff)
197 {
198         const unsigned int idlen = asb->s_idlen;
199         struct adfs_discmap *dm, *dm_end;
200         int result;
201 
202         dm      = asb->s_map + zone;
203         zone    = asb->s_map_size;
204         dm_end  = asb->s_map + zone;
205 
206         do {
207                 result = lookup_zone(dm, idlen, frag_id, &mapoff);
208 
209                 if (result != -1)
210                         goto found;
211 
212                 dm ++;
213                 if (dm == dm_end)
214                         dm = asb->s_map;
215         } while (--zone > 0);
216 
217         return -1;
218 found:
219         result -= dm->dm_startbit;
220         result += dm->dm_startblk;
221 
222         return result;
223 }
224 
225 /*
226  * calculate the amount of free blocks in the map.
227  *
228  *              n=1
229  *  total_free = E(free_in_zone_n)
230  *              nzones
231  */
232 unsigned int
233 adfs_map_free(struct super_block *sb)
234 {
235         struct adfs_sb_info *asb = &sb->u.adfs_sb;
236         struct adfs_discmap *dm;
237         unsigned int total = 0;
238         unsigned int zone;
239 
240         dm   = asb->s_map;
241         zone = asb->s_map_size;
242 
243         do {
244                 total += scan_free_map(asb, dm++);
245         } while (--zone > 0);
246 
247         return signed_asl(total, asb->s_map2blk);
248 }
249 
250 int adfs_map_lookup (struct super_block *sb, int frag_id, int offset)
251 {
252         struct adfs_sb_info *asb = &sb->u.adfs_sb;
253         unsigned int zone, mapoff;
254         int result;
255 
256         /*
257          * map & root fragment is special - it starts in the center of the
258          * disk.  The other fragments start at zone (frag / ids_per_zone)
259          */
260         if (frag_id == ADFS_ROOT_FRAG)
261                 zone = asb->s_map_size >> 1;
262         else
263                 zone = frag_id / asb->s_ids_per_zone;
264 
265         if (zone >= asb->s_map_size)
266                 goto bad_fragment;
267 
268         /* Convert sector offset to map offset */
269         mapoff = signed_asl(offset, -asb->s_map2blk);
270 
271         read_lock(&adfs_map_lock);
272         result = scan_map(asb, zone, frag_id, mapoff);
273         read_unlock(&adfs_map_lock);
274 
275         if (result > 0) {
276                 unsigned int secoff;
277 
278                 /* Calculate sector offset into map block */
279                 secoff = offset - signed_asl(mapoff, asb->s_map2blk);
280                 return secoff + signed_asl(result, asb->s_map2blk);
281         }
282 
283         adfs_error(sb, "fragment %04X at offset %d not found in map",
284                    frag_id, offset);
285         return 0;
286 
287 bad_fragment:
288         adfs_error(sb, "fragment %X is invalid (zone = %d, max = %d)",
289                    frag_id, zone, asb->s_map_size);
290         return 0;
291 }
292 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.