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

Linux Cross Reference
Linux/fs/cramfs/inode.c

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

  1 /*
  2  * Compressed rom filesystem for Linux.
  3  *
  4  * Copyright (C) 1999 Linus Torvalds.
  5  *
  6  * This file is released under the GPL.
  7  */
  8 
  9 /*
 10  * These are the VFS interfaces to the compressed rom filesystem.
 11  * The actual compression is based on zlib, see the other files.
 12  */
 13 
 14 #include <linux/module.h>
 15 #include <linux/fs.h>
 16 #include <linux/pagemap.h>
 17 #include <linux/init.h>
 18 #include <linux/string.h>
 19 #include <linux/locks.h>
 20 
 21 #include <asm/uaccess.h>
 22 
 23 #include "cramfs.h"
 24 
 25 static struct super_operations cramfs_ops;
 26 static struct inode_operations cramfs_dir_inode_operations;
 27 static struct file_operations cramfs_directory_operations;
 28 static struct address_space_operations cramfs_aops;
 29 
 30 /* These two macros may change in future, to provide better st_ino
 31    semantics. */
 32 #define CRAMINO(x)      ((x)->offset?(x)->offset<<2:1)
 33 #define OFFSET(x)       ((x)->i_ino)
 34 
 35 static struct inode *get_cramfs_inode(struct super_block *sb, struct cramfs_inode * cramfs_inode)
 36 {
 37         struct inode * inode = new_inode(sb);
 38 
 39         if (inode) {
 40                 inode->i_mode = cramfs_inode->mode;
 41                 inode->i_uid = cramfs_inode->uid;
 42                 inode->i_size = cramfs_inode->size;
 43                 inode->i_gid = cramfs_inode->gid;
 44                 inode->i_ino = CRAMINO(cramfs_inode);
 45                 /* inode->i_nlink is left 1 - arguably wrong for directories,
 46                    but it's the best we can do without reading the directory
 47                    contents.  1 yields the right result in GNU find, even
 48                    without -noleaf option. */
 49                 insert_inode_hash(inode);
 50                 if (S_ISREG(inode->i_mode)) {
 51                         inode->i_fop = &generic_ro_fops;
 52                         inode->i_data.a_ops = &cramfs_aops;
 53                 } else if (S_ISDIR(inode->i_mode)) {
 54                         inode->i_op = &cramfs_dir_inode_operations;
 55                         inode->i_fop = &cramfs_directory_operations;
 56                 } else if (S_ISLNK(inode->i_mode)) {
 57                         inode->i_op = &page_symlink_inode_operations;
 58                         inode->i_data.a_ops = &cramfs_aops;
 59                 } else {
 60                         inode->i_size = 0;
 61                         init_special_inode(inode, inode->i_mode, cramfs_inode->size);
 62                 }
 63         }
 64         return inode;
 65 }
 66 
 67 /*
 68  * We have our own block cache: don't fill up the buffer cache
 69  * with the rom-image, because the way the filesystem is set
 70  * up the accesses should be fairly regular and cached in the
 71  * page cache and dentry tree anyway..
 72  *
 73  * This also acts as a way to guarantee contiguous areas of up to
 74  * BLKS_PER_BUF*PAGE_CACHE_SIZE, so that the caller doesn't need to
 75  * worry about end-of-buffer issues even when decompressing a full
 76  * page cache.
 77  */
 78 #define READ_BUFFERS (2)
 79 /* NEXT_BUFFER(): Loop over [0..(READ_BUFFERS-1)]. */
 80 #define NEXT_BUFFER(_ix) ((_ix) ^ 1)
 81 
 82 /*
 83  * BLKS_PER_BUF_SHIFT should be at least 2 to allow for "compressed"
 84  * data that takes up more space than the original and with unlucky
 85  * alignment.
 86  */
 87 #define BLKS_PER_BUF_SHIFT      (2)
 88 #define BLKS_PER_BUF            (1 << BLKS_PER_BUF_SHIFT)
 89 #define BUFFER_SIZE             (BLKS_PER_BUF*PAGE_CACHE_SIZE)
 90 
 91 static unsigned char read_buffers[READ_BUFFERS][BUFFER_SIZE];
 92 static unsigned buffer_blocknr[READ_BUFFERS];
 93 static struct super_block * buffer_dev[READ_BUFFERS];
 94 static int next_buffer;
 95 
 96 /*
 97  * Returns a pointer to a buffer containing at least LEN bytes of
 98  * filesystem starting at byte offset OFFSET into the filesystem.
 99  */
100 static void *cramfs_read(struct super_block *sb, unsigned int offset, unsigned int len)
101 {
102         struct buffer_head * bh_array[BLKS_PER_BUF];
103         unsigned i, blocknr, buffer;
104         char *data;
105 
106         if (!len)
107                 return NULL;
108         blocknr = offset >> PAGE_CACHE_SHIFT;
109         offset &= PAGE_CACHE_SIZE - 1;
110 
111         /* Check if an existing buffer already has the data.. */
112         for (i = 0; i < READ_BUFFERS; i++) {
113                 unsigned int blk_offset;
114 
115                 if (buffer_dev[i] != sb)
116                         continue;
117                 if (blocknr < buffer_blocknr[i])
118                         continue;
119                 blk_offset = (blocknr - buffer_blocknr[i]) << PAGE_CACHE_SHIFT;
120                 blk_offset += offset;
121                 if (blk_offset + len > BUFFER_SIZE)
122                         continue;
123                 return read_buffers[i] + blk_offset;
124         }
125 
126         /* Ok, read in BLKS_PER_BUF pages completely first. */
127         for (i = 0; i < BLKS_PER_BUF; i++)
128                 bh_array[i] = bread(sb->s_dev, blocknr + i, PAGE_CACHE_SIZE);
129 
130         /* Ok, copy them to the staging area without sleeping. */
131         buffer = next_buffer;
132         next_buffer = NEXT_BUFFER(buffer);
133         buffer_blocknr[buffer] = blocknr;
134         buffer_dev[buffer] = sb;
135 
136         data = read_buffers[buffer];
137         for (i = 0; i < BLKS_PER_BUF; i++) {
138                 struct buffer_head * bh = bh_array[i];
139                 if (bh) {
140                         memcpy(data, bh->b_data, PAGE_CACHE_SIZE);
141                         bforget(bh);
142                 } else
143                         memset(data, 0, PAGE_CACHE_SIZE);
144                 data += PAGE_CACHE_SIZE;
145         }
146         return read_buffers[buffer] + offset;
147 }
148                         
149 
150 static struct super_block * cramfs_read_super(struct super_block *sb, void *data, int silent)
151 {
152         int i;
153         struct cramfs_super super;
154         unsigned long root_offset;
155         struct super_block * retval = NULL;
156 
157         set_blocksize(sb->s_dev, PAGE_CACHE_SIZE);
158         sb->s_blocksize = PAGE_CACHE_SIZE;
159         sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
160 
161         /* Invalidate the read buffers on mount: think disk change.. */
162         for (i = 0; i < READ_BUFFERS; i++)
163                 buffer_blocknr[i] = -1;
164 
165         /* Read the first block and get the superblock from it */
166         memcpy(&super, cramfs_read(sb, 0, sizeof(super)), sizeof(super));
167 
168         /* Do sanity checks on the superblock */
169         if (super.magic != CRAMFS_MAGIC) {
170                 printk("wrong magic\n");
171                 goto out;
172         }
173         if (memcmp(super.signature, CRAMFS_SIGNATURE, sizeof(super.signature))) {
174                 printk("wrong signature\n");
175                 goto out;
176         }
177         if (super.flags & ~CRAMFS_SUPPORTED_FLAGS) {
178                 printk("unsupported filesystem features\n");
179                 goto out;
180         }
181 
182         /* Check that the root inode is in a sane state */
183         if (!S_ISDIR(super.root.mode)) {
184                 printk("root is not a directory\n");
185                 goto out;
186         }
187         root_offset = super.root.offset << 2;
188         if (root_offset == 0)
189                 printk(KERN_INFO "cramfs: note: empty filesystem");
190         else if (root_offset != sizeof(struct cramfs_super)) {
191                 printk("bad root offset %lu\n", root_offset);
192                 goto out;
193         }
194 
195         /* Set it all up.. */
196         sb->s_op        = &cramfs_ops;
197         sb->s_root = d_alloc_root(get_cramfs_inode(sb, &super.root));
198         retval = sb;
199 
200 out:
201         return retval;
202 }
203 
204 static int cramfs_statfs(struct super_block *sb, struct statfs *buf)
205 {
206         buf->f_type = CRAMFS_MAGIC;
207         buf->f_bsize = PAGE_CACHE_SIZE;
208         buf->f_bfree = 0;
209         buf->f_bavail = 0;
210         buf->f_ffree = 0;
211         buf->f_namelen = 255;
212         return 0;
213 }
214 
215 /*
216  * Read a cramfs directory entry.
217  */
218 static int cramfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
219 {
220         struct inode *inode = filp->f_dentry->d_inode;
221         struct super_block *sb = inode->i_sb;
222         unsigned int offset;
223         int copied;
224 
225         /* Offset within the thing. */
226         offset = filp->f_pos;
227         if (offset >= inode->i_size)
228                 return 0;
229         /* Directory entries are always 4-byte aligned */
230         if (offset & 3)
231                 return -EINVAL;
232 
233         copied = 0;
234         while (offset < inode->i_size) {
235                 struct cramfs_inode *de;
236                 unsigned long nextoffset;
237                 char *name;
238                 int namelen, error;
239 
240                 de = cramfs_read(sb, OFFSET(inode) + offset, sizeof(*de)+256);
241                 name = (char *)(de+1);
242 
243                 /*
244                  * Namelengths on disk are shifted by two
245                  * and the name padded out to 4-byte boundaries
246                  * with zeroes.
247                  */
248                 namelen = de->namelen << 2;
249                 nextoffset = offset + sizeof(*de) + namelen;
250                 for (;;) {
251                         if (!namelen)
252                                 return -EIO;
253                         if (name[namelen-1])
254                                 break;
255                         namelen--;
256                 }
257                 error = filldir(dirent, name, namelen, offset, CRAMINO(de), de->mode >> 12);
258                 if (error)
259                         break;
260 
261                 offset = nextoffset;
262                 filp->f_pos = offset;
263                 copied++;
264         }
265         return 0;
266 }
267 
268 /*
269  * Lookup and fill in the inode data..
270  */
271 static struct dentry * cramfs_lookup(struct inode *dir, struct dentry *dentry)
272 {
273         unsigned int offset = 0;
274 
275         while (offset < dir->i_size) {
276                 struct cramfs_inode *de;
277                 char *name;
278                 int namelen;
279 
280                 de = cramfs_read(dir->i_sb, OFFSET(dir) + offset, sizeof(*de)+256);
281                 name = (char *)(de+1);
282                 namelen = de->namelen << 2;
283                 offset += sizeof(*de) + namelen;
284 
285                 /* Quick check that the name is roughly the right length */
286                 if (((dentry->d_name.len + 3) & ~3) != namelen)
287                         continue;
288 
289                 for (;;) {
290                         if (!namelen)
291                                 return ERR_PTR(-EIO);
292                         if (name[namelen-1])
293                                 break;
294                         namelen--;
295                 }
296                 if (namelen != dentry->d_name.len)
297                         continue;
298                 if (memcmp(dentry->d_name.name, name, namelen))
299                         continue;
300                 d_add(dentry, get_cramfs_inode(dir->i_sb, de));
301                 return NULL;
302         }
303         d_add(dentry, NULL);
304         return NULL;
305 }
306 
307 static int cramfs_readpage(struct file *file, struct page * page)
308 {
309         struct inode *inode = page->mapping->host;
310         u32 maxblock, bytes_filled;
311 
312         maxblock = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
313         bytes_filled = 0;
314         if (page->index < maxblock) {
315                 struct super_block *sb = inode->i_sb;
316                 u32 blkptr_offset = OFFSET(inode) + page->index*4;
317                 u32 start_offset, compr_len;
318 
319                 start_offset = OFFSET(inode) + maxblock*4;
320                 if (page->index)
321                         start_offset = *(u32 *) cramfs_read(sb, blkptr_offset-4, 4);
322                 compr_len = (*(u32 *) cramfs_read(sb, blkptr_offset, 4)
323                              - start_offset);
324                 if (compr_len == 0)
325                         ; /* hole */
326                 else
327                         bytes_filled = cramfs_uncompress_block(page_address(page),
328                                  PAGE_CACHE_SIZE,
329                                  cramfs_read(sb, start_offset, compr_len),
330                                  compr_len);
331         }
332         memset(page_address(page) + bytes_filled, 0, PAGE_CACHE_SIZE - bytes_filled);
333         flush_dcache_page(page);
334         SetPageUptodate(page);
335         UnlockPage(page);
336         return 0;
337 }
338 
339 static struct address_space_operations cramfs_aops = {
340         readpage: cramfs_readpage
341 };
342 
343 /*
344  * Our operations:
345  */
346 
347 /*
348  * A directory can only readdir
349  */
350 static struct file_operations cramfs_directory_operations = {
351         read:           generic_read_dir,
352         readdir:        cramfs_readdir,
353 };
354 
355 static struct inode_operations cramfs_dir_inode_operations = {
356         lookup:         cramfs_lookup,
357 };
358 
359 static struct super_operations cramfs_ops = {
360         statfs:         cramfs_statfs,
361 };
362 
363 static DECLARE_FSTYPE_DEV(cramfs_fs_type, "cramfs", cramfs_read_super);
364 
365 static int __init init_cramfs_fs(void)
366 {
367         cramfs_uncompress_init();
368         return register_filesystem(&cramfs_fs_type);
369 }
370 
371 static void __exit exit_cramfs_fs(void)
372 {
373         cramfs_uncompress_exit();
374         unregister_filesystem(&cramfs_fs_type);
375 }
376 
377 module_init(init_cramfs_fs)
378 module_exit(exit_cramfs_fs)
379 

~ [ 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.