diff options
Diffstat (limited to 'fs/qnx4/inode.c')
-rw-r--r-- | fs/qnx4/inode.c | 603 |
1 files changed, 603 insertions, 0 deletions
diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c new file mode 100644 index 000000000000..aa92d6b76a9a --- /dev/null +++ b/fs/qnx4/inode.c | |||
@@ -0,0 +1,603 @@ | |||
1 | /* | ||
2 | * QNX4 file system, Linux implementation. | ||
3 | * | ||
4 | * Version : 0.2.1 | ||
5 | * | ||
6 | * Using parts of the xiafs filesystem. | ||
7 | * | ||
8 | * History : | ||
9 | * | ||
10 | * 01-06-1998 by Richard Frowijn : first release. | ||
11 | * 20-06-1998 by Frank Denis : Linux 2.1.99+ support, boot signature, misc. | ||
12 | * 30-06-1998 by Frank Denis : first step to write inodes. | ||
13 | */ | ||
14 | |||
15 | #include <linux/config.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/types.h> | ||
18 | #include <linux/string.h> | ||
19 | #include <linux/errno.h> | ||
20 | #include <linux/slab.h> | ||
21 | #include <linux/fs.h> | ||
22 | #include <linux/qnx4_fs.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/highuid.h> | ||
25 | #include <linux/smp_lock.h> | ||
26 | #include <linux/pagemap.h> | ||
27 | #include <linux/buffer_head.h> | ||
28 | #include <linux/vfs.h> | ||
29 | #include <asm/uaccess.h> | ||
30 | |||
31 | #define QNX4_VERSION 4 | ||
32 | #define QNX4_BMNAME ".bitmap" | ||
33 | |||
34 | static struct super_operations qnx4_sops; | ||
35 | |||
36 | #ifdef CONFIG_QNX4FS_RW | ||
37 | |||
38 | int qnx4_sync_inode(struct inode *inode) | ||
39 | { | ||
40 | int err = 0; | ||
41 | # if 0 | ||
42 | struct buffer_head *bh; | ||
43 | |||
44 | bh = qnx4_update_inode(inode); | ||
45 | if (bh && buffer_dirty(bh)) | ||
46 | { | ||
47 | sync_dirty_buffer(bh); | ||
48 | if (buffer_req(bh) && !buffer_uptodate(bh)) | ||
49 | { | ||
50 | printk ("IO error syncing qnx4 inode [%s:%08lx]\n", | ||
51 | inode->i_sb->s_id, inode->i_ino); | ||
52 | err = -1; | ||
53 | } | ||
54 | brelse (bh); | ||
55 | } else if (!bh) { | ||
56 | err = -1; | ||
57 | } | ||
58 | # endif | ||
59 | |||
60 | return err; | ||
61 | } | ||
62 | |||
63 | static void qnx4_delete_inode(struct inode *inode) | ||
64 | { | ||
65 | QNX4DEBUG(("qnx4: deleting inode [%lu]\n", (unsigned long) inode->i_ino)); | ||
66 | inode->i_size = 0; | ||
67 | qnx4_truncate(inode); | ||
68 | lock_kernel(); | ||
69 | qnx4_free_inode(inode); | ||
70 | unlock_kernel(); | ||
71 | } | ||
72 | |||
73 | static void qnx4_write_super(struct super_block *sb) | ||
74 | { | ||
75 | lock_kernel(); | ||
76 | QNX4DEBUG(("qnx4: write_super\n")); | ||
77 | sb->s_dirt = 0; | ||
78 | unlock_kernel(); | ||
79 | } | ||
80 | |||
81 | static int qnx4_write_inode(struct inode *inode, int unused) | ||
82 | { | ||
83 | struct qnx4_inode_entry *raw_inode; | ||
84 | int block, ino; | ||
85 | struct buffer_head *bh; | ||
86 | ino = inode->i_ino; | ||
87 | |||
88 | QNX4DEBUG(("qnx4: write inode 1.\n")); | ||
89 | if (inode->i_nlink == 0) { | ||
90 | return 0; | ||
91 | } | ||
92 | if (!ino) { | ||
93 | printk("qnx4: bad inode number on dev %s: %d is out of range\n", | ||
94 | inode->i_sb->s_id, ino); | ||
95 | return -EIO; | ||
96 | } | ||
97 | QNX4DEBUG(("qnx4: write inode 2.\n")); | ||
98 | block = ino / QNX4_INODES_PER_BLOCK; | ||
99 | lock_kernel(); | ||
100 | if (!(bh = sb_bread(inode->i_sb, block))) { | ||
101 | printk("qnx4: major problem: unable to read inode from dev " | ||
102 | "%s\n", inode->i_sb->s_id); | ||
103 | unlock_kernel(); | ||
104 | return -EIO; | ||
105 | } | ||
106 | raw_inode = ((struct qnx4_inode_entry *) bh->b_data) + | ||
107 | (ino % QNX4_INODES_PER_BLOCK); | ||
108 | raw_inode->di_mode = cpu_to_le16(inode->i_mode); | ||
109 | raw_inode->di_uid = cpu_to_le16(fs_high2lowuid(inode->i_uid)); | ||
110 | raw_inode->di_gid = cpu_to_le16(fs_high2lowgid(inode->i_gid)); | ||
111 | raw_inode->di_nlink = cpu_to_le16(inode->i_nlink); | ||
112 | raw_inode->di_size = cpu_to_le32(inode->i_size); | ||
113 | raw_inode->di_mtime = cpu_to_le32(inode->i_mtime.tv_sec); | ||
114 | raw_inode->di_atime = cpu_to_le32(inode->i_atime.tv_sec); | ||
115 | raw_inode->di_ctime = cpu_to_le32(inode->i_ctime.tv_sec); | ||
116 | raw_inode->di_first_xtnt.xtnt_size = cpu_to_le32(inode->i_blocks); | ||
117 | mark_buffer_dirty(bh); | ||
118 | brelse(bh); | ||
119 | unlock_kernel(); | ||
120 | return 0; | ||
121 | } | ||
122 | |||
123 | #endif | ||
124 | |||
125 | static void qnx4_put_super(struct super_block *sb); | ||
126 | static struct inode *qnx4_alloc_inode(struct super_block *sb); | ||
127 | static void qnx4_destroy_inode(struct inode *inode); | ||
128 | static void qnx4_read_inode(struct inode *); | ||
129 | static int qnx4_remount(struct super_block *sb, int *flags, char *data); | ||
130 | static int qnx4_statfs(struct super_block *, struct kstatfs *); | ||
131 | |||
132 | static struct super_operations qnx4_sops = | ||
133 | { | ||
134 | .alloc_inode = qnx4_alloc_inode, | ||
135 | .destroy_inode = qnx4_destroy_inode, | ||
136 | .read_inode = qnx4_read_inode, | ||
137 | .put_super = qnx4_put_super, | ||
138 | .statfs = qnx4_statfs, | ||
139 | .remount_fs = qnx4_remount, | ||
140 | #ifdef CONFIG_QNX4FS_RW | ||
141 | .write_inode = qnx4_write_inode, | ||
142 | .delete_inode = qnx4_delete_inode, | ||
143 | .write_super = qnx4_write_super, | ||
144 | #endif | ||
145 | }; | ||
146 | |||
147 | static int qnx4_remount(struct super_block *sb, int *flags, char *data) | ||
148 | { | ||
149 | struct qnx4_sb_info *qs; | ||
150 | |||
151 | qs = qnx4_sb(sb); | ||
152 | qs->Version = QNX4_VERSION; | ||
153 | #ifndef CONFIG_QNX4FS_RW | ||
154 | *flags |= MS_RDONLY; | ||
155 | #endif | ||
156 | if (*flags & MS_RDONLY) { | ||
157 | return 0; | ||
158 | } | ||
159 | |||
160 | mark_buffer_dirty(qs->sb_buf); | ||
161 | |||
162 | return 0; | ||
163 | } | ||
164 | |||
165 | static struct buffer_head *qnx4_getblk(struct inode *inode, int nr, | ||
166 | int create) | ||
167 | { | ||
168 | struct buffer_head *result = NULL; | ||
169 | |||
170 | if ( nr >= 0 ) | ||
171 | nr = qnx4_block_map( inode, nr ); | ||
172 | if (nr) { | ||
173 | result = sb_getblk(inode->i_sb, nr); | ||
174 | return result; | ||
175 | } | ||
176 | if (!create) { | ||
177 | return NULL; | ||
178 | } | ||
179 | #if 0 | ||
180 | tmp = qnx4_new_block(inode->i_sb); | ||
181 | if (!tmp) { | ||
182 | return NULL; | ||
183 | } | ||
184 | result = sb_getblk(inode->i_sb, tmp); | ||
185 | if (tst) { | ||
186 | qnx4_free_block(inode->i_sb, tmp); | ||
187 | brelse(result); | ||
188 | goto repeat; | ||
189 | } | ||
190 | tst = tmp; | ||
191 | #endif | ||
192 | inode->i_ctime = CURRENT_TIME_SEC; | ||
193 | mark_inode_dirty(inode); | ||
194 | return result; | ||
195 | } | ||
196 | |||
197 | struct buffer_head *qnx4_bread(struct inode *inode, int block, int create) | ||
198 | { | ||
199 | struct buffer_head *bh; | ||
200 | |||
201 | bh = qnx4_getblk(inode, block, create); | ||
202 | if (!bh || buffer_uptodate(bh)) { | ||
203 | return bh; | ||
204 | } | ||
205 | ll_rw_block(READ, 1, &bh); | ||
206 | wait_on_buffer(bh); | ||
207 | if (buffer_uptodate(bh)) { | ||
208 | return bh; | ||
209 | } | ||
210 | brelse(bh); | ||
211 | |||
212 | return NULL; | ||
213 | } | ||
214 | |||
215 | static int qnx4_get_block( struct inode *inode, sector_t iblock, struct buffer_head *bh, int create ) | ||
216 | { | ||
217 | unsigned long phys; | ||
218 | |||
219 | QNX4DEBUG(("qnx4: qnx4_get_block inode=[%ld] iblock=[%ld]\n",inode->i_ino,iblock)); | ||
220 | |||
221 | phys = qnx4_block_map( inode, iblock ); | ||
222 | if ( phys ) { | ||
223 | // logical block is before EOF | ||
224 | map_bh(bh, inode->i_sb, phys); | ||
225 | } else if ( create ) { | ||
226 | // to be done. | ||
227 | } | ||
228 | return 0; | ||
229 | } | ||
230 | |||
231 | unsigned long qnx4_block_map( struct inode *inode, long iblock ) | ||
232 | { | ||
233 | int ix; | ||
234 | long offset, i_xblk; | ||
235 | unsigned long block = 0; | ||
236 | struct buffer_head *bh = NULL; | ||
237 | struct qnx4_xblk *xblk = NULL; | ||
238 | struct qnx4_inode_entry *qnx4_inode = qnx4_raw_inode(inode); | ||
239 | qnx4_nxtnt_t nxtnt = le16_to_cpu(qnx4_inode->di_num_xtnts); | ||
240 | |||
241 | if ( iblock < le32_to_cpu(qnx4_inode->di_first_xtnt.xtnt_size) ) { | ||
242 | // iblock is in the first extent. This is easy. | ||
243 | block = le32_to_cpu(qnx4_inode->di_first_xtnt.xtnt_blk) + iblock - 1; | ||
244 | } else { | ||
245 | // iblock is beyond first extent. We have to follow the extent chain. | ||
246 | i_xblk = le32_to_cpu(qnx4_inode->di_xblk); | ||
247 | offset = iblock - le32_to_cpu(qnx4_inode->di_first_xtnt.xtnt_size); | ||
248 | ix = 0; | ||
249 | while ( --nxtnt > 0 ) { | ||
250 | if ( ix == 0 ) { | ||
251 | // read next xtnt block. | ||
252 | bh = sb_bread(inode->i_sb, i_xblk - 1); | ||
253 | if ( !bh ) { | ||
254 | QNX4DEBUG(("qnx4: I/O error reading xtnt block [%ld])\n", i_xblk - 1)); | ||
255 | return -EIO; | ||
256 | } | ||
257 | xblk = (struct qnx4_xblk*)bh->b_data; | ||
258 | if ( memcmp( xblk->xblk_signature, "IamXblk", 7 ) ) { | ||
259 | QNX4DEBUG(("qnx4: block at %ld is not a valid xtnt\n", qnx4_inode->i_xblk)); | ||
260 | return -EIO; | ||
261 | } | ||
262 | } | ||
263 | if ( offset < le32_to_cpu(xblk->xblk_xtnts[ix].xtnt_size) ) { | ||
264 | // got it! | ||
265 | block = le32_to_cpu(xblk->xblk_xtnts[ix].xtnt_blk) + offset - 1; | ||
266 | break; | ||
267 | } | ||
268 | offset -= le32_to_cpu(xblk->xblk_xtnts[ix].xtnt_size); | ||
269 | if ( ++ix >= xblk->xblk_num_xtnts ) { | ||
270 | i_xblk = le32_to_cpu(xblk->xblk_next_xblk); | ||
271 | ix = 0; | ||
272 | brelse( bh ); | ||
273 | bh = NULL; | ||
274 | } | ||
275 | } | ||
276 | if ( bh ) | ||
277 | brelse( bh ); | ||
278 | } | ||
279 | |||
280 | QNX4DEBUG(("qnx4: mapping block %ld of inode %ld = %ld\n",iblock,inode->i_ino,block)); | ||
281 | return block; | ||
282 | } | ||
283 | |||
284 | static int qnx4_statfs(struct super_block *sb, struct kstatfs *buf) | ||
285 | { | ||
286 | lock_kernel(); | ||
287 | |||
288 | buf->f_type = sb->s_magic; | ||
289 | buf->f_bsize = sb->s_blocksize; | ||
290 | buf->f_blocks = le32_to_cpu(qnx4_sb(sb)->BitMap->di_size) * 8; | ||
291 | buf->f_bfree = qnx4_count_free_blocks(sb); | ||
292 | buf->f_bavail = buf->f_bfree; | ||
293 | buf->f_namelen = QNX4_NAME_MAX; | ||
294 | |||
295 | unlock_kernel(); | ||
296 | |||
297 | return 0; | ||
298 | } | ||
299 | |||
300 | /* | ||
301 | * Check the root directory of the filesystem to make sure | ||
302 | * it really _is_ a qnx4 filesystem, and to check the size | ||
303 | * of the directory entry. | ||
304 | */ | ||
305 | static const char *qnx4_checkroot(struct super_block *sb) | ||
306 | { | ||
307 | struct buffer_head *bh; | ||
308 | struct qnx4_inode_entry *rootdir; | ||
309 | int rd, rl; | ||
310 | int i, j; | ||
311 | int found = 0; | ||
312 | |||
313 | if (*(qnx4_sb(sb)->sb->RootDir.di_fname) != '/') { | ||
314 | return "no qnx4 filesystem (no root dir)."; | ||
315 | } else { | ||
316 | QNX4DEBUG(("QNX4 filesystem found on dev %s.\n", sb->s_id)); | ||
317 | rd = le32_to_cpu(qnx4_sb(sb)->sb->RootDir.di_first_xtnt.xtnt_blk) - 1; | ||
318 | rl = le32_to_cpu(qnx4_sb(sb)->sb->RootDir.di_first_xtnt.xtnt_size); | ||
319 | for (j = 0; j < rl; j++) { | ||
320 | bh = sb_bread(sb, rd + j); /* root dir, first block */ | ||
321 | if (bh == NULL) { | ||
322 | return "unable to read root entry."; | ||
323 | } | ||
324 | for (i = 0; i < QNX4_INODES_PER_BLOCK; i++) { | ||
325 | rootdir = (struct qnx4_inode_entry *) (bh->b_data + i * QNX4_DIR_ENTRY_SIZE); | ||
326 | if (rootdir->di_fname != NULL) { | ||
327 | QNX4DEBUG(("Rootdir entry found : [%s]\n", rootdir->di_fname)); | ||
328 | if (!strncmp(rootdir->di_fname, QNX4_BMNAME, sizeof QNX4_BMNAME)) { | ||
329 | found = 1; | ||
330 | qnx4_sb(sb)->BitMap = kmalloc( sizeof( struct qnx4_inode_entry ), GFP_KERNEL ); | ||
331 | if (!qnx4_sb(sb)->BitMap) { | ||
332 | brelse (bh); | ||
333 | return "not enough memory for bitmap inode"; | ||
334 | } | ||
335 | memcpy( qnx4_sb(sb)->BitMap, rootdir, sizeof( struct qnx4_inode_entry ) ); /* keep bitmap inode known */ | ||
336 | break; | ||
337 | } | ||
338 | } | ||
339 | } | ||
340 | brelse(bh); | ||
341 | if (found != 0) { | ||
342 | break; | ||
343 | } | ||
344 | } | ||
345 | if (found == 0) { | ||
346 | return "bitmap file not found."; | ||
347 | } | ||
348 | } | ||
349 | return NULL; | ||
350 | } | ||
351 | |||
352 | static int qnx4_fill_super(struct super_block *s, void *data, int silent) | ||
353 | { | ||
354 | struct buffer_head *bh; | ||
355 | struct inode *root; | ||
356 | const char *errmsg; | ||
357 | struct qnx4_sb_info *qs; | ||
358 | |||
359 | qs = kmalloc(sizeof(struct qnx4_sb_info), GFP_KERNEL); | ||
360 | if (!qs) | ||
361 | return -ENOMEM; | ||
362 | s->s_fs_info = qs; | ||
363 | memset(qs, 0, sizeof(struct qnx4_sb_info)); | ||
364 | |||
365 | sb_set_blocksize(s, QNX4_BLOCK_SIZE); | ||
366 | |||
367 | /* Check the superblock signature. Since the qnx4 code is | ||
368 | dangerous, we should leave as quickly as possible | ||
369 | if we don't belong here... */ | ||
370 | bh = sb_bread(s, 1); | ||
371 | if (!bh) { | ||
372 | printk("qnx4: unable to read the superblock\n"); | ||
373 | goto outnobh; | ||
374 | } | ||
375 | if ( le32_to_cpu( *(__u32*)bh->b_data ) != QNX4_SUPER_MAGIC ) { | ||
376 | if (!silent) | ||
377 | printk("qnx4: wrong fsid in superblock.\n"); | ||
378 | goto out; | ||
379 | } | ||
380 | s->s_op = &qnx4_sops; | ||
381 | s->s_magic = QNX4_SUPER_MAGIC; | ||
382 | #ifndef CONFIG_QNX4FS_RW | ||
383 | s->s_flags |= MS_RDONLY; /* Yup, read-only yet */ | ||
384 | #endif | ||
385 | qnx4_sb(s)->sb_buf = bh; | ||
386 | qnx4_sb(s)->sb = (struct qnx4_super_block *) bh->b_data; | ||
387 | |||
388 | |||
389 | /* check before allocating dentries, inodes, .. */ | ||
390 | errmsg = qnx4_checkroot(s); | ||
391 | if (errmsg != NULL) { | ||
392 | if (!silent) | ||
393 | printk("qnx4: %s\n", errmsg); | ||
394 | goto out; | ||
395 | } | ||
396 | |||
397 | /* does root not have inode number QNX4_ROOT_INO ?? */ | ||
398 | root = iget(s, QNX4_ROOT_INO * QNX4_INODES_PER_BLOCK); | ||
399 | if (!root) { | ||
400 | printk("qnx4: get inode failed\n"); | ||
401 | goto out; | ||
402 | } | ||
403 | |||
404 | s->s_root = d_alloc_root(root); | ||
405 | if (s->s_root == NULL) | ||
406 | goto outi; | ||
407 | |||
408 | brelse(bh); | ||
409 | |||
410 | return 0; | ||
411 | |||
412 | outi: | ||
413 | iput(root); | ||
414 | out: | ||
415 | brelse(bh); | ||
416 | outnobh: | ||
417 | kfree(qs); | ||
418 | s->s_fs_info = NULL; | ||
419 | return -EINVAL; | ||
420 | } | ||
421 | |||
422 | static void qnx4_put_super(struct super_block *sb) | ||
423 | { | ||
424 | struct qnx4_sb_info *qs = qnx4_sb(sb); | ||
425 | kfree( qs->BitMap ); | ||
426 | kfree( qs ); | ||
427 | sb->s_fs_info = NULL; | ||
428 | return; | ||
429 | } | ||
430 | |||
431 | static int qnx4_writepage(struct page *page, struct writeback_control *wbc) | ||
432 | { | ||
433 | return block_write_full_page(page,qnx4_get_block, wbc); | ||
434 | } | ||
435 | static int qnx4_readpage(struct file *file, struct page *page) | ||
436 | { | ||
437 | return block_read_full_page(page,qnx4_get_block); | ||
438 | } | ||
439 | static int qnx4_prepare_write(struct file *file, struct page *page, | ||
440 | unsigned from, unsigned to) | ||
441 | { | ||
442 | struct qnx4_inode_info *qnx4_inode = qnx4_i(page->mapping->host); | ||
443 | return cont_prepare_write(page, from, to, qnx4_get_block, | ||
444 | &qnx4_inode->mmu_private); | ||
445 | } | ||
446 | static sector_t qnx4_bmap(struct address_space *mapping, sector_t block) | ||
447 | { | ||
448 | return generic_block_bmap(mapping,block,qnx4_get_block); | ||
449 | } | ||
450 | static struct address_space_operations qnx4_aops = { | ||
451 | .readpage = qnx4_readpage, | ||
452 | .writepage = qnx4_writepage, | ||
453 | .sync_page = block_sync_page, | ||
454 | .prepare_write = qnx4_prepare_write, | ||
455 | .commit_write = generic_commit_write, | ||
456 | .bmap = qnx4_bmap | ||
457 | }; | ||
458 | |||
459 | static void qnx4_read_inode(struct inode *inode) | ||
460 | { | ||
461 | struct buffer_head *bh; | ||
462 | struct qnx4_inode_entry *raw_inode; | ||
463 | int block, ino; | ||
464 | struct super_block *sb = inode->i_sb; | ||
465 | struct qnx4_inode_entry *qnx4_inode = qnx4_raw_inode(inode); | ||
466 | |||
467 | ino = inode->i_ino; | ||
468 | inode->i_mode = 0; | ||
469 | |||
470 | QNX4DEBUG(("Reading inode : [%d]\n", ino)); | ||
471 | if (!ino) { | ||
472 | printk("qnx4: bad inode number on dev %s: %d is out of range\n", | ||
473 | sb->s_id, ino); | ||
474 | return; | ||
475 | } | ||
476 | block = ino / QNX4_INODES_PER_BLOCK; | ||
477 | |||
478 | if (!(bh = sb_bread(sb, block))) { | ||
479 | printk("qnx4: major problem: unable to read inode from dev " | ||
480 | "%s\n", sb->s_id); | ||
481 | return; | ||
482 | } | ||
483 | raw_inode = ((struct qnx4_inode_entry *) bh->b_data) + | ||
484 | (ino % QNX4_INODES_PER_BLOCK); | ||
485 | |||
486 | inode->i_mode = le16_to_cpu(raw_inode->di_mode); | ||
487 | inode->i_uid = (uid_t)le16_to_cpu(raw_inode->di_uid); | ||
488 | inode->i_gid = (gid_t)le16_to_cpu(raw_inode->di_gid); | ||
489 | inode->i_nlink = le16_to_cpu(raw_inode->di_nlink); | ||
490 | inode->i_size = le32_to_cpu(raw_inode->di_size); | ||
491 | inode->i_mtime.tv_sec = le32_to_cpu(raw_inode->di_mtime); | ||
492 | inode->i_mtime.tv_nsec = 0; | ||
493 | inode->i_atime.tv_sec = le32_to_cpu(raw_inode->di_atime); | ||
494 | inode->i_atime.tv_nsec = 0; | ||
495 | inode->i_ctime.tv_sec = le32_to_cpu(raw_inode->di_ctime); | ||
496 | inode->i_ctime.tv_nsec = 0; | ||
497 | inode->i_blocks = le32_to_cpu(raw_inode->di_first_xtnt.xtnt_size); | ||
498 | inode->i_blksize = QNX4_DIR_ENTRY_SIZE; | ||
499 | |||
500 | memcpy(qnx4_inode, raw_inode, QNX4_DIR_ENTRY_SIZE); | ||
501 | if (S_ISREG(inode->i_mode)) { | ||
502 | inode->i_op = &qnx4_file_inode_operations; | ||
503 | inode->i_fop = &qnx4_file_operations; | ||
504 | inode->i_mapping->a_ops = &qnx4_aops; | ||
505 | qnx4_i(inode)->mmu_private = inode->i_size; | ||
506 | } else if (S_ISDIR(inode->i_mode)) { | ||
507 | inode->i_op = &qnx4_dir_inode_operations; | ||
508 | inode->i_fop = &qnx4_dir_operations; | ||
509 | } else if (S_ISLNK(inode->i_mode)) { | ||
510 | inode->i_op = &page_symlink_inode_operations; | ||
511 | inode->i_mapping->a_ops = &qnx4_aops; | ||
512 | qnx4_i(inode)->mmu_private = inode->i_size; | ||
513 | } else | ||
514 | printk("qnx4: bad inode %d on dev %s\n",ino,sb->s_id); | ||
515 | brelse(bh); | ||
516 | } | ||
517 | |||
518 | static kmem_cache_t *qnx4_inode_cachep; | ||
519 | |||
520 | static struct inode *qnx4_alloc_inode(struct super_block *sb) | ||
521 | { | ||
522 | struct qnx4_inode_info *ei; | ||
523 | ei = kmem_cache_alloc(qnx4_inode_cachep, SLAB_KERNEL); | ||
524 | if (!ei) | ||
525 | return NULL; | ||
526 | return &ei->vfs_inode; | ||
527 | } | ||
528 | |||
529 | static void qnx4_destroy_inode(struct inode *inode) | ||
530 | { | ||
531 | kmem_cache_free(qnx4_inode_cachep, qnx4_i(inode)); | ||
532 | } | ||
533 | |||
534 | static void init_once(void *foo, kmem_cache_t * cachep, | ||
535 | unsigned long flags) | ||
536 | { | ||
537 | struct qnx4_inode_info *ei = (struct qnx4_inode_info *) foo; | ||
538 | |||
539 | if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) == | ||
540 | SLAB_CTOR_CONSTRUCTOR) | ||
541 | inode_init_once(&ei->vfs_inode); | ||
542 | } | ||
543 | |||
544 | static int init_inodecache(void) | ||
545 | { | ||
546 | qnx4_inode_cachep = kmem_cache_create("qnx4_inode_cache", | ||
547 | sizeof(struct qnx4_inode_info), | ||
548 | 0, SLAB_RECLAIM_ACCOUNT, | ||
549 | init_once, NULL); | ||
550 | if (qnx4_inode_cachep == NULL) | ||
551 | return -ENOMEM; | ||
552 | return 0; | ||
553 | } | ||
554 | |||
555 | static void destroy_inodecache(void) | ||
556 | { | ||
557 | if (kmem_cache_destroy(qnx4_inode_cachep)) | ||
558 | printk(KERN_INFO | ||
559 | "qnx4_inode_cache: not all structures were freed\n"); | ||
560 | } | ||
561 | |||
562 | static struct super_block *qnx4_get_sb(struct file_system_type *fs_type, | ||
563 | int flags, const char *dev_name, void *data) | ||
564 | { | ||
565 | return get_sb_bdev(fs_type, flags, dev_name, data, qnx4_fill_super); | ||
566 | } | ||
567 | |||
568 | static struct file_system_type qnx4_fs_type = { | ||
569 | .owner = THIS_MODULE, | ||
570 | .name = "qnx4", | ||
571 | .get_sb = qnx4_get_sb, | ||
572 | .kill_sb = kill_block_super, | ||
573 | .fs_flags = FS_REQUIRES_DEV, | ||
574 | }; | ||
575 | |||
576 | static int __init init_qnx4_fs(void) | ||
577 | { | ||
578 | int err; | ||
579 | |||
580 | err = init_inodecache(); | ||
581 | if (err) | ||
582 | return err; | ||
583 | |||
584 | err = register_filesystem(&qnx4_fs_type); | ||
585 | if (err) { | ||
586 | destroy_inodecache(); | ||
587 | return err; | ||
588 | } | ||
589 | |||
590 | printk("QNX4 filesystem 0.2.3 registered.\n"); | ||
591 | return 0; | ||
592 | } | ||
593 | |||
594 | static void __exit exit_qnx4_fs(void) | ||
595 | { | ||
596 | unregister_filesystem(&qnx4_fs_type); | ||
597 | destroy_inodecache(); | ||
598 | } | ||
599 | |||
600 | module_init(init_qnx4_fs) | ||
601 | module_exit(exit_qnx4_fs) | ||
602 | MODULE_LICENSE("GPL"); | ||
603 | |||