aboutsummaryrefslogtreecommitdiffstats
path: root/fs/omfs
diff options
context:
space:
mode:
Diffstat (limited to 'fs/omfs')
-rw-r--r--fs/omfs/Makefile4
-rw-r--r--fs/omfs/bitmap.c192
-rw-r--r--fs/omfs/dir.c504
-rw-r--r--fs/omfs/file.c346
-rw-r--r--fs/omfs/inode.c553
-rw-r--r--fs/omfs/omfs.h67
-rw-r--r--fs/omfs/omfs_fs.h80
7 files changed, 1746 insertions, 0 deletions
diff --git a/fs/omfs/Makefile b/fs/omfs/Makefile
new file mode 100644
index 000000000000..8b82b63f1129
--- /dev/null
+++ b/fs/omfs/Makefile
@@ -0,0 +1,4 @@
1
2obj-$(CONFIG_OMFS_FS) += omfs.o
3
4omfs-y := bitmap.o dir.o file.o inode.o
diff --git a/fs/omfs/bitmap.c b/fs/omfs/bitmap.c
new file mode 100644
index 000000000000..dc75f22be3f2
--- /dev/null
+++ b/fs/omfs/bitmap.c
@@ -0,0 +1,192 @@
1#include <linux/kernel.h>
2#include <linux/fs.h>
3#include <linux/buffer_head.h>
4#include <asm/div64.h>
5#include "omfs.h"
6
7unsigned long omfs_count_free(struct super_block *sb)
8{
9 unsigned int i;
10 unsigned long sum = 0;
11 struct omfs_sb_info *sbi = OMFS_SB(sb);
12 int nbits = sb->s_blocksize * 8;
13
14 for (i = 0; i < sbi->s_imap_size; i++)
15 sum += nbits - bitmap_weight(sbi->s_imap[i], nbits);
16
17 return sum;
18}
19
20/*
21 * Counts the run of zero bits starting at bit up to max.
22 * It handles the case where a run might spill over a buffer.
23 * Called with bitmap lock.
24 */
25static int count_run(unsigned long **addr, int nbits,
26 int addrlen, int bit, int max)
27{
28 int count = 0;
29 int x;
30
31 for (; addrlen > 0; addrlen--, addr++) {
32 x = find_next_bit(*addr, nbits, bit);
33 count += x - bit;
34
35 if (x < nbits || count > max)
36 return min(count, max);
37
38 bit = 0;
39 }
40 return min(count, max);
41}
42
43/*
44 * Sets or clears the run of count bits starting with bit.
45 * Called with bitmap lock.
46 */
47static int set_run(struct super_block *sb, int map,
48 int nbits, int bit, int count, int set)
49{
50 int i;
51 int err;
52 struct buffer_head *bh;
53 struct omfs_sb_info *sbi = OMFS_SB(sb);
54
55 err = -ENOMEM;
56 bh = sb_bread(sb, clus_to_blk(sbi, sbi->s_bitmap_ino) + map);
57 if (!bh)
58 goto out;
59
60 for (i = 0; i < count; i++, bit++) {
61 if (bit >= nbits) {
62 bit = 0;
63 map++;
64
65 mark_buffer_dirty(bh);
66 brelse(bh);
67 bh = sb_bread(sb,
68 clus_to_blk(sbi, sbi->s_bitmap_ino) + map);
69 if (!bh)
70 goto out;
71 }
72 if (set) {
73 set_bit(bit, sbi->s_imap[map]);
74 set_bit(bit, (long *) bh->b_data);
75 } else {
76 clear_bit(bit, sbi->s_imap[map]);
77 clear_bit(bit, (long *) bh->b_data);
78 }
79 }
80 mark_buffer_dirty(bh);
81 brelse(bh);
82 err = 0;
83out:
84 return err;
85}
86
87/*
88 * Tries to allocate exactly one block. Returns true if sucessful.
89 */
90int omfs_allocate_block(struct super_block *sb, u64 block)
91{
92 struct buffer_head *bh;
93 struct omfs_sb_info *sbi = OMFS_SB(sb);
94 int bits_per_entry = 8 * sb->s_blocksize;
95 int map, bit;
96 int ret = 0;
97 u64 tmp;
98
99 tmp = block;
100 bit = do_div(tmp, bits_per_entry);
101 map = tmp;
102
103 mutex_lock(&sbi->s_bitmap_lock);
104 if (map >= sbi->s_imap_size || test_and_set_bit(bit, sbi->s_imap[map]))
105 goto out;
106
107 if (sbi->s_bitmap_ino > 0) {
108 bh = sb_bread(sb, clus_to_blk(sbi, sbi->s_bitmap_ino) + map);
109 if (!bh)
110 goto out;
111
112 set_bit(bit, (long *) bh->b_data);
113 mark_buffer_dirty(bh);
114 brelse(bh);
115 }
116 ret = 1;
117out:
118 mutex_unlock(&sbi->s_bitmap_lock);
119 return ret;
120}
121
122
123/*
124 * Tries to allocate a set of blocks. The request size depends on the
125 * type: for inodes, we must allocate sbi->s_mirrors blocks, and for file
126 * blocks, we try to allocate sbi->s_clustersize, but can always get away
127 * with just one block.
128 */
129int omfs_allocate_range(struct super_block *sb,
130 int min_request,
131 int max_request,
132 u64 *return_block,
133 int *return_size)
134{
135 struct omfs_sb_info *sbi = OMFS_SB(sb);
136 int bits_per_entry = 8 * sb->s_blocksize;
137 int ret = 0;
138 int i, run, bit;
139
140 mutex_lock(&sbi->s_bitmap_lock);
141 for (i = 0; i < sbi->s_imap_size; i++) {
142 bit = 0;
143 while (bit < bits_per_entry) {
144 bit = find_next_zero_bit(sbi->s_imap[i], bits_per_entry,
145 bit);
146
147 if (bit == bits_per_entry)
148 break;
149
150 run = count_run(&sbi->s_imap[i], bits_per_entry,
151 sbi->s_imap_size-i, bit, max_request);
152
153 if (run >= min_request)
154 goto found;
155 bit += run;
156 }
157 }
158 ret = -ENOSPC;
159 goto out;
160
161found:
162 *return_block = i * bits_per_entry + bit;
163 *return_size = run;
164 ret = set_run(sb, i, bits_per_entry, bit, run, 1);
165
166out:
167 mutex_unlock(&sbi->s_bitmap_lock);
168 return ret;
169}
170
171/*
172 * Clears count bits starting at a given block.
173 */
174int omfs_clear_range(struct super_block *sb, u64 block, int count)
175{
176 struct omfs_sb_info *sbi = OMFS_SB(sb);
177 int bits_per_entry = 8 * sb->s_blocksize;
178 u64 tmp;
179 int map, bit, ret;
180
181 tmp = block;
182 bit = do_div(tmp, bits_per_entry);
183 map = tmp;
184
185 if (map >= sbi->s_imap_size)
186 return 0;
187
188 mutex_lock(&sbi->s_bitmap_lock);
189 ret = set_run(sb, map, bits_per_entry, bit, count, 0);
190 mutex_unlock(&sbi->s_bitmap_lock);
191 return ret;
192}
diff --git a/fs/omfs/dir.c b/fs/omfs/dir.c
new file mode 100644
index 000000000000..05a5bc31e4bd
--- /dev/null
+++ b/fs/omfs/dir.c
@@ -0,0 +1,504 @@
1/*
2 * OMFS (as used by RIO Karma) directory operations.
3 * Copyright (C) 2005 Bob Copeland <me@bobcopeland.com>
4 * Released under GPL v2.
5 */
6
7#include <linux/fs.h>
8#include <linux/ctype.h>
9#include <linux/buffer_head.h>
10#include "omfs.h"
11
12static int omfs_hash(const char *name, int namelen, int mod)
13{
14 int i, hash = 0;
15 for (i = 0; i < namelen; i++)
16 hash ^= tolower(name[i]) << (i % 24);
17 return hash % mod;
18}
19
20/*
21 * Finds the bucket for a given name and reads the containing block;
22 * *ofs is set to the offset of the first list entry.
23 */
24static struct buffer_head *omfs_get_bucket(struct inode *dir,
25 const char *name, int namelen, int *ofs)
26{
27 int nbuckets = (dir->i_size - OMFS_DIR_START)/8;
28 int block = clus_to_blk(OMFS_SB(dir->i_sb), dir->i_ino);
29 int bucket = omfs_hash(name, namelen, nbuckets);
30
31 *ofs = OMFS_DIR_START + bucket * 8;
32 return sb_bread(dir->i_sb, block);
33}
34
35static struct buffer_head *omfs_scan_list(struct inode *dir, u64 block,
36 const char *name, int namelen,
37 u64 *prev_block)
38{
39 struct buffer_head *bh;
40 struct omfs_inode *oi;
41 int err = -ENOENT;
42 *prev_block = ~0;
43
44 while (block != ~0) {
45 bh = sb_bread(dir->i_sb,
46 clus_to_blk(OMFS_SB(dir->i_sb), block));
47 if (!bh) {
48 err = -EIO;
49 goto err;
50 }
51
52 oi = (struct omfs_inode *) bh->b_data;
53 if (omfs_is_bad(OMFS_SB(dir->i_sb), &oi->i_head, block)) {
54 brelse(bh);
55 goto err;
56 }
57
58 if (strncmp(oi->i_name, name, namelen) == 0)
59 return bh;
60
61 *prev_block = block;
62 block = be64_to_cpu(oi->i_sibling);
63 brelse(bh);
64 }
65err:
66 return ERR_PTR(err);
67}
68
69static struct buffer_head *omfs_find_entry(struct inode *dir,
70 const char *name, int namelen)
71{
72 struct buffer_head *bh;
73 int ofs;
74 u64 block, dummy;
75
76 bh = omfs_get_bucket(dir, name, namelen, &ofs);
77 if (!bh)
78 return ERR_PTR(-EIO);
79
80 block = be64_to_cpu(*((__be64 *) &bh->b_data[ofs]));
81 brelse(bh);
82
83 return omfs_scan_list(dir, block, name, namelen, &dummy);
84}
85
86int omfs_make_empty(struct inode *inode, struct super_block *sb)
87{
88 struct omfs_sb_info *sbi = OMFS_SB(sb);
89 int block = clus_to_blk(sbi, inode->i_ino);
90 struct buffer_head *bh;
91 struct omfs_inode *oi;
92
93 bh = sb_bread(sb, block);
94 if (!bh)
95 return -ENOMEM;
96
97 memset(bh->b_data, 0, sizeof(struct omfs_inode));
98
99 if (inode->i_mode & S_IFDIR) {
100 memset(&bh->b_data[OMFS_DIR_START], 0xff,
101 sbi->s_sys_blocksize - OMFS_DIR_START);
102 } else
103 omfs_make_empty_table(bh, OMFS_EXTENT_START);
104
105 oi = (struct omfs_inode *) bh->b_data;
106 oi->i_head.h_self = cpu_to_be64(inode->i_ino);
107 oi->i_sibling = ~0ULL;
108
109 mark_buffer_dirty(bh);
110 brelse(bh);
111 return 0;
112}
113
114static int omfs_add_link(struct dentry *dentry, struct inode *inode)
115{
116 struct inode *dir = dentry->d_parent->d_inode;
117 const char *name = dentry->d_name.name;
118 int namelen = dentry->d_name.len;
119 struct omfs_inode *oi;
120 struct buffer_head *bh;
121 u64 block;
122 __be64 *entry;
123 int ofs;
124
125 /* just prepend to head of queue in proper bucket */
126 bh = omfs_get_bucket(dir, name, namelen, &ofs);
127 if (!bh)
128 goto out;
129
130 entry = (__be64 *) &bh->b_data[ofs];
131 block = be64_to_cpu(*entry);
132 *entry = cpu_to_be64(inode->i_ino);
133 mark_buffer_dirty(bh);
134 brelse(bh);
135
136 /* now set the sibling and parent pointers on the new inode */
137 bh = sb_bread(dir->i_sb, clus_to_blk(OMFS_SB(dir->i_sb), inode->i_ino));
138 if (!bh)
139 goto out;
140
141 oi = (struct omfs_inode *) bh->b_data;
142 memcpy(oi->i_name, name, namelen);
143 memset(oi->i_name + namelen, 0, OMFS_NAMELEN - namelen);
144 oi->i_sibling = cpu_to_be64(block);
145 oi->i_parent = cpu_to_be64(dir->i_ino);
146 mark_buffer_dirty(bh);
147 brelse(bh);
148
149 dir->i_ctime = CURRENT_TIME_SEC;
150
151 /* mark affected inodes dirty to rebuild checksums */
152 mark_inode_dirty(dir);
153 mark_inode_dirty(inode);
154 return 0;
155out:
156 return -ENOMEM;
157}
158
159static int omfs_delete_entry(struct dentry *dentry)
160{
161 struct inode *dir = dentry->d_parent->d_inode;
162 struct inode *dirty;
163 const char *name = dentry->d_name.name;
164 int namelen = dentry->d_name.len;
165 struct omfs_inode *oi;
166 struct buffer_head *bh, *bh2;
167 __be64 *entry, next;
168 u64 block, prev;
169 int ofs;
170 int err = -ENOMEM;
171
172 /* delete the proper node in the bucket's linked list */
173 bh = omfs_get_bucket(dir, name, namelen, &ofs);
174 if (!bh)
175 goto out;
176
177 entry = (__be64 *) &bh->b_data[ofs];
178 block = be64_to_cpu(*entry);
179
180 bh2 = omfs_scan_list(dir, block, name, namelen, &prev);
181 if (IS_ERR(bh2)) {
182 err = PTR_ERR(bh2);
183 goto out_free_bh;
184 }
185
186 oi = (struct omfs_inode *) bh2->b_data;
187 next = oi->i_sibling;
188 brelse(bh2);
189
190 if (prev != ~0) {
191 /* found in middle of list, get list ptr */
192 brelse(bh);
193 bh = sb_bread(dir->i_sb,
194 clus_to_blk(OMFS_SB(dir->i_sb), prev));
195 if (!bh)
196 goto out;
197
198 oi = (struct omfs_inode *) bh->b_data;
199 entry = &oi->i_sibling;
200 }
201
202 *entry = next;
203 mark_buffer_dirty(bh);
204
205 if (prev != ~0) {
206 dirty = omfs_iget(dir->i_sb, prev);
207 if (!IS_ERR(dirty)) {
208 mark_inode_dirty(dirty);
209 iput(dirty);
210 }
211 }
212
213 err = 0;
214out_free_bh:
215 brelse(bh);
216out:
217 return err;
218}
219
220static int omfs_dir_is_empty(struct inode *inode)
221{
222 int nbuckets = (inode->i_size - OMFS_DIR_START) / 8;
223 struct buffer_head *bh;
224 u64 *ptr;
225 int i;
226
227 bh = sb_bread(inode->i_sb, clus_to_blk(OMFS_SB(inode->i_sb),
228 inode->i_ino));
229
230 if (!bh)
231 return 0;
232
233 ptr = (u64 *) &bh->b_data[OMFS_DIR_START];
234
235 for (i = 0; i < nbuckets; i++, ptr++)
236 if (*ptr != ~0)
237 break;
238
239 brelse(bh);
240 return *ptr != ~0;
241}
242
243static int omfs_unlink(struct inode *dir, struct dentry *dentry)
244{
245 int ret;
246 struct inode *inode = dentry->d_inode;
247
248 ret = omfs_delete_entry(dentry);
249 if (ret)
250 goto end_unlink;
251
252 inode_dec_link_count(inode);
253 mark_inode_dirty(dir);
254
255end_unlink:
256 return ret;
257}
258
259static int omfs_rmdir(struct inode *dir, struct dentry *dentry)
260{
261 int err = -ENOTEMPTY;
262 struct inode *inode = dentry->d_inode;
263
264 if (omfs_dir_is_empty(inode)) {
265 err = omfs_unlink(dir, dentry);
266 if (!err)
267 inode_dec_link_count(inode);
268 }
269 return err;
270}
271
272static int omfs_add_node(struct inode *dir, struct dentry *dentry, int mode)
273{
274 int err;
275 struct inode *inode = omfs_new_inode(dir, mode);
276
277 if (IS_ERR(inode))
278 return PTR_ERR(inode);
279
280 err = omfs_make_empty(inode, dir->i_sb);
281 if (err)
282 goto out_free_inode;
283
284 err = omfs_add_link(dentry, inode);
285 if (err)
286 goto out_free_inode;
287
288 d_instantiate(dentry, inode);
289 return 0;
290
291out_free_inode:
292 iput(inode);
293 return err;
294}
295
296static int omfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
297{
298 return omfs_add_node(dir, dentry, mode | S_IFDIR);
299}
300
301static int omfs_create(struct inode *dir, struct dentry *dentry, int mode,
302 struct nameidata *nd)
303{
304 return omfs_add_node(dir, dentry, mode | S_IFREG);
305}
306
307static struct dentry *omfs_lookup(struct inode *dir, struct dentry *dentry,
308 struct nameidata *nd)
309{
310 struct buffer_head *bh;
311 struct inode *inode = NULL;
312
313 if (dentry->d_name.len > OMFS_NAMELEN)
314 return ERR_PTR(-ENAMETOOLONG);
315
316 bh = omfs_find_entry(dir, dentry->d_name.name, dentry->d_name.len);
317 if (!IS_ERR(bh)) {
318 struct omfs_inode *oi = (struct omfs_inode *)bh->b_data;
319 ino_t ino = be64_to_cpu(oi->i_head.h_self);
320 brelse(bh);
321 inode = omfs_iget(dir->i_sb, ino);
322 if (IS_ERR(inode))
323 return ERR_CAST(inode);
324 }
325 d_add(dentry, inode);
326 return NULL;
327}
328
329/* sanity check block's self pointer */
330int omfs_is_bad(struct omfs_sb_info *sbi, struct omfs_header *header,
331 u64 fsblock)
332{
333 int is_bad;
334 u64 ino = be64_to_cpu(header->h_self);
335 is_bad = ((ino != fsblock) || (ino < sbi->s_root_ino) ||
336 (ino > sbi->s_num_blocks));
337
338 if (is_bad)
339 printk(KERN_WARNING "omfs: bad hash chain detected\n");
340
341 return is_bad;
342}
343
344static int omfs_fill_chain(struct file *filp, void *dirent, filldir_t filldir,
345 u64 fsblock, int hindex)
346{
347 struct inode *dir = filp->f_dentry->d_inode;
348 struct buffer_head *bh;
349 struct omfs_inode *oi;
350 u64 self;
351 int res = 0;
352 unsigned char d_type;
353
354 /* follow chain in this bucket */
355 while (fsblock != ~0) {
356 bh = sb_bread(dir->i_sb, clus_to_blk(OMFS_SB(dir->i_sb),
357 fsblock));
358 if (!bh)
359 goto out;
360
361 oi = (struct omfs_inode *) bh->b_data;
362 if (omfs_is_bad(OMFS_SB(dir->i_sb), &oi->i_head, fsblock)) {
363 brelse(bh);
364 goto out;
365 }
366
367 self = fsblock;
368 fsblock = be64_to_cpu(oi->i_sibling);
369
370 /* skip visited nodes */
371 if (hindex) {
372 hindex--;
373 brelse(bh);
374 continue;
375 }
376
377 d_type = (oi->i_type == OMFS_DIR) ? DT_DIR : DT_REG;
378
379 res = filldir(dirent, oi->i_name, strnlen(oi->i_name,
380 OMFS_NAMELEN), filp->f_pos, self, d_type);
381 if (res == 0)
382 filp->f_pos++;
383 brelse(bh);
384 }
385out:
386 return res;
387}
388
389static int omfs_rename(struct inode *old_dir, struct dentry *old_dentry,
390 struct inode *new_dir, struct dentry *new_dentry)
391{
392 struct inode *new_inode = new_dentry->d_inode;
393 struct inode *old_inode = old_dentry->d_inode;
394 struct buffer_head *bh;
395 int is_dir;
396 int err;
397
398 is_dir = S_ISDIR(old_inode->i_mode);
399
400 if (new_inode) {
401 /* overwriting existing file/dir */
402 err = -ENOTEMPTY;
403 if (is_dir && !omfs_dir_is_empty(new_inode))
404 goto out;
405
406 err = -ENOENT;
407 bh = omfs_find_entry(new_dir, new_dentry->d_name.name,
408 new_dentry->d_name.len);
409 if (IS_ERR(bh))
410 goto out;
411 brelse(bh);
412
413 err = omfs_unlink(new_dir, new_dentry);
414 if (err)
415 goto out;
416 }
417
418 /* since omfs locates files by name, we need to unlink _before_
419 * adding the new link or we won't find the old one */
420 inode_inc_link_count(old_inode);
421 err = omfs_unlink(old_dir, old_dentry);
422 if (err) {
423 inode_dec_link_count(old_inode);
424 goto out;
425 }
426
427 err = omfs_add_link(new_dentry, old_inode);
428 if (err)
429 goto out;
430
431 old_inode->i_ctime = CURRENT_TIME_SEC;
432out:
433 return err;
434}
435
436static int omfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
437{
438 struct inode *dir = filp->f_dentry->d_inode;
439 struct buffer_head *bh;
440 loff_t offset, res;
441 unsigned int hchain, hindex;
442 int nbuckets;
443 u64 fsblock;
444 int ret = -EINVAL;
445
446 if (filp->f_pos >> 32)
447 goto success;
448
449 switch ((unsigned long) filp->f_pos) {
450 case 0:
451 if (filldir(dirent, ".", 1, 0, dir->i_ino, DT_DIR) < 0)
452 goto success;
453 filp->f_pos++;
454 /* fall through */
455 case 1:
456 if (filldir(dirent, "..", 2, 1,
457 parent_ino(filp->f_dentry), DT_DIR) < 0)
458 goto success;
459 filp->f_pos = 1 << 20;
460 /* fall through */
461 }
462
463 nbuckets = (dir->i_size - OMFS_DIR_START) / 8;
464
465 /* high 12 bits store bucket + 1 and low 20 bits store hash index */
466 hchain = (filp->f_pos >> 20) - 1;
467 hindex = filp->f_pos & 0xfffff;
468
469 bh = sb_bread(dir->i_sb, clus_to_blk(OMFS_SB(dir->i_sb), dir->i_ino));
470 if (!bh)
471 goto out;
472
473 offset = OMFS_DIR_START + hchain * 8;
474
475 for (; hchain < nbuckets; hchain++, offset += 8) {
476 fsblock = be64_to_cpu(*((__be64 *) &bh->b_data[offset]));
477
478 res = omfs_fill_chain(filp, dirent, filldir, fsblock, hindex);
479 hindex = 0;
480 if (res < 0)
481 break;
482
483 filp->f_pos = (hchain+2) << 20;
484 }
485 brelse(bh);
486success:
487 ret = 0;
488out:
489 return ret;
490}
491
492struct inode_operations omfs_dir_inops = {
493 .lookup = omfs_lookup,
494 .mkdir = omfs_mkdir,
495 .rename = omfs_rename,
496 .create = omfs_create,
497 .unlink = omfs_unlink,
498 .rmdir = omfs_rmdir,
499};
500
501struct file_operations omfs_dir_operations = {
502 .read = generic_read_dir,
503 .readdir = omfs_readdir,
504};
diff --git a/fs/omfs/file.c b/fs/omfs/file.c
new file mode 100644
index 000000000000..66e01fae4384
--- /dev/null
+++ b/fs/omfs/file.c
@@ -0,0 +1,346 @@
1/*
2 * OMFS (as used by RIO Karma) file operations.
3 * Copyright (C) 2005 Bob Copeland <me@bobcopeland.com>
4 * Released under GPL v2.
5 */
6
7#include <linux/version.h>
8#include <linux/module.h>
9#include <linux/fs.h>
10#include <linux/buffer_head.h>
11#include <linux/mpage.h>
12#include "omfs.h"
13
14static int omfs_sync_file(struct file *file, struct dentry *dentry,
15 int datasync)
16{
17 struct inode *inode = dentry->d_inode;
18 int err;
19
20 err = sync_mapping_buffers(inode->i_mapping);
21 if (!(inode->i_state & I_DIRTY))
22 return err;
23 if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
24 return err;
25 err |= omfs_sync_inode(inode);
26 return err ? -EIO : 0;
27}
28
29void omfs_make_empty_table(struct buffer_head *bh, int offset)
30{
31 struct omfs_extent *oe = (struct omfs_extent *) &bh->b_data[offset];
32
33 oe->e_next = ~0ULL;
34 oe->e_extent_count = cpu_to_be32(1),
35 oe->e_fill = cpu_to_be32(0x22),
36 oe->e_entry.e_cluster = ~0ULL;
37 oe->e_entry.e_blocks = ~0ULL;
38}
39
40int omfs_shrink_inode(struct inode *inode)
41{
42 struct omfs_sb_info *sbi = OMFS_SB(inode->i_sb);
43 struct omfs_extent *oe;
44 struct omfs_extent_entry *entry;
45 struct buffer_head *bh;
46 u64 next, last;
47 u32 extent_count;
48 int ret;
49
50 /* traverse extent table, freeing each entry that is greater
51 * than inode->i_size;
52 */
53 next = inode->i_ino;
54
55 /* only support truncate -> 0 for now */
56 ret = -EIO;
57 if (inode->i_size != 0)
58 goto out;
59
60 bh = sb_bread(inode->i_sb, clus_to_blk(sbi, next));
61 if (!bh)
62 goto out;
63
64 oe = (struct omfs_extent *)(&bh->b_data[OMFS_EXTENT_START]);
65
66 for (;;) {
67
68 if (omfs_is_bad(sbi, (struct omfs_header *) bh->b_data, next)) {
69 brelse(bh);
70 goto out;
71 }
72
73 extent_count = be32_to_cpu(oe->e_extent_count);
74 last = next;
75 next = be64_to_cpu(oe->e_next);
76 entry = &oe->e_entry;
77
78 /* ignore last entry as it is the terminator */
79 for (; extent_count > 1; extent_count--) {
80 u64 start, count;
81 start = be64_to_cpu(entry->e_cluster);
82 count = be64_to_cpu(entry->e_blocks);
83
84 omfs_clear_range(inode->i_sb, start, (int) count);
85 entry++;
86 }
87 omfs_make_empty_table(bh, (char *) oe - bh->b_data);
88 mark_buffer_dirty(bh);
89 brelse(bh);
90
91 if (last != inode->i_ino)
92 omfs_clear_range(inode->i_sb, last, sbi->s_mirrors);
93
94 if (next == ~0)
95 break;
96
97 bh = sb_bread(inode->i_sb, clus_to_blk(sbi, next));
98 if (!bh)
99 goto out;
100 oe = (struct omfs_extent *) (&bh->b_data[OMFS_EXTENT_CONT]);
101 }
102 ret = 0;
103out:
104 return ret;
105}
106
107static void omfs_truncate(struct inode *inode)
108{
109 omfs_shrink_inode(inode);
110 mark_inode_dirty(inode);
111}
112
113/*
114 * Add new blocks to the current extent, or create new entries/continuations
115 * as necessary.
116 */
117static int omfs_grow_extent(struct inode *inode, struct omfs_extent *oe,
118 u64 *ret_block)
119{
120 struct omfs_extent_entry *terminator;
121 struct omfs_extent_entry *entry = &oe->e_entry;
122 struct omfs_sb_info *sbi = OMFS_SB(inode->i_sb);
123 u32 extent_count = be32_to_cpu(oe->e_extent_count);
124 u64 new_block = 0;
125 u32 max_count;
126 int new_count;
127 int ret = 0;
128
129 /* reached the end of the extent table with no blocks mapped.
130 * there are three possibilities for adding: grow last extent,
131 * add a new extent to the current extent table, and add a
132 * continuation inode. in last two cases need an allocator for
133 * sbi->s_cluster_size
134 */
135
136 /* TODO: handle holes */
137
138 /* should always have a terminator */
139 if (extent_count < 1)
140 return -EIO;
141
142 /* trivially grow current extent, if next block is not taken */
143 terminator = entry + extent_count - 1;
144 if (extent_count > 1) {
145 entry = terminator-1;
146 new_block = be64_to_cpu(entry->e_cluster) +
147 be64_to_cpu(entry->e_blocks);
148
149 if (omfs_allocate_block(inode->i_sb, new_block)) {
150 entry->e_blocks =
151 cpu_to_be64(be64_to_cpu(entry->e_blocks) + 1);
152 terminator->e_blocks = ~(cpu_to_be64(
153 be64_to_cpu(~terminator->e_blocks) + 1));
154 goto out;
155 }
156 }
157 max_count = (sbi->s_sys_blocksize - OMFS_EXTENT_START -
158 sizeof(struct omfs_extent)) /
159 sizeof(struct omfs_extent_entry) + 1;
160
161 /* TODO: add a continuation block here */
162 if (be32_to_cpu(oe->e_extent_count) > max_count-1)
163 return -EIO;
164
165 /* try to allocate a new cluster */
166 ret = omfs_allocate_range(inode->i_sb, 1, sbi->s_clustersize,
167 &new_block, &new_count);
168 if (ret)
169 goto out_fail;
170
171 /* copy terminator down an entry */
172 entry = terminator;
173 terminator++;
174 memcpy(terminator, entry, sizeof(struct omfs_extent_entry));
175
176 entry->e_cluster = cpu_to_be64(new_block);
177 entry->e_blocks = cpu_to_be64((u64) new_count);
178
179 terminator->e_blocks = ~(cpu_to_be64(
180 be64_to_cpu(~terminator->e_blocks) + (u64) new_count));
181
182 /* write in new entry */
183 oe->e_extent_count = cpu_to_be32(1 + be32_to_cpu(oe->e_extent_count));
184
185out:
186 *ret_block = new_block;
187out_fail:
188 return ret;
189}
190
191/*
192 * Scans across the directory table for a given file block number.
193 * If block not found, return 0.
194 */
195static sector_t find_block(struct inode *inode, struct omfs_extent_entry *ent,
196 sector_t block, int count, int *left)
197{
198 /* count > 1 because of terminator */
199 sector_t searched = 0;
200 for (; count > 1; count--) {
201 int numblocks = clus_to_blk(OMFS_SB(inode->i_sb),
202 be64_to_cpu(ent->e_blocks));
203
204 if (block >= searched &&
205 block < searched + numblocks) {
206 /*
207 * found it at cluster + (block - searched)
208 * numblocks - (block - searched) is remainder
209 */
210 *left = numblocks - (block - searched);
211 return clus_to_blk(OMFS_SB(inode->i_sb),
212 be64_to_cpu(ent->e_cluster)) +
213 block - searched;
214 }
215 searched += numblocks;
216 ent++;
217 }
218 return 0;
219}
220
221static int omfs_get_block(struct inode *inode, sector_t block,
222 struct buffer_head *bh_result, int create)
223{
224 struct buffer_head *bh;
225 sector_t next, offset;
226 int ret;
227 u64 new_block;
228 int extent_count;
229 struct omfs_extent *oe;
230 struct omfs_extent_entry *entry;
231 struct omfs_sb_info *sbi = OMFS_SB(inode->i_sb);
232 int max_blocks = bh_result->b_size >> inode->i_blkbits;
233 int remain;
234
235 ret = -EIO;
236 bh = sb_bread(inode->i_sb, clus_to_blk(sbi, inode->i_ino));
237 if (!bh)
238 goto out;
239
240 oe = (struct omfs_extent *)(&bh->b_data[OMFS_EXTENT_START]);
241 next = inode->i_ino;
242
243 for (;;) {
244
245 if (omfs_is_bad(sbi, (struct omfs_header *) bh->b_data, next))
246 goto out_brelse;
247
248 extent_count = be32_to_cpu(oe->e_extent_count);
249 next = be64_to_cpu(oe->e_next);
250 entry = &oe->e_entry;
251
252 offset = find_block(inode, entry, block, extent_count, &remain);
253 if (offset > 0) {
254 ret = 0;
255 map_bh(bh_result, inode->i_sb, offset);
256 if (remain > max_blocks)
257 remain = max_blocks;
258 bh_result->b_size = (remain << inode->i_blkbits);
259 goto out_brelse;
260 }
261 if (next == ~0)
262 break;
263
264 brelse(bh);
265 bh = sb_bread(inode->i_sb, clus_to_blk(sbi, next));
266 if (!bh)
267 goto out;
268 oe = (struct omfs_extent *) (&bh->b_data[OMFS_EXTENT_CONT]);
269 }
270 if (create) {
271 ret = omfs_grow_extent(inode, oe, &new_block);
272 if (ret == 0) {
273 mark_buffer_dirty(bh);
274 mark_inode_dirty(inode);
275 map_bh(bh_result, inode->i_sb,
276 clus_to_blk(sbi, new_block));
277 }
278 }
279out_brelse:
280 brelse(bh);
281out:
282 return ret;
283}
284
285static int omfs_readpage(struct file *file, struct page *page)
286{
287 return block_read_full_page(page, omfs_get_block);
288}
289
290static int omfs_readpages(struct file *file, struct address_space *mapping,
291 struct list_head *pages, unsigned nr_pages)
292{
293 return mpage_readpages(mapping, pages, nr_pages, omfs_get_block);
294}
295
296static int omfs_writepage(struct page *page, struct writeback_control *wbc)
297{
298 return block_write_full_page(page, omfs_get_block, wbc);
299}
300
301static int
302omfs_writepages(struct address_space *mapping, struct writeback_control *wbc)
303{
304 return mpage_writepages(mapping, wbc, omfs_get_block);
305}
306
307static int omfs_write_begin(struct file *file, struct address_space *mapping,
308 loff_t pos, unsigned len, unsigned flags,
309 struct page **pagep, void **fsdata)
310{
311 *pagep = NULL;
312 return block_write_begin(file, mapping, pos, len, flags,
313 pagep, fsdata, omfs_get_block);
314}
315
316static sector_t omfs_bmap(struct address_space *mapping, sector_t block)
317{
318 return generic_block_bmap(mapping, block, omfs_get_block);
319}
320
321struct file_operations omfs_file_operations = {
322 .llseek = generic_file_llseek,
323 .read = do_sync_read,
324 .write = do_sync_write,
325 .aio_read = generic_file_aio_read,
326 .aio_write = generic_file_aio_write,
327 .mmap = generic_file_mmap,
328 .fsync = omfs_sync_file,
329 .splice_read = generic_file_splice_read,
330};
331
332struct inode_operations omfs_file_inops = {
333 .truncate = omfs_truncate
334};
335
336struct address_space_operations omfs_aops = {
337 .readpage = omfs_readpage,
338 .readpages = omfs_readpages,
339 .writepage = omfs_writepage,
340 .writepages = omfs_writepages,
341 .sync_page = block_sync_page,
342 .write_begin = omfs_write_begin,
343 .write_end = generic_write_end,
344 .bmap = omfs_bmap,
345};
346
diff --git a/fs/omfs/inode.c b/fs/omfs/inode.c
new file mode 100644
index 000000000000..d865f5535436
--- /dev/null
+++ b/fs/omfs/inode.c
@@ -0,0 +1,553 @@
1/*
2 * Optimized MPEG FS - inode and super operations.
3 * Copyright (C) 2006 Bob Copeland <me@bobcopeland.com>
4 * Released under GPL v2.
5 */
6#include <linux/version.h>
7#include <linux/module.h>
8#include <linux/sched.h>
9#include <linux/fs.h>
10#include <linux/vfs.h>
11#include <linux/parser.h>
12#include <linux/buffer_head.h>
13#include <linux/vmalloc.h>
14#include <linux/crc-itu-t.h>
15#include "omfs.h"
16
17MODULE_AUTHOR("Bob Copeland <me@bobcopeland.com>");
18MODULE_DESCRIPTION("OMFS (ReplayTV/Karma) Filesystem for Linux");
19MODULE_LICENSE("GPL");
20
21struct inode *omfs_new_inode(struct inode *dir, int mode)
22{
23 struct inode *inode;
24 u64 new_block;
25 int err;
26 int len;
27 struct omfs_sb_info *sbi = OMFS_SB(dir->i_sb);
28
29 inode = new_inode(dir->i_sb);
30 if (!inode)
31 return ERR_PTR(-ENOMEM);
32
33 err = omfs_allocate_range(dir->i_sb, sbi->s_mirrors, sbi->s_mirrors,
34 &new_block, &len);
35 if (err)
36 goto fail;
37
38 inode->i_ino = new_block;
39 inode->i_mode = mode;
40 inode->i_uid = current->fsuid;
41 inode->i_gid = current->fsgid;
42 inode->i_blocks = 0;
43 inode->i_mapping->a_ops = &omfs_aops;
44
45 inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
46 switch (mode & S_IFMT) {
47 case S_IFDIR:
48 inode->i_op = &omfs_dir_inops;
49 inode->i_fop = &omfs_dir_operations;
50 inode->i_size = sbi->s_sys_blocksize;
51 inc_nlink(inode);
52 break;
53 case S_IFREG:
54 inode->i_op = &omfs_file_inops;
55 inode->i_fop = &omfs_file_operations;
56 inode->i_size = 0;
57 break;
58 }
59
60 insert_inode_hash(inode);
61 mark_inode_dirty(inode);
62 return inode;
63fail:
64 make_bad_inode(inode);
65 iput(inode);
66 return ERR_PTR(err);
67}
68
69/*
70 * Update the header checksums for a dirty inode based on its contents.
71 * Caller is expected to hold the buffer head underlying oi and mark it
72 * dirty.
73 */
74static void omfs_update_checksums(struct omfs_inode *oi)
75{
76 int xor, i, ofs = 0, count;
77 u16 crc = 0;
78 unsigned char *ptr = (unsigned char *) oi;
79
80 count = be32_to_cpu(oi->i_head.h_body_size);
81 ofs = sizeof(struct omfs_header);
82
83 crc = crc_itu_t(crc, ptr + ofs, count);
84 oi->i_head.h_crc = cpu_to_be16(crc);
85
86 xor = ptr[0];
87 for (i = 1; i < OMFS_XOR_COUNT; i++)
88 xor ^= ptr[i];
89
90 oi->i_head.h_check_xor = xor;
91}
92
93static int omfs_write_inode(struct inode *inode, int wait)
94{
95 struct omfs_inode *oi;
96 struct omfs_sb_info *sbi = OMFS_SB(inode->i_sb);
97 struct buffer_head *bh, *bh2;
98 unsigned int block;
99 u64 ctime;
100 int i;
101 int ret = -EIO;
102 int sync_failed = 0;
103
104 /* get current inode since we may have written sibling ptrs etc. */
105 block = clus_to_blk(sbi, inode->i_ino);
106 bh = sb_bread(inode->i_sb, block);
107 if (!bh)
108 goto out;
109
110 oi = (struct omfs_inode *) bh->b_data;
111
112 oi->i_head.h_self = cpu_to_be64(inode->i_ino);
113 if (S_ISDIR(inode->i_mode))
114 oi->i_type = OMFS_DIR;
115 else if (S_ISREG(inode->i_mode))
116 oi->i_type = OMFS_FILE;
117 else {
118 printk(KERN_WARNING "omfs: unknown file type: %d\n",
119 inode->i_mode);
120 goto out_brelse;
121 }
122
123 oi->i_head.h_body_size = cpu_to_be32(sbi->s_sys_blocksize -
124 sizeof(struct omfs_header));
125 oi->i_head.h_version = 1;
126 oi->i_head.h_type = OMFS_INODE_NORMAL;
127 oi->i_head.h_magic = OMFS_IMAGIC;
128 oi->i_size = cpu_to_be64(inode->i_size);
129
130 ctime = inode->i_ctime.tv_sec * 1000LL +
131 ((inode->i_ctime.tv_nsec + 999)/1000);
132 oi->i_ctime = cpu_to_be64(ctime);
133
134 omfs_update_checksums(oi);
135
136 mark_buffer_dirty(bh);
137 if (wait) {
138 sync_dirty_buffer(bh);
139 if (buffer_req(bh) && !buffer_uptodate(bh))
140 sync_failed = 1;
141 }
142
143 /* if mirroring writes, copy to next fsblock */
144 for (i = 1; i < sbi->s_mirrors; i++) {
145 bh2 = sb_bread(inode->i_sb, block + i *
146 (sbi->s_blocksize / sbi->s_sys_blocksize));
147 if (!bh2)
148 goto out_brelse;
149
150 memcpy(bh2->b_data, bh->b_data, bh->b_size);
151 mark_buffer_dirty(bh2);
152 if (wait) {
153 sync_dirty_buffer(bh2);
154 if (buffer_req(bh2) && !buffer_uptodate(bh2))
155 sync_failed = 1;
156 }
157 brelse(bh2);
158 }
159 ret = (sync_failed) ? -EIO : 0;
160out_brelse:
161 brelse(bh);
162out:
163 return ret;
164}
165
166int omfs_sync_inode(struct inode *inode)
167{
168 return omfs_write_inode(inode, 1);
169}
170
171/*
172 * called when an entry is deleted, need to clear the bits in the
173 * bitmaps.
174 */
175static void omfs_delete_inode(struct inode *inode)
176{
177 truncate_inode_pages(&inode->i_data, 0);
178
179 if (S_ISREG(inode->i_mode)) {
180 inode->i_size = 0;
181 omfs_shrink_inode(inode);
182 }
183
184 omfs_clear_range(inode->i_sb, inode->i_ino, 2);
185 clear_inode(inode);
186}
187
188struct inode *omfs_iget(struct super_block *sb, ino_t ino)
189{
190 struct omfs_sb_info *sbi = OMFS_SB(sb);
191 struct omfs_inode *oi;
192 struct buffer_head *bh;
193 unsigned int block;
194 u64 ctime;
195 unsigned long nsecs;
196 struct inode *inode;
197
198 inode = iget_locked(sb, ino);
199 if (!inode)
200 return ERR_PTR(-ENOMEM);
201 if (!(inode->i_state & I_NEW))
202 return inode;
203
204 block = clus_to_blk(sbi, ino);
205 bh = sb_bread(inode->i_sb, block);
206 if (!bh)
207 goto iget_failed;
208
209 oi = (struct omfs_inode *)bh->b_data;
210
211 /* check self */
212 if (ino != be64_to_cpu(oi->i_head.h_self))
213 goto fail_bh;
214
215 inode->i_uid = sbi->s_uid;
216 inode->i_gid = sbi->s_gid;
217
218 ctime = be64_to_cpu(oi->i_ctime);
219 nsecs = do_div(ctime, 1000) * 1000L;
220
221 inode->i_atime.tv_sec = ctime;
222 inode->i_mtime.tv_sec = ctime;
223 inode->i_ctime.tv_sec = ctime;
224 inode->i_atime.tv_nsec = nsecs;
225 inode->i_mtime.tv_nsec = nsecs;
226 inode->i_ctime.tv_nsec = nsecs;
227
228 inode->i_mapping->a_ops = &omfs_aops;
229
230 switch (oi->i_type) {
231 case OMFS_DIR:
232 inode->i_mode = S_IFDIR | (S_IRWXUGO & ~sbi->s_dmask);
233 inode->i_op = &omfs_dir_inops;
234 inode->i_fop = &omfs_dir_operations;
235 inode->i_size = be32_to_cpu(oi->i_head.h_body_size) +
236 sizeof(struct omfs_header);
237 inc_nlink(inode);
238 break;
239 case OMFS_FILE:
240 inode->i_mode = S_IFREG | (S_IRWXUGO & ~sbi->s_fmask);
241 inode->i_fop = &omfs_file_operations;
242 inode->i_size = be64_to_cpu(oi->i_size);
243 break;
244 }
245 brelse(bh);
246 unlock_new_inode(inode);
247 return inode;
248fail_bh:
249 brelse(bh);
250iget_failed:
251 iget_failed(inode);
252 return ERR_PTR(-EIO);
253}
254
255static void omfs_put_super(struct super_block *sb)
256{
257 struct omfs_sb_info *sbi = OMFS_SB(sb);
258 kfree(sbi->s_imap);
259 kfree(sbi);
260 sb->s_fs_info = NULL;
261}
262
263static int omfs_statfs(struct dentry *dentry, struct kstatfs *buf)
264{
265 struct super_block *s = dentry->d_sb;
266 struct omfs_sb_info *sbi = OMFS_SB(s);
267 buf->f_type = OMFS_MAGIC;
268 buf->f_bsize = sbi->s_blocksize;
269 buf->f_blocks = sbi->s_num_blocks;
270 buf->f_files = sbi->s_num_blocks;
271 buf->f_namelen = OMFS_NAMELEN;
272
273 buf->f_bfree = buf->f_bavail = buf->f_ffree =
274 omfs_count_free(s);
275 return 0;
276}
277
278static struct super_operations omfs_sops = {
279 .write_inode = omfs_write_inode,
280 .delete_inode = omfs_delete_inode,
281 .put_super = omfs_put_super,
282 .statfs = omfs_statfs,
283 .show_options = generic_show_options,
284};
285
286/*
287 * For Rio Karma, there is an on-disk free bitmap whose location is
288 * stored in the root block. For ReplayTV, there is no such free bitmap
289 * so we have to walk the tree. Both inodes and file data are allocated
290 * from the same map. This array can be big (300k) so we allocate
291 * in units of the blocksize.
292 */
293static int omfs_get_imap(struct super_block *sb)
294{
295 int bitmap_size;
296 int array_size;
297 int count;
298 struct omfs_sb_info *sbi = OMFS_SB(sb);
299 struct buffer_head *bh;
300 unsigned long **ptr;
301 sector_t block;
302
303 bitmap_size = DIV_ROUND_UP(sbi->s_num_blocks, 8);
304 array_size = DIV_ROUND_UP(bitmap_size, sb->s_blocksize);
305
306 if (sbi->s_bitmap_ino == ~0ULL)
307 goto out;
308
309 sbi->s_imap_size = array_size;
310 sbi->s_imap = kzalloc(array_size * sizeof(unsigned long *), GFP_KERNEL);
311 if (!sbi->s_imap)
312 goto nomem;
313
314 block = clus_to_blk(sbi, sbi->s_bitmap_ino);
315 ptr = sbi->s_imap;
316 for (count = bitmap_size; count > 0; count -= sb->s_blocksize) {
317 bh = sb_bread(sb, block++);
318 if (!bh)
319 goto nomem_free;
320 *ptr = kmalloc(sb->s_blocksize, GFP_KERNEL);
321 if (!*ptr) {
322 brelse(bh);
323 goto nomem_free;
324 }
325 memcpy(*ptr, bh->b_data, sb->s_blocksize);
326 if (count < sb->s_blocksize)
327 memset((void *)*ptr + count, 0xff,
328 sb->s_blocksize - count);
329 brelse(bh);
330 ptr++;
331 }
332out:
333 return 0;
334
335nomem_free:
336 for (count = 0; count < array_size; count++)
337 kfree(sbi->s_imap[count]);
338
339 kfree(sbi->s_imap);
340nomem:
341 sbi->s_imap = NULL;
342 sbi->s_imap_size = 0;
343 return -ENOMEM;
344}
345
346enum {
347 Opt_uid, Opt_gid, Opt_umask, Opt_dmask, Opt_fmask
348};
349
350static match_table_t tokens = {
351 {Opt_uid, "uid=%u"},
352 {Opt_gid, "gid=%u"},
353 {Opt_umask, "umask=%o"},
354 {Opt_dmask, "dmask=%o"},
355 {Opt_fmask, "fmask=%o"},
356};
357
358static int parse_options(char *options, struct omfs_sb_info *sbi)
359{
360 char *p;
361 substring_t args[MAX_OPT_ARGS];
362 int option;
363
364 if (!options)
365 return 1;
366
367 while ((p = strsep(&options, ",")) != NULL) {
368 int token;
369 if (!*p)
370 continue;
371
372 token = match_token(p, tokens, args);
373 switch (token) {
374 case Opt_uid:
375 if (match_int(&args[0], &option))
376 return 0;
377 sbi->s_uid = option;
378 break;
379 case Opt_gid:
380 if (match_int(&args[0], &option))
381 return 0;
382 sbi->s_gid = option;
383 break;
384 case Opt_umask:
385 if (match_octal(&args[0], &option))
386 return 0;
387 sbi->s_fmask = sbi->s_dmask = option;
388 break;
389 case Opt_dmask:
390 if (match_octal(&args[0], &option))
391 return 0;
392 sbi->s_dmask = option;
393 break;
394 case Opt_fmask:
395 if (match_octal(&args[0], &option))
396 return 0;
397 sbi->s_fmask = option;
398 break;
399 default:
400 return 0;
401 }
402 }
403 return 1;
404}
405
406static int omfs_fill_super(struct super_block *sb, void *data, int silent)
407{
408 struct buffer_head *bh, *bh2;
409 struct omfs_super_block *omfs_sb;
410 struct omfs_root_block *omfs_rb;
411 struct omfs_sb_info *sbi;
412 struct inode *root;
413 sector_t start;
414 int ret = -EINVAL;
415
416 save_mount_options(sb, (char *) data);
417
418 sbi = kzalloc(sizeof(struct omfs_sb_info), GFP_KERNEL);
419 if (!sbi)
420 return -ENOMEM;
421
422 sb->s_fs_info = sbi;
423
424 sbi->s_uid = current->uid;
425 sbi->s_gid = current->gid;
426 sbi->s_dmask = sbi->s_fmask = current->fs->umask;
427
428 if (!parse_options((char *) data, sbi))
429 goto end;
430
431 sb->s_maxbytes = 0xffffffff;
432
433 sb_set_blocksize(sb, 0x200);
434
435 bh = sb_bread(sb, 0);
436 if (!bh)
437 goto end;
438
439 omfs_sb = (struct omfs_super_block *)bh->b_data;
440
441 if (omfs_sb->s_magic != cpu_to_be32(OMFS_MAGIC)) {
442 if (!silent)
443 printk(KERN_ERR "omfs: Invalid superblock (%x)\n",
444 omfs_sb->s_magic);
445 goto out_brelse_bh;
446 }
447 sb->s_magic = OMFS_MAGIC;
448
449 sbi->s_num_blocks = be64_to_cpu(omfs_sb->s_num_blocks);
450 sbi->s_blocksize = be32_to_cpu(omfs_sb->s_blocksize);
451 sbi->s_mirrors = be32_to_cpu(omfs_sb->s_mirrors);
452 sbi->s_root_ino = be64_to_cpu(omfs_sb->s_root_block);
453 sbi->s_sys_blocksize = be32_to_cpu(omfs_sb->s_sys_blocksize);
454 mutex_init(&sbi->s_bitmap_lock);
455
456 if (sbi->s_sys_blocksize > PAGE_SIZE) {
457 printk(KERN_ERR "omfs: sysblock size (%d) is out of range\n",
458 sbi->s_sys_blocksize);
459 goto out_brelse_bh;
460 }
461
462 if (sbi->s_blocksize < sbi->s_sys_blocksize ||
463 sbi->s_blocksize > OMFS_MAX_BLOCK_SIZE) {
464 printk(KERN_ERR "omfs: block size (%d) is out of range\n",
465 sbi->s_blocksize);
466 goto out_brelse_bh;
467 }
468
469 /*
470 * Use sys_blocksize as the fs block since it is smaller than a
471 * page while the fs blocksize can be larger.
472 */
473 sb_set_blocksize(sb, sbi->s_sys_blocksize);
474
475 /*
476 * ...and the difference goes into a shift. sys_blocksize is always
477 * a power of two factor of blocksize.
478 */
479 sbi->s_block_shift = get_bitmask_order(sbi->s_blocksize) -
480 get_bitmask_order(sbi->s_sys_blocksize);
481
482 start = clus_to_blk(sbi, be64_to_cpu(omfs_sb->s_root_block));
483 bh2 = sb_bread(sb, start);
484 if (!bh2)
485 goto out_brelse_bh;
486
487 omfs_rb = (struct omfs_root_block *)bh2->b_data;
488
489 sbi->s_bitmap_ino = be64_to_cpu(omfs_rb->r_bitmap);
490 sbi->s_clustersize = be32_to_cpu(omfs_rb->r_clustersize);
491
492 if (sbi->s_num_blocks != be64_to_cpu(omfs_rb->r_num_blocks)) {
493 printk(KERN_ERR "omfs: block count discrepancy between "
494 "super and root blocks (%llx, %llx)\n",
495 sbi->s_num_blocks, be64_to_cpu(omfs_rb->r_num_blocks));
496 goto out_brelse_bh2;
497 }
498
499 ret = omfs_get_imap(sb);
500 if (ret)
501 goto out_brelse_bh2;
502
503 sb->s_op = &omfs_sops;
504
505 root = omfs_iget(sb, be64_to_cpu(omfs_rb->r_root_dir));
506 if (IS_ERR(root)) {
507 ret = PTR_ERR(root);
508 goto out_brelse_bh2;
509 }
510
511 sb->s_root = d_alloc_root(root);
512 if (!sb->s_root) {
513 iput(root);
514 goto out_brelse_bh2;
515 }
516 printk(KERN_DEBUG "omfs: Mounted volume %s\n", omfs_rb->r_name);
517
518 ret = 0;
519out_brelse_bh2:
520 brelse(bh2);
521out_brelse_bh:
522 brelse(bh);
523end:
524 return ret;
525}
526
527static int omfs_get_sb(struct file_system_type *fs_type,
528 int flags, const char *dev_name,
529 void *data, struct vfsmount *m)
530{
531 return get_sb_bdev(fs_type, flags, dev_name, data, omfs_fill_super, m);
532}
533
534static struct file_system_type omfs_fs_type = {
535 .owner = THIS_MODULE,
536 .name = "omfs",
537 .get_sb = omfs_get_sb,
538 .kill_sb = kill_block_super,
539 .fs_flags = FS_REQUIRES_DEV,
540};
541
542static int __init init_omfs_fs(void)
543{
544 return register_filesystem(&omfs_fs_type);
545}
546
547static void __exit exit_omfs_fs(void)
548{
549 unregister_filesystem(&omfs_fs_type);
550}
551
552module_init(init_omfs_fs);
553module_exit(exit_omfs_fs);
diff --git a/fs/omfs/omfs.h b/fs/omfs/omfs.h
new file mode 100644
index 000000000000..2bc0f0670406
--- /dev/null
+++ b/fs/omfs/omfs.h
@@ -0,0 +1,67 @@
1#ifndef _OMFS_H
2#define _OMFS_H
3
4#include <linux/module.h>
5#include <linux/fs.h>
6
7#include "omfs_fs.h"
8
9/* In-memory structures */
10struct omfs_sb_info {
11 u64 s_num_blocks;
12 u64 s_bitmap_ino;
13 u64 s_root_ino;
14 u32 s_blocksize;
15 u32 s_mirrors;
16 u32 s_sys_blocksize;
17 u32 s_clustersize;
18 int s_block_shift;
19 unsigned long **s_imap;
20 int s_imap_size;
21 struct mutex s_bitmap_lock;
22 int s_uid;
23 int s_gid;
24 int s_dmask;
25 int s_fmask;
26};
27
28/* convert a cluster number to a scaled block number */
29static inline sector_t clus_to_blk(struct omfs_sb_info *sbi, sector_t block)
30{
31 return block << sbi->s_block_shift;
32}
33
34static inline struct omfs_sb_info *OMFS_SB(struct super_block *sb)
35{
36 return sb->s_fs_info;
37}
38
39/* bitmap.c */
40extern unsigned long omfs_count_free(struct super_block *sb);
41extern int omfs_allocate_block(struct super_block *sb, u64 block);
42extern int omfs_allocate_range(struct super_block *sb, int min_request,
43 int max_request, u64 *return_block, int *return_size);
44extern int omfs_clear_range(struct super_block *sb, u64 block, int count);
45
46/* dir.c */
47extern struct file_operations omfs_dir_operations;
48extern struct inode_operations omfs_dir_inops;
49extern int omfs_make_empty(struct inode *inode, struct super_block *sb);
50extern int omfs_is_bad(struct omfs_sb_info *sbi, struct omfs_header *header,
51 u64 fsblock);
52
53/* file.c */
54extern struct file_operations omfs_file_operations;
55extern struct inode_operations omfs_file_inops;
56extern struct address_space_operations omfs_aops;
57extern void omfs_make_empty_table(struct buffer_head *bh, int offset);
58extern int omfs_shrink_inode(struct inode *inode);
59
60/* inode.c */
61extern struct inode *omfs_iget(struct super_block *sb, ino_t inode);
62extern struct inode *omfs_new_inode(struct inode *dir, int mode);
63extern int omfs_reserve_block(struct super_block *sb, sector_t block);
64extern int omfs_find_empty_block(struct super_block *sb, int mode, ino_t *ino);
65extern int omfs_sync_inode(struct inode *inode);
66
67#endif
diff --git a/fs/omfs/omfs_fs.h b/fs/omfs/omfs_fs.h
new file mode 100644
index 000000000000..12cca245d6e8
--- /dev/null
+++ b/fs/omfs/omfs_fs.h
@@ -0,0 +1,80 @@
1#ifndef _OMFS_FS_H
2#define _OMFS_FS_H
3
4/* OMFS On-disk structures */
5
6#define OMFS_MAGIC 0xC2993D87
7#define OMFS_IMAGIC 0xD2
8
9#define OMFS_DIR 'D'
10#define OMFS_FILE 'F'
11#define OMFS_INODE_NORMAL 'e'
12#define OMFS_INODE_CONTINUATION 'c'
13#define OMFS_INODE_SYSTEM 's'
14#define OMFS_NAMELEN 256
15#define OMFS_DIR_START 0x1b8
16#define OMFS_EXTENT_START 0x1d0
17#define OMFS_EXTENT_CONT 0x40
18#define OMFS_XOR_COUNT 19
19#define OMFS_MAX_BLOCK_SIZE 8192
20
21struct omfs_super_block {
22 char s_fill1[256];
23 __be64 s_root_block; /* block number of omfs_root_block */
24 __be64 s_num_blocks; /* total number of FS blocks */
25 __be32 s_magic; /* OMFS_MAGIC */
26 __be32 s_blocksize; /* size of a block */
27 __be32 s_mirrors; /* # of mirrors of system blocks */
28 __be32 s_sys_blocksize; /* size of non-data blocks */
29};
30
31struct omfs_header {
32 __be64 h_self; /* FS block where this is located */
33 __be32 h_body_size; /* size of useful data after header */
34 __be16 h_crc; /* crc-ccitt of body_size bytes */
35 char h_fill1[2];
36 u8 h_version; /* version, always 1 */
37 char h_type; /* OMFS_INODE_X */
38 u8 h_magic; /* OMFS_IMAGIC */
39 u8 h_check_xor; /* XOR of header bytes before this */
40 __be32 h_fill2;
41};
42
43struct omfs_root_block {
44 struct omfs_header r_head; /* header */
45 __be64 r_fill1;
46 __be64 r_num_blocks; /* total number of FS blocks */
47 __be64 r_root_dir; /* block # of root directory */
48 __be64 r_bitmap; /* block # of free space bitmap */
49 __be32 r_blocksize; /* size of a block */
50 __be32 r_clustersize; /* size allocated for data blocks */
51 __be64 r_mirrors; /* # of mirrors of system blocks */
52 char r_name[OMFS_NAMELEN]; /* partition label */
53};
54
55struct omfs_inode {
56 struct omfs_header i_head; /* header */
57 __be64 i_parent; /* parent containing this inode */
58 __be64 i_sibling; /* next inode in hash bucket */
59 __be64 i_ctime; /* ctime, in milliseconds */
60 char i_fill1[35];
61 char i_type; /* OMFS_[DIR,FILE] */
62 __be32 i_fill2;
63 char i_fill3[64];
64 char i_name[OMFS_NAMELEN]; /* filename */
65 __be64 i_size; /* size of file, in bytes */
66};
67
68struct omfs_extent_entry {
69 __be64 e_cluster; /* start location of a set of blocks */
70 __be64 e_blocks; /* number of blocks after e_cluster */
71};
72
73struct omfs_extent {
74 __be64 e_next; /* next extent table location */
75 __be32 e_extent_count; /* total # extents in this table */
76 __be32 e_fill;
77 struct omfs_extent_entry e_entry; /* start of extent entries */
78};
79
80#endif