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
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.