diff options
author | Ingo Molnar <mingo@elte.hu> | 2008-10-03 13:28:46 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-10-03 13:28:46 -0400 |
commit | f68ec0c24755e5cdb779be6240925f2175311d84 (patch) | |
tree | a7b7128e61a8456385d82bd1c7ca5f14eecbf2ca /fs/omfs | |
parent | 98920dc3d1113b883cbc73e3293446d3525c6042 (diff) | |
parent | 94aca1dac6f6d21f4b07e4864baf7768cabcc6e7 (diff) |
Merge commit 'v2.6.27-rc8' into x86/setup
Diffstat (limited to 'fs/omfs')
-rw-r--r-- | fs/omfs/Makefile | 4 | ||||
-rw-r--r-- | fs/omfs/bitmap.c | 193 | ||||
-rw-r--r-- | fs/omfs/dir.c | 504 | ||||
-rw-r--r-- | fs/omfs/file.c | 365 | ||||
-rw-r--r-- | fs/omfs/inode.c | 553 | ||||
-rw-r--r-- | fs/omfs/omfs.h | 67 | ||||
-rw-r--r-- | fs/omfs/omfs_fs.h | 80 |
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 | |||
2 | obj-$(CONFIG_OMFS_FS) += omfs.o | ||
3 | |||
4 | omfs-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 | |||
7 | unsigned 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 | */ | ||
25 | static 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 | */ | ||
47 | static 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; | ||
83 | out: | ||
84 | return err; | ||
85 | } | ||
86 | |||
87 | /* | ||
88 | * Tries to allocate exactly one block. Returns true if sucessful. | ||
89 | */ | ||
90 | int 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; | ||
117 | out: | ||
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 | */ | ||
129 | int 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 | |||
161 | found: | ||
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 | |||
166 | out: | ||
167 | mutex_unlock(&sbi->s_bitmap_lock); | ||
168 | return ret; | ||
169 | } | ||
170 | |||
171 | /* | ||
172 | * Clears count bits starting at a given block. | ||
173 | */ | ||
174 | int 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 | |||
12 | static 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 | */ | ||
24 | static 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 | |||
35 | static 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 | } | ||
65 | err: | ||
66 | return ERR_PTR(err); | ||
67 | } | ||
68 | |||
69 | static 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 | |||
86 | int 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 | |||
114 | static 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; | ||
155 | out: | ||
156 | return -ENOMEM; | ||
157 | } | ||
158 | |||
159 | static 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; | ||
214 | out_free_bh: | ||
215 | brelse(bh); | ||
216 | out: | ||
217 | return err; | ||
218 | } | ||
219 | |||
220 | static 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 | |||
243 | static 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 | |||
255 | end_unlink: | ||
256 | return ret; | ||
257 | } | ||
258 | |||
259 | static 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 | |||
272 | static 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 | |||
291 | out_free_inode: | ||
292 | iput(inode); | ||
293 | return err; | ||
294 | } | ||
295 | |||
296 | static int omfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | ||
297 | { | ||
298 | return omfs_add_node(dir, dentry, mode | S_IFDIR); | ||
299 | } | ||
300 | |||
301 | static 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 | |||
307 | static 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 */ | ||
330 | int 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 | |||
344 | static 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 | } | ||
385 | out: | ||
386 | return res; | ||
387 | } | ||
388 | |||
389 | static 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; | ||
432 | out: | ||
433 | return err; | ||
434 | } | ||
435 | |||
436 | static 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); | ||
486 | success: | ||
487 | ret = 0; | ||
488 | out: | ||
489 | return ret; | ||
490 | } | ||
491 | |||
492 | struct 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 | |||
501 | struct 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 | |||
14 | static 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 | |||
29 | static 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 | |||
36 | void 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 | |||
47 | int 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; | ||
115 | out: | ||
116 | return ret; | ||
117 | out_brelse: | ||
118 | brelse(bh); | ||
119 | return ret; | ||
120 | } | ||
121 | |||
122 | static 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 | */ | ||
132 | static 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 | |||
198 | out: | ||
199 | *ret_block = new_block; | ||
200 | out_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 | */ | ||
208 | static 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 | |||
234 | static 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 | } | ||
298 | out_brelse: | ||
299 | brelse(bh); | ||
300 | out: | ||
301 | return ret; | ||
302 | } | ||
303 | |||
304 | static int omfs_readpage(struct file *file, struct page *page) | ||
305 | { | ||
306 | return block_read_full_page(page, omfs_get_block); | ||
307 | } | ||
308 | |||
309 | static 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 | |||
315 | static int omfs_writepage(struct page *page, struct writeback_control *wbc) | ||
316 | { | ||
317 | return block_write_full_page(page, omfs_get_block, wbc); | ||
318 | } | ||
319 | |||
320 | static int | ||
321 | omfs_writepages(struct address_space *mapping, struct writeback_control *wbc) | ||
322 | { | ||
323 | return mpage_writepages(mapping, wbc, omfs_get_block); | ||
324 | } | ||
325 | |||
326 | static 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 | |||
335 | static sector_t omfs_bmap(struct address_space *mapping, sector_t block) | ||
336 | { | ||
337 | return generic_block_bmap(mapping, block, omfs_get_block); | ||
338 | } | ||
339 | |||
340 | struct 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 | |||
351 | struct inode_operations omfs_file_inops = { | ||
352 | .truncate = omfs_truncate | ||
353 | }; | ||
354 | |||
355 | struct 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 | |||
17 | MODULE_AUTHOR("Bob Copeland <me@bobcopeland.com>"); | ||
18 | MODULE_DESCRIPTION("OMFS (ReplayTV/Karma) Filesystem for Linux"); | ||
19 | MODULE_LICENSE("GPL"); | ||
20 | |||
21 | struct 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; | ||
63 | fail: | ||
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 | */ | ||
74 | static 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 | |||
93 | static 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; | ||
160 | out_brelse: | ||
161 | brelse(bh); | ||
162 | out: | ||
163 | return ret; | ||
164 | } | ||
165 | |||
166 | int 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 | */ | ||
175 | static 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 | |||
188 | struct 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; | ||
247 | fail_bh: | ||
248 | brelse(bh); | ||
249 | iget_failed: | ||
250 | iget_failed(inode); | ||
251 | return ERR_PTR(-EIO); | ||
252 | } | ||
253 | |||
254 | static 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 | |||
262 | static 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 | |||
277 | static 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 | */ | ||
292 | static 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 | } | ||
331 | out: | ||
332 | return 0; | ||
333 | |||
334 | nomem_free: | ||
335 | for (count = 0; count < array_size; count++) | ||
336 | kfree(sbi->s_imap[count]); | ||
337 | |||
338 | kfree(sbi->s_imap); | ||
339 | nomem: | ||
340 | sbi->s_imap = NULL; | ||
341 | sbi->s_imap_size = 0; | ||
342 | return -ENOMEM; | ||
343 | } | ||
344 | |||
345 | enum { | ||
346 | Opt_uid, Opt_gid, Opt_umask, Opt_dmask, Opt_fmask | ||
347 | }; | ||
348 | |||
349 | static 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 | |||
357 | static 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 | |||
405 | static 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; | ||
519 | out_brelse_bh2: | ||
520 | brelse(bh2); | ||
521 | out_brelse_bh: | ||
522 | brelse(bh); | ||
523 | end: | ||
524 | return ret; | ||
525 | } | ||
526 | |||
527 | static 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 | |||
534 | static 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 | |||
542 | static int __init init_omfs_fs(void) | ||
543 | { | ||
544 | return register_filesystem(&omfs_fs_type); | ||
545 | } | ||
546 | |||
547 | static void __exit exit_omfs_fs(void) | ||
548 | { | ||
549 | unregister_filesystem(&omfs_fs_type); | ||
550 | } | ||
551 | |||
552 | module_init(init_omfs_fs); | ||
553 | module_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 */ | ||
10 | struct 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 */ | ||
29 | static inline sector_t clus_to_blk(struct omfs_sb_info *sbi, sector_t block) | ||
30 | { | ||
31 | return block << sbi->s_block_shift; | ||
32 | } | ||
33 | |||
34 | static inline struct omfs_sb_info *OMFS_SB(struct super_block *sb) | ||
35 | { | ||
36 | return sb->s_fs_info; | ||
37 | } | ||
38 | |||
39 | /* bitmap.c */ | ||
40 | extern unsigned long omfs_count_free(struct super_block *sb); | ||
41 | extern int omfs_allocate_block(struct super_block *sb, u64 block); | ||
42 | extern int omfs_allocate_range(struct super_block *sb, int min_request, | ||
43 | int max_request, u64 *return_block, int *return_size); | ||
44 | extern int omfs_clear_range(struct super_block *sb, u64 block, int count); | ||
45 | |||
46 | /* dir.c */ | ||
47 | extern struct file_operations omfs_dir_operations; | ||
48 | extern struct inode_operations omfs_dir_inops; | ||
49 | extern int omfs_make_empty(struct inode *inode, struct super_block *sb); | ||
50 | extern int omfs_is_bad(struct omfs_sb_info *sbi, struct omfs_header *header, | ||
51 | u64 fsblock); | ||
52 | |||
53 | /* file.c */ | ||
54 | extern struct file_operations omfs_file_operations; | ||
55 | extern struct inode_operations omfs_file_inops; | ||
56 | extern struct address_space_operations omfs_aops; | ||
57 | extern void omfs_make_empty_table(struct buffer_head *bh, int offset); | ||
58 | extern int omfs_shrink_inode(struct inode *inode); | ||
59 | |||
60 | /* inode.c */ | ||
61 | extern struct inode *omfs_iget(struct super_block *sb, ino_t inode); | ||
62 | extern struct inode *omfs_new_inode(struct inode *dir, int mode); | ||
63 | extern int omfs_reserve_block(struct super_block *sb, sector_t block); | ||
64 | extern int omfs_find_empty_block(struct super_block *sb, int mode, ino_t *ino); | ||
65 | extern 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 | |||
21 | struct 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 | |||
31 | struct 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 | |||
43 | struct 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 | |||
55 | struct 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 | |||
68 | struct 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 | |||
73 | struct 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 | ||