aboutsummaryrefslogtreecommitdiffstats
path: root/fs/omfs
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2008-10-03 13:28:46 -0400
committerIngo Molnar <mingo@elte.hu>2008-10-03 13:28:46 -0400
commitf68ec0c24755e5cdb779be6240925f2175311d84 (patch)
treea7b7128e61a8456385d82bd1c7ca5f14eecbf2ca /fs/omfs
parent98920dc3d1113b883cbc73e3293446d3525c6042 (diff)
parent94aca1dac6f6d21f4b07e4864baf7768cabcc6e7 (diff)
Merge commit 'v2.6.27-rc8' into x86/setup
Diffstat (limited to 'fs/omfs')
-rw-r--r--fs/omfs/Makefile4
-rw-r--r--fs/omfs/bitmap.c193
-rw-r--r--fs/omfs/dir.c504
-rw-r--r--fs/omfs/file.c365
-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, 1766 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..e1c0ec0ae989
--- /dev/null
+++ b/fs/omfs/bitmap.c
@@ -0,0 +1,193 @@
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, (unsigned long *)bh->b_data);
75 } else {
76 clear_bit(bit, sbi->s_imap[map]);
77 clear_bit(bit, (unsigned 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 unsigned 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, (unsigned 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 unsigned int map, bit;
180 int ret;
181
182 tmp = block;
183 bit = do_div(tmp, bits_per_entry);
184 map = tmp;
185
186 if (map >= sbi->s_imap_size)
187 return 0;
188
189 mutex_lock(&sbi->s_bitmap_lock);
190 ret = set_run(sb, map, bits_per_entry, bit, count, 0);
191 mutex_unlock(&sbi->s_bitmap_lock);
192 return ret;
193}
diff --git a/fs/omfs/dir.c b/fs/omfs/dir.c
new file mode 100644
index 000000000000..c0757e998876
--- /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 = ~cpu_to_be64(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..834b2331f6b3
--- /dev/null
+++ b/fs/omfs/file.c
@@ -0,0 +1,365 @@
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
29static u32 omfs_max_extents(struct omfs_sb_info *sbi, int offset)
30{
31 return (sbi->s_sys_blocksize - offset -
32 sizeof(struct omfs_extent)) /
33 sizeof(struct omfs_extent_entry) + 1;
34}
35
36void omfs_make_empty_table(struct buffer_head *bh, int offset)
37{
38 struct omfs_extent *oe = (struct omfs_extent *) &bh->b_data[offset];
39
40 oe->e_next = ~cpu_to_be64(0ULL);
41 oe->e_extent_count = cpu_to_be32(1),
42 oe->e_fill = cpu_to_be32(0x22),
43 oe->e_entry.e_cluster = ~cpu_to_be64(0ULL);
44 oe->e_entry.e_blocks = ~cpu_to_be64(0ULL);
45}
46
47int omfs_shrink_inode(struct inode *inode)
48{
49 struct omfs_sb_info *sbi = OMFS_SB(inode->i_sb);
50 struct omfs_extent *oe;
51 struct omfs_extent_entry *entry;
52 struct buffer_head *bh;
53 u64 next, last;
54 u32 extent_count;
55 u32 max_extents;
56 int ret;
57
58 /* traverse extent table, freeing each entry that is greater
59 * than inode->i_size;
60 */
61 next = inode->i_ino;
62
63 /* only support truncate -> 0 for now */
64 ret = -EIO;
65 if (inode->i_size != 0)
66 goto out;
67
68 bh = sb_bread(inode->i_sb, clus_to_blk(sbi, next));
69 if (!bh)
70 goto out;
71
72 oe = (struct omfs_extent *)(&bh->b_data[OMFS_EXTENT_START]);
73 max_extents = omfs_max_extents(sbi, OMFS_EXTENT_START);
74
75 for (;;) {
76
77 if (omfs_is_bad(sbi, (struct omfs_header *) bh->b_data, next))
78 goto out_brelse;
79
80 extent_count = be32_to_cpu(oe->e_extent_count);
81
82 if (extent_count > max_extents)
83 goto out_brelse;
84
85 last = next;
86 next = be64_to_cpu(oe->e_next);
87 entry = &oe->e_entry;
88
89 /* ignore last entry as it is the terminator */
90 for (; extent_count > 1; extent_count--) {
91 u64 start, count;
92 start = be64_to_cpu(entry->e_cluster);
93 count = be64_to_cpu(entry->e_blocks);
94
95 omfs_clear_range(inode->i_sb, start, (int) count);
96 entry++;
97 }
98 omfs_make_empty_table(bh, (char *) oe - bh->b_data);
99 mark_buffer_dirty(bh);
100 brelse(bh);
101
102 if (last != inode->i_ino)
103 omfs_clear_range(inode->i_sb, last, sbi->s_mirrors);
104
105 if (next == ~0)
106 break;
107
108 bh = sb_bread(inode->i_sb, clus_to_blk(sbi, next));
109 if (!bh)
110 goto out;
111 oe = (struct omfs_extent *) (&bh->b_data[OMFS_EXTENT_CONT]);
112 max_extents = omfs_max_extents(sbi, OMFS_EXTENT_CONT);
113 }
114 ret = 0;
115out:
116 return ret;
117out_brelse:
118 brelse(bh);
119 return ret;
120}
121
122static void omfs_truncate(struct inode *inode)
123{
124 omfs_shrink_inode(inode);
125 mark_inode_dirty(inode);
126}
127
128/*
129 * Add new blocks to the current extent, or create new entries/continuations
130 * as necessary.
131 */
132static int omfs_grow_extent(struct inode *inode, struct omfs_extent *oe,
133 u64 *ret_block)
134{
135 struct omfs_extent_entry *terminator;
136 struct omfs_extent_entry *entry = &oe->e_entry;
137 struct omfs_sb_info *sbi = OMFS_SB(inode->i_sb);
138 u32 extent_count = be32_to_cpu(oe->e_extent_count);
139 u64 new_block = 0;
140 u32 max_count;
141 int new_count;
142 int ret = 0;
143
144 /* reached the end of the extent table with no blocks mapped.
145 * there are three possibilities for adding: grow last extent,
146 * add a new extent to the current extent table, and add a
147 * continuation inode. in last two cases need an allocator for
148 * sbi->s_cluster_size
149 */
150
151 /* TODO: handle holes */
152
153 /* should always have a terminator */
154 if (extent_count < 1)
155 return -EIO;
156
157 /* trivially grow current extent, if next block is not taken */
158 terminator = entry + extent_count - 1;
159 if (extent_count > 1) {
160 entry = terminator-1;
161 new_block = be64_to_cpu(entry->e_cluster) +
162 be64_to_cpu(entry->e_blocks);
163
164 if (omfs_allocate_block(inode->i_sb, new_block)) {
165 entry->e_blocks =
166 cpu_to_be64(be64_to_cpu(entry->e_blocks) + 1);
167 terminator->e_blocks = ~(cpu_to_be64(
168 be64_to_cpu(~terminator->e_blocks) + 1));
169 goto out;
170 }
171 }
172 max_count = omfs_max_extents(sbi, OMFS_EXTENT_START);
173
174 /* TODO: add a continuation block here */
175 if (be32_to_cpu(oe->e_extent_count) > max_count-1)
176 return -EIO;
177
178 /* try to allocate a new cluster */
179 ret = omfs_allocate_range(inode->i_sb, 1, sbi->s_clustersize,
180 &new_block, &new_count);
181 if (ret)
182 goto out_fail;
183
184 /* copy terminator down an entry */
185 entry = terminator;
186 terminator++;
187 memcpy(terminator, entry, sizeof(struct omfs_extent_entry));
188
189 entry->e_cluster = cpu_to_be64(new_block);
190 entry->e_blocks = cpu_to_be64((u64) new_count);
191
192 terminator->e_blocks = ~(cpu_to_be64(
193 be64_to_cpu(~terminator->e_blocks) + (u64) new_count));
194
195 /* write in new entry */
196 oe->e_extent_count = cpu_to_be32(1 + be32_to_cpu(oe->e_extent_count));
197
198out:
199 *ret_block = new_block;
200out_fail:
201 return ret;
202}
203
204/*
205 * Scans across the directory table for a given file block number.
206 * If block not found, return 0.
207 */
208static sector_t find_block(struct inode *inode, struct omfs_extent_entry *ent,
209 sector_t block, int count, int *left)
210{
211 /* count > 1 because of terminator */
212 sector_t searched = 0;
213 for (; count > 1; count--) {
214 int numblocks = clus_to_blk(OMFS_SB(inode->i_sb),
215 be64_to_cpu(ent->e_blocks));
216
217 if (block >= searched &&
218 block < searched + numblocks) {
219 /*
220 * found it at cluster + (block - searched)
221 * numblocks - (block - searched) is remainder
222 */
223 *left = numblocks - (block - searched);
224 return clus_to_blk(OMFS_SB(inode->i_sb),
225 be64_to_cpu(ent->e_cluster)) +
226 block - searched;
227 }
228 searched += numblocks;
229 ent++;
230 }
231 return 0;
232}
233
234static int omfs_get_block(struct inode *inode, sector_t block,
235 struct buffer_head *bh_result, int create)
236{
237 struct buffer_head *bh;
238 sector_t next, offset;
239 int ret;
240 u64 new_block;
241 u32 max_extents;
242 int extent_count;
243 struct omfs_extent *oe;
244 struct omfs_extent_entry *entry;
245 struct omfs_sb_info *sbi = OMFS_SB(inode->i_sb);
246 int max_blocks = bh_result->b_size >> inode->i_blkbits;
247 int remain;
248
249 ret = -EIO;
250 bh = sb_bread(inode->i_sb, clus_to_blk(sbi, inode->i_ino));
251 if (!bh)
252 goto out;
253
254 oe = (struct omfs_extent *)(&bh->b_data[OMFS_EXTENT_START]);
255 max_extents = omfs_max_extents(sbi, OMFS_EXTENT_START);
256 next = inode->i_ino;
257
258 for (;;) {
259
260 if (omfs_is_bad(sbi, (struct omfs_header *) bh->b_data, next))
261 goto out_brelse;
262
263 extent_count = be32_to_cpu(oe->e_extent_count);
264 next = be64_to_cpu(oe->e_next);
265 entry = &oe->e_entry;
266
267 if (extent_count > max_extents)
268 goto out_brelse;
269
270 offset = find_block(inode, entry, block, extent_count, &remain);
271 if (offset > 0) {
272 ret = 0;
273 map_bh(bh_result, inode->i_sb, offset);
274 if (remain > max_blocks)
275 remain = max_blocks;
276 bh_result->b_size = (remain << inode->i_blkbits);
277 goto out_brelse;
278 }
279 if (next == ~0)
280 break;
281
282 brelse(bh);
283 bh = sb_bread(inode->i_sb, clus_to_blk(sbi, next));
284 if (!bh)
285 goto out;
286 oe = (struct omfs_extent *) (&bh->b_data[OMFS_EXTENT_CONT]);
287 max_extents = omfs_max_extents(sbi, OMFS_EXTENT_CONT);
288 }
289 if (create) {
290 ret = omfs_grow_extent(inode, oe, &new_block);
291 if (ret == 0) {
292 mark_buffer_dirty(bh);
293 mark_inode_dirty(inode);
294 map_bh(bh_result, inode->i_sb,
295 clus_to_blk(sbi, new_block));
296 }
297 }
298out_brelse:
299 brelse(bh);
300out:
301 return ret;
302}
303
304static int omfs_readpage(struct file *file, struct page *page)
305{
306 return block_read_full_page(page, omfs_get_block);
307}
308
309static int omfs_readpages(struct file *file, struct address_space *mapping,
310 struct list_head *pages, unsigned nr_pages)
311{
312 return mpage_readpages(mapping, pages, nr_pages, omfs_get_block);
313}
314
315static int omfs_writepage(struct page *page, struct writeback_control *wbc)
316{
317 return block_write_full_page(page, omfs_get_block, wbc);
318}
319
320static int
321omfs_writepages(struct address_space *mapping, struct writeback_control *wbc)
322{
323 return mpage_writepages(mapping, wbc, omfs_get_block);
324}
325
326static int omfs_write_begin(struct file *file, struct address_space *mapping,
327 loff_t pos, unsigned len, unsigned flags,
328 struct page **pagep, void **fsdata)
329{
330 *pagep = NULL;
331 return block_write_begin(file, mapping, pos, len, flags,
332 pagep, fsdata, omfs_get_block);
333}
334
335static sector_t omfs_bmap(struct address_space *mapping, sector_t block)
336{
337 return generic_block_bmap(mapping, block, omfs_get_block);
338}
339
340struct file_operations omfs_file_operations = {
341 .llseek = generic_file_llseek,
342 .read = do_sync_read,
343 .write = do_sync_write,
344 .aio_read = generic_file_aio_read,
345 .aio_write = generic_file_aio_write,
346 .mmap = generic_file_mmap,
347 .fsync = omfs_sync_file,
348 .splice_read = generic_file_splice_read,
349};
350
351struct inode_operations omfs_file_inops = {
352 .truncate = omfs_truncate
353};
354
355struct address_space_operations omfs_aops = {
356 .readpage = omfs_readpage,
357 .readpages = omfs_readpages,
358 .writepage = omfs_writepage,
359 .writepages = omfs_writepages,
360 .sync_page = block_sync_page,
361 .write_begin = omfs_write_begin,
362 .write_end = generic_write_end,
363 .bmap = omfs_bmap,
364};
365
diff --git a/fs/omfs/inode.c b/fs/omfs/inode.c
new file mode 100644
index 000000000000..d29047b1b9b0
--- /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 = sbi->s_sys_blocksize;
236 inc_nlink(inode);
237 break;
238 case OMFS_FILE:
239 inode->i_mode = S_IFREG | (S_IRWXUGO & ~sbi->s_fmask);
240 inode->i_fop = &omfs_file_operations;
241 inode->i_size = be64_to_cpu(oi->i_size);
242 break;
243 }
244 brelse(bh);
245 unlock_new_inode(inode);
246 return inode;
247fail_bh:
248 brelse(bh);
249iget_failed:
250 iget_failed(inode);
251 return ERR_PTR(-EIO);
252}
253
254static void omfs_put_super(struct super_block *sb)
255{
256 struct omfs_sb_info *sbi = OMFS_SB(sb);
257 kfree(sbi->s_imap);
258 kfree(sbi);
259 sb->s_fs_info = NULL;
260}
261
262static int omfs_statfs(struct dentry *dentry, struct kstatfs *buf)
263{
264 struct super_block *s = dentry->d_sb;
265 struct omfs_sb_info *sbi = OMFS_SB(s);
266 buf->f_type = OMFS_MAGIC;
267 buf->f_bsize = sbi->s_blocksize;
268 buf->f_blocks = sbi->s_num_blocks;
269 buf->f_files = sbi->s_num_blocks;
270 buf->f_namelen = OMFS_NAMELEN;
271
272 buf->f_bfree = buf->f_bavail = buf->f_ffree =
273 omfs_count_free(s);
274 return 0;
275}
276
277static struct super_operations omfs_sops = {
278 .write_inode = omfs_write_inode,
279 .delete_inode = omfs_delete_inode,
280 .put_super = omfs_put_super,
281 .statfs = omfs_statfs,
282 .show_options = generic_show_options,
283};
284
285/*
286 * For Rio Karma, there is an on-disk free bitmap whose location is
287 * stored in the root block. For ReplayTV, there is no such free bitmap
288 * so we have to walk the tree. Both inodes and file data are allocated
289 * from the same map. This array can be big (300k) so we allocate
290 * in units of the blocksize.
291 */
292static int omfs_get_imap(struct super_block *sb)
293{
294 int bitmap_size;
295 int array_size;
296 int count;
297 struct omfs_sb_info *sbi = OMFS_SB(sb);
298 struct buffer_head *bh;
299 unsigned long **ptr;
300 sector_t block;
301
302 bitmap_size = DIV_ROUND_UP(sbi->s_num_blocks, 8);
303 array_size = DIV_ROUND_UP(bitmap_size, sb->s_blocksize);
304
305 if (sbi->s_bitmap_ino == ~0ULL)
306 goto out;
307
308 sbi->s_imap_size = array_size;
309 sbi->s_imap = kzalloc(array_size * sizeof(unsigned long *), GFP_KERNEL);
310 if (!sbi->s_imap)
311 goto nomem;
312
313 block = clus_to_blk(sbi, sbi->s_bitmap_ino);
314 ptr = sbi->s_imap;
315 for (count = bitmap_size; count > 0; count -= sb->s_blocksize) {
316 bh = sb_bread(sb, block++);
317 if (!bh)
318 goto nomem_free;
319 *ptr = kmalloc(sb->s_blocksize, GFP_KERNEL);
320 if (!*ptr) {
321 brelse(bh);
322 goto nomem_free;
323 }
324 memcpy(*ptr, bh->b_data, sb->s_blocksize);
325 if (count < sb->s_blocksize)
326 memset((void *)*ptr + count, 0xff,
327 sb->s_blocksize - count);
328 brelse(bh);
329 ptr++;
330 }
331out:
332 return 0;
333
334nomem_free:
335 for (count = 0; count < array_size; count++)
336 kfree(sbi->s_imap[count]);
337
338 kfree(sbi->s_imap);
339nomem:
340 sbi->s_imap = NULL;
341 sbi->s_imap_size = 0;
342 return -ENOMEM;
343}
344
345enum {
346 Opt_uid, Opt_gid, Opt_umask, Opt_dmask, Opt_fmask
347};
348
349static match_table_t tokens = {
350 {Opt_uid, "uid=%u"},
351 {Opt_gid, "gid=%u"},
352 {Opt_umask, "umask=%o"},
353 {Opt_dmask, "dmask=%o"},
354 {Opt_fmask, "fmask=%o"},
355};
356
357static int parse_options(char *options, struct omfs_sb_info *sbi)
358{
359 char *p;
360 substring_t args[MAX_OPT_ARGS];
361 int option;
362
363 if (!options)
364 return 1;
365
366 while ((p = strsep(&options, ",")) != NULL) {
367 int token;
368 if (!*p)
369 continue;
370
371 token = match_token(p, tokens, args);
372 switch (token) {
373 case Opt_uid:
374 if (match_int(&args[0], &option))
375 return 0;
376 sbi->s_uid = option;
377 break;
378 case Opt_gid:
379 if (match_int(&args[0], &option))
380 return 0;
381 sbi->s_gid = option;
382 break;
383 case Opt_umask:
384 if (match_octal(&args[0], &option))
385 return 0;
386 sbi->s_fmask = sbi->s_dmask = option;
387 break;
388 case Opt_dmask:
389 if (match_octal(&args[0], &option))
390 return 0;
391 sbi->s_dmask = option;
392 break;
393 case Opt_fmask:
394 if (match_octal(&args[0], &option))
395 return 0;
396 sbi->s_fmask = option;
397 break;
398 default:
399 return 0;
400 }
401 }
402 return 1;
403}
404
405static int omfs_fill_super(struct super_block *sb, void *data, int silent)
406{
407 struct buffer_head *bh, *bh2;
408 struct omfs_super_block *omfs_sb;
409 struct omfs_root_block *omfs_rb;
410 struct omfs_sb_info *sbi;
411 struct inode *root;
412 sector_t start;
413 int ret = -EINVAL;
414
415 save_mount_options(sb, (char *) data);
416
417 sbi = kzalloc(sizeof(struct omfs_sb_info), GFP_KERNEL);
418 if (!sbi)
419 return -ENOMEM;
420
421 sb->s_fs_info = sbi;
422
423 sbi->s_uid = current->uid;
424 sbi->s_gid = current->gid;
425 sbi->s_dmask = sbi->s_fmask = current->fs->umask;
426
427 if (!parse_options((char *) data, sbi))
428 goto end;
429
430 sb->s_maxbytes = 0xffffffff;
431
432 sb_set_blocksize(sb, 0x200);
433
434 bh = sb_bread(sb, 0);
435 if (!bh)
436 goto end;
437
438 omfs_sb = (struct omfs_super_block *)bh->b_data;
439
440 if (omfs_sb->s_magic != cpu_to_be32(OMFS_MAGIC)) {
441 if (!silent)
442 printk(KERN_ERR "omfs: Invalid superblock (%x)\n",
443 omfs_sb->s_magic);
444 goto out_brelse_bh;
445 }
446 sb->s_magic = OMFS_MAGIC;
447
448 sbi->s_num_blocks = be64_to_cpu(omfs_sb->s_num_blocks);
449 sbi->s_blocksize = be32_to_cpu(omfs_sb->s_blocksize);
450 sbi->s_mirrors = be32_to_cpu(omfs_sb->s_mirrors);
451 sbi->s_root_ino = be64_to_cpu(omfs_sb->s_root_block);
452 sbi->s_sys_blocksize = be32_to_cpu(omfs_sb->s_sys_blocksize);
453 mutex_init(&sbi->s_bitmap_lock);
454
455 if (sbi->s_sys_blocksize > PAGE_SIZE) {
456 printk(KERN_ERR "omfs: sysblock size (%d) is out of range\n",
457 sbi->s_sys_blocksize);
458 goto out_brelse_bh;
459 }
460
461 if (sbi->s_blocksize < sbi->s_sys_blocksize ||
462 sbi->s_blocksize > OMFS_MAX_BLOCK_SIZE) {
463 printk(KERN_ERR "omfs: block size (%d) is out of range\n",
464 sbi->s_blocksize);
465 goto out_brelse_bh;
466 }
467
468 /*
469 * Use sys_blocksize as the fs block since it is smaller than a
470 * page while the fs blocksize can be larger.
471 */
472 sb_set_blocksize(sb, sbi->s_sys_blocksize);
473
474 /*
475 * ...and the difference goes into a shift. sys_blocksize is always
476 * a power of two factor of blocksize.
477 */
478 sbi->s_block_shift = get_bitmask_order(sbi->s_blocksize) -
479 get_bitmask_order(sbi->s_sys_blocksize);
480
481 start = clus_to_blk(sbi, be64_to_cpu(omfs_sb->s_root_block));
482 bh2 = sb_bread(sb, start);
483 if (!bh2)
484 goto out_brelse_bh;
485
486 omfs_rb = (struct omfs_root_block *)bh2->b_data;
487
488 sbi->s_bitmap_ino = be64_to_cpu(omfs_rb->r_bitmap);
489 sbi->s_clustersize = be32_to_cpu(omfs_rb->r_clustersize);
490
491 if (sbi->s_num_blocks != be64_to_cpu(omfs_rb->r_num_blocks)) {
492 printk(KERN_ERR "omfs: block count discrepancy between "
493 "super and root blocks (%llx, %llx)\n",
494 (unsigned long long)sbi->s_num_blocks,
495 (unsigned long long)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