blob: 40712867b8a874f9b4bca3df50faca3dc26e1292 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#include <linux/module.h>
16#include <linux/types.h>
17#include <linux/string.h>
18#include <linux/errno.h>
19#include <linux/slab.h>
20#include <linux/fs.h>
21#include <linux/qnx4_fs.h>
22#include <linux/init.h>
23#include <linux/highuid.h>
24#include <linux/smp_lock.h>
25#include <linux/pagemap.h>
26#include <linux/buffer_head.h>
Al Viro79d25762009-06-07 09:30:08 -040027#include <linux/writeback.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070028#include <linux/vfs.h>
29#include <asm/uaccess.h>
30
31#define QNX4_VERSION 4
32#define QNX4_BMNAME ".bitmap"
33
Josef 'Jeff' Sipekee9b6d62007-02-12 00:55:41 -080034static const struct super_operations qnx4_sops;
Linus Torvalds1da177e2005-04-16 15:20:36 -070035
36#ifdef CONFIG_QNX4FS_RW
37
Linus Torvalds1da177e2005-04-16 15:20:36 -070038static void qnx4_delete_inode(struct inode *inode)
39{
40 QNX4DEBUG(("qnx4: deleting inode [%lu]\n", (unsigned long) inode->i_ino));
Mark Fashehfef26652005-09-09 13:01:31 -070041 truncate_inode_pages(&inode->i_data, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070042 inode->i_size = 0;
43 qnx4_truncate(inode);
44 lock_kernel();
45 qnx4_free_inode(inode);
46 unlock_kernel();
47}
48
Al Viro79d25762009-06-07 09:30:08 -040049static int qnx4_write_inode(struct inode *inode, int do_sync)
Linus Torvalds1da177e2005-04-16 15:20:36 -070050{
51 struct qnx4_inode_entry *raw_inode;
52 int block, ino;
53 struct buffer_head *bh;
54 ino = inode->i_ino;
55
56 QNX4DEBUG(("qnx4: write inode 1.\n"));
57 if (inode->i_nlink == 0) {
58 return 0;
59 }
60 if (!ino) {
61 printk("qnx4: bad inode number on dev %s: %d is out of range\n",
62 inode->i_sb->s_id, ino);
63 return -EIO;
64 }
65 QNX4DEBUG(("qnx4: write inode 2.\n"));
66 block = ino / QNX4_INODES_PER_BLOCK;
67 lock_kernel();
68 if (!(bh = sb_bread(inode->i_sb, block))) {
69 printk("qnx4: major problem: unable to read inode from dev "
70 "%s\n", inode->i_sb->s_id);
71 unlock_kernel();
72 return -EIO;
73 }
74 raw_inode = ((struct qnx4_inode_entry *) bh->b_data) +
75 (ino % QNX4_INODES_PER_BLOCK);
76 raw_inode->di_mode = cpu_to_le16(inode->i_mode);
77 raw_inode->di_uid = cpu_to_le16(fs_high2lowuid(inode->i_uid));
78 raw_inode->di_gid = cpu_to_le16(fs_high2lowgid(inode->i_gid));
79 raw_inode->di_nlink = cpu_to_le16(inode->i_nlink);
80 raw_inode->di_size = cpu_to_le32(inode->i_size);
81 raw_inode->di_mtime = cpu_to_le32(inode->i_mtime.tv_sec);
82 raw_inode->di_atime = cpu_to_le32(inode->i_atime.tv_sec);
83 raw_inode->di_ctime = cpu_to_le32(inode->i_ctime.tv_sec);
84 raw_inode->di_first_xtnt.xtnt_size = cpu_to_le32(inode->i_blocks);
85 mark_buffer_dirty(bh);
Al Viro79d25762009-06-07 09:30:08 -040086 if (do_sync) {
87 sync_dirty_buffer(bh);
88 if (buffer_req(bh) && !buffer_uptodate(bh)) {
89 printk("qnx4: IO error syncing inode [%s:%08x]\n",
90 inode->i_sb->s_id, ino);
91 brelse(bh);
92 unlock_kernel();
93 return -EIO;
94 }
95 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070096 brelse(bh);
97 unlock_kernel();
98 return 0;
99}
100
101#endif
102
103static void qnx4_put_super(struct super_block *sb);
104static struct inode *qnx4_alloc_inode(struct super_block *sb);
105static void qnx4_destroy_inode(struct inode *inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106static int qnx4_remount(struct super_block *sb, int *flags, char *data);
David Howells726c3342006-06-23 02:02:58 -0700107static int qnx4_statfs(struct dentry *, struct kstatfs *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108
Josef 'Jeff' Sipekee9b6d62007-02-12 00:55:41 -0800109static const struct super_operations qnx4_sops =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110{
111 .alloc_inode = qnx4_alloc_inode,
112 .destroy_inode = qnx4_destroy_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113 .put_super = qnx4_put_super,
114 .statfs = qnx4_statfs,
115 .remount_fs = qnx4_remount,
116#ifdef CONFIG_QNX4FS_RW
117 .write_inode = qnx4_write_inode,
118 .delete_inode = qnx4_delete_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119#endif
120};
121
122static int qnx4_remount(struct super_block *sb, int *flags, char *data)
123{
124 struct qnx4_sb_info *qs;
125
126 qs = qnx4_sb(sb);
127 qs->Version = QNX4_VERSION;
128#ifndef CONFIG_QNX4FS_RW
129 *flags |= MS_RDONLY;
130#endif
131 if (*flags & MS_RDONLY) {
132 return 0;
133 }
134
135 mark_buffer_dirty(qs->sb_buf);
136
137 return 0;
138}
139
140static struct buffer_head *qnx4_getblk(struct inode *inode, int nr,
141 int create)
142{
143 struct buffer_head *result = NULL;
144
145 if ( nr >= 0 )
146 nr = qnx4_block_map( inode, nr );
147 if (nr) {
148 result = sb_getblk(inode->i_sb, nr);
149 return result;
150 }
151 if (!create) {
152 return NULL;
153 }
154#if 0
155 tmp = qnx4_new_block(inode->i_sb);
156 if (!tmp) {
157 return NULL;
158 }
159 result = sb_getblk(inode->i_sb, tmp);
160 if (tst) {
161 qnx4_free_block(inode->i_sb, tmp);
162 brelse(result);
163 goto repeat;
164 }
165 tst = tmp;
166#endif
167 inode->i_ctime = CURRENT_TIME_SEC;
168 mark_inode_dirty(inode);
169 return result;
170}
171
172struct buffer_head *qnx4_bread(struct inode *inode, int block, int create)
173{
174 struct buffer_head *bh;
175
176 bh = qnx4_getblk(inode, block, create);
177 if (!bh || buffer_uptodate(bh)) {
178 return bh;
179 }
180 ll_rw_block(READ, 1, &bh);
181 wait_on_buffer(bh);
182 if (buffer_uptodate(bh)) {
183 return bh;
184 }
185 brelse(bh);
186
187 return NULL;
188}
189
190static int qnx4_get_block( struct inode *inode, sector_t iblock, struct buffer_head *bh, int create )
191{
192 unsigned long phys;
193
194 QNX4DEBUG(("qnx4: qnx4_get_block inode=[%ld] iblock=[%ld]\n",inode->i_ino,iblock));
195
196 phys = qnx4_block_map( inode, iblock );
197 if ( phys ) {
198 // logical block is before EOF
199 map_bh(bh, inode->i_sb, phys);
200 } else if ( create ) {
201 // to be done.
202 }
203 return 0;
204}
205
206unsigned long qnx4_block_map( struct inode *inode, long iblock )
207{
208 int ix;
209 long offset, i_xblk;
210 unsigned long block = 0;
211 struct buffer_head *bh = NULL;
212 struct qnx4_xblk *xblk = NULL;
213 struct qnx4_inode_entry *qnx4_inode = qnx4_raw_inode(inode);
Alexey Dobriyan75043cb2005-06-24 20:52:52 +0000214 u16 nxtnt = le16_to_cpu(qnx4_inode->di_num_xtnts);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215
216 if ( iblock < le32_to_cpu(qnx4_inode->di_first_xtnt.xtnt_size) ) {
217 // iblock is in the first extent. This is easy.
218 block = le32_to_cpu(qnx4_inode->di_first_xtnt.xtnt_blk) + iblock - 1;
219 } else {
220 // iblock is beyond first extent. We have to follow the extent chain.
221 i_xblk = le32_to_cpu(qnx4_inode->di_xblk);
222 offset = iblock - le32_to_cpu(qnx4_inode->di_first_xtnt.xtnt_size);
223 ix = 0;
224 while ( --nxtnt > 0 ) {
225 if ( ix == 0 ) {
226 // read next xtnt block.
227 bh = sb_bread(inode->i_sb, i_xblk - 1);
228 if ( !bh ) {
229 QNX4DEBUG(("qnx4: I/O error reading xtnt block [%ld])\n", i_xblk - 1));
230 return -EIO;
231 }
232 xblk = (struct qnx4_xblk*)bh->b_data;
233 if ( memcmp( xblk->xblk_signature, "IamXblk", 7 ) ) {
234 QNX4DEBUG(("qnx4: block at %ld is not a valid xtnt\n", qnx4_inode->i_xblk));
235 return -EIO;
236 }
237 }
238 if ( offset < le32_to_cpu(xblk->xblk_xtnts[ix].xtnt_size) ) {
239 // got it!
240 block = le32_to_cpu(xblk->xblk_xtnts[ix].xtnt_blk) + offset - 1;
241 break;
242 }
243 offset -= le32_to_cpu(xblk->xblk_xtnts[ix].xtnt_size);
244 if ( ++ix >= xblk->xblk_num_xtnts ) {
245 i_xblk = le32_to_cpu(xblk->xblk_next_xblk);
246 ix = 0;
247 brelse( bh );
248 bh = NULL;
249 }
250 }
251 if ( bh )
252 brelse( bh );
253 }
254
255 QNX4DEBUG(("qnx4: mapping block %ld of inode %ld = %ld\n",iblock,inode->i_ino,block));
256 return block;
257}
258
David Howells726c3342006-06-23 02:02:58 -0700259static int qnx4_statfs(struct dentry *dentry, struct kstatfs *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260{
David Howells726c3342006-06-23 02:02:58 -0700261 struct super_block *sb = dentry->d_sb;
Coly Li5b76dc02009-04-02 16:59:40 -0700262 u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
David Howells726c3342006-06-23 02:02:58 -0700263
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 lock_kernel();
265
266 buf->f_type = sb->s_magic;
267 buf->f_bsize = sb->s_blocksize;
268 buf->f_blocks = le32_to_cpu(qnx4_sb(sb)->BitMap->di_size) * 8;
269 buf->f_bfree = qnx4_count_free_blocks(sb);
270 buf->f_bavail = buf->f_bfree;
271 buf->f_namelen = QNX4_NAME_MAX;
Coly Li5b76dc02009-04-02 16:59:40 -0700272 buf->f_fsid.val[0] = (u32)id;
273 buf->f_fsid.val[1] = (u32)(id >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274
275 unlock_kernel();
276
277 return 0;
278}
279
280/*
281 * Check the root directory of the filesystem to make sure
282 * it really _is_ a qnx4 filesystem, and to check the size
283 * of the directory entry.
284 */
285static const char *qnx4_checkroot(struct super_block *sb)
286{
287 struct buffer_head *bh;
288 struct qnx4_inode_entry *rootdir;
289 int rd, rl;
290 int i, j;
291 int found = 0;
292
293 if (*(qnx4_sb(sb)->sb->RootDir.di_fname) != '/') {
294 return "no qnx4 filesystem (no root dir).";
295 } else {
296 QNX4DEBUG(("QNX4 filesystem found on dev %s.\n", sb->s_id));
297 rd = le32_to_cpu(qnx4_sb(sb)->sb->RootDir.di_first_xtnt.xtnt_blk) - 1;
298 rl = le32_to_cpu(qnx4_sb(sb)->sb->RootDir.di_first_xtnt.xtnt_size);
299 for (j = 0; j < rl; j++) {
300 bh = sb_bread(sb, rd + j); /* root dir, first block */
301 if (bh == NULL) {
302 return "unable to read root entry.";
303 }
304 for (i = 0; i < QNX4_INODES_PER_BLOCK; i++) {
305 rootdir = (struct qnx4_inode_entry *) (bh->b_data + i * QNX4_DIR_ENTRY_SIZE);
306 if (rootdir->di_fname != NULL) {
307 QNX4DEBUG(("Rootdir entry found : [%s]\n", rootdir->di_fname));
308 if (!strncmp(rootdir->di_fname, QNX4_BMNAME, sizeof QNX4_BMNAME)) {
309 found = 1;
310 qnx4_sb(sb)->BitMap = kmalloc( sizeof( struct qnx4_inode_entry ), GFP_KERNEL );
311 if (!qnx4_sb(sb)->BitMap) {
312 brelse (bh);
313 return "not enough memory for bitmap inode";
314 }
315 memcpy( qnx4_sb(sb)->BitMap, rootdir, sizeof( struct qnx4_inode_entry ) ); /* keep bitmap inode known */
316 break;
317 }
318 }
319 }
320 brelse(bh);
321 if (found != 0) {
322 break;
323 }
324 }
325 if (found == 0) {
326 return "bitmap file not found.";
327 }
328 }
329 return NULL;
330}
331
332static int qnx4_fill_super(struct super_block *s, void *data, int silent)
333{
334 struct buffer_head *bh;
335 struct inode *root;
336 const char *errmsg;
337 struct qnx4_sb_info *qs;
David Howells2b7e5bc2008-02-07 00:15:45 -0800338 int ret = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339
Panagiotis Issarisf8314dc2006-09-27 01:49:37 -0700340 qs = kzalloc(sizeof(struct qnx4_sb_info), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 if (!qs)
342 return -ENOMEM;
343 s->s_fs_info = qs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344
345 sb_set_blocksize(s, QNX4_BLOCK_SIZE);
346
347 /* Check the superblock signature. Since the qnx4 code is
348 dangerous, we should leave as quickly as possible
349 if we don't belong here... */
350 bh = sb_bread(s, 1);
351 if (!bh) {
352 printk("qnx4: unable to read the superblock\n");
353 goto outnobh;
354 }
Alexey Dobriyan75043cb2005-06-24 20:52:52 +0000355 if ( le32_to_cpup((__le32*) bh->b_data) != QNX4_SUPER_MAGIC ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 if (!silent)
357 printk("qnx4: wrong fsid in superblock.\n");
358 goto out;
359 }
360 s->s_op = &qnx4_sops;
361 s->s_magic = QNX4_SUPER_MAGIC;
362#ifndef CONFIG_QNX4FS_RW
363 s->s_flags |= MS_RDONLY; /* Yup, read-only yet */
364#endif
365 qnx4_sb(s)->sb_buf = bh;
366 qnx4_sb(s)->sb = (struct qnx4_super_block *) bh->b_data;
367
368
369 /* check before allocating dentries, inodes, .. */
370 errmsg = qnx4_checkroot(s);
371 if (errmsg != NULL) {
372 if (!silent)
373 printk("qnx4: %s\n", errmsg);
374 goto out;
375 }
376
377 /* does root not have inode number QNX4_ROOT_INO ?? */
David Howells2b7e5bc2008-02-07 00:15:45 -0800378 root = qnx4_iget(s, QNX4_ROOT_INO * QNX4_INODES_PER_BLOCK);
379 if (IS_ERR(root)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 printk("qnx4: get inode failed\n");
David Howells2b7e5bc2008-02-07 00:15:45 -0800381 ret = PTR_ERR(root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 goto out;
383 }
384
David Howells2b7e5bc2008-02-07 00:15:45 -0800385 ret = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 s->s_root = d_alloc_root(root);
387 if (s->s_root == NULL)
388 goto outi;
389
390 brelse(bh);
391
392 return 0;
393
394 outi:
395 iput(root);
396 out:
397 brelse(bh);
398 outnobh:
399 kfree(qs);
400 s->s_fs_info = NULL;
David Howells2b7e5bc2008-02-07 00:15:45 -0800401 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402}
403
404static void qnx4_put_super(struct super_block *sb)
405{
406 struct qnx4_sb_info *qs = qnx4_sb(sb);
407 kfree( qs->BitMap );
408 kfree( qs );
409 sb->s_fs_info = NULL;
410 return;
411}
412
413static int qnx4_writepage(struct page *page, struct writeback_control *wbc)
414{
415 return block_write_full_page(page,qnx4_get_block, wbc);
416}
Nick Pigginf8706182007-10-16 01:25:12 -0700417
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418static int qnx4_readpage(struct file *file, struct page *page)
419{
420 return block_read_full_page(page,qnx4_get_block);
421}
Nick Pigginf8706182007-10-16 01:25:12 -0700422
423static int qnx4_write_begin(struct file *file, struct address_space *mapping,
424 loff_t pos, unsigned len, unsigned flags,
425 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426{
Nick Pigginf8706182007-10-16 01:25:12 -0700427 struct qnx4_inode_info *qnx4_inode = qnx4_i(mapping->host);
428 *pagep = NULL;
429 return cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
430 qnx4_get_block,
431 &qnx4_inode->mmu_private);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432}
433static sector_t qnx4_bmap(struct address_space *mapping, sector_t block)
434{
435 return generic_block_bmap(mapping,block,qnx4_get_block);
436}
Christoph Hellwigf5e54d62006-06-28 04:26:44 -0700437static const struct address_space_operations qnx4_aops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 .readpage = qnx4_readpage,
439 .writepage = qnx4_writepage,
440 .sync_page = block_sync_page,
Nick Pigginf8706182007-10-16 01:25:12 -0700441 .write_begin = qnx4_write_begin,
442 .write_end = generic_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 .bmap = qnx4_bmap
444};
445
David Howells2b7e5bc2008-02-07 00:15:45 -0800446struct inode *qnx4_iget(struct super_block *sb, unsigned long ino)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447{
448 struct buffer_head *bh;
449 struct qnx4_inode_entry *raw_inode;
David Howells2b7e5bc2008-02-07 00:15:45 -0800450 int block;
451 struct qnx4_inode_entry *qnx4_inode;
452 struct inode *inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453
David Howells2b7e5bc2008-02-07 00:15:45 -0800454 inode = iget_locked(sb, ino);
455 if (!inode)
456 return ERR_PTR(-ENOMEM);
457 if (!(inode->i_state & I_NEW))
458 return inode;
459
460 qnx4_inode = qnx4_raw_inode(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 inode->i_mode = 0;
462
463 QNX4DEBUG(("Reading inode : [%d]\n", ino));
464 if (!ino) {
David Howells2b7e5bc2008-02-07 00:15:45 -0800465 printk(KERN_ERR "qnx4: bad inode number on dev %s: %lu is "
466 "out of range\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 sb->s_id, ino);
David Howells2b7e5bc2008-02-07 00:15:45 -0800468 iget_failed(inode);
469 return ERR_PTR(-EIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470 }
471 block = ino / QNX4_INODES_PER_BLOCK;
472
473 if (!(bh = sb_bread(sb, block))) {
474 printk("qnx4: major problem: unable to read inode from dev "
475 "%s\n", sb->s_id);
David Howells2b7e5bc2008-02-07 00:15:45 -0800476 iget_failed(inode);
477 return ERR_PTR(-EIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 }
479 raw_inode = ((struct qnx4_inode_entry *) bh->b_data) +
480 (ino % QNX4_INODES_PER_BLOCK);
481
482 inode->i_mode = le16_to_cpu(raw_inode->di_mode);
483 inode->i_uid = (uid_t)le16_to_cpu(raw_inode->di_uid);
484 inode->i_gid = (gid_t)le16_to_cpu(raw_inode->di_gid);
485 inode->i_nlink = le16_to_cpu(raw_inode->di_nlink);
486 inode->i_size = le32_to_cpu(raw_inode->di_size);
487 inode->i_mtime.tv_sec = le32_to_cpu(raw_inode->di_mtime);
488 inode->i_mtime.tv_nsec = 0;
489 inode->i_atime.tv_sec = le32_to_cpu(raw_inode->di_atime);
490 inode->i_atime.tv_nsec = 0;
491 inode->i_ctime.tv_sec = le32_to_cpu(raw_inode->di_ctime);
492 inode->i_ctime.tv_nsec = 0;
493 inode->i_blocks = le32_to_cpu(raw_inode->di_first_xtnt.xtnt_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494
495 memcpy(qnx4_inode, raw_inode, QNX4_DIR_ENTRY_SIZE);
496 if (S_ISREG(inode->i_mode)) {
497 inode->i_op = &qnx4_file_inode_operations;
498 inode->i_fop = &qnx4_file_operations;
499 inode->i_mapping->a_ops = &qnx4_aops;
500 qnx4_i(inode)->mmu_private = inode->i_size;
501 } else if (S_ISDIR(inode->i_mode)) {
502 inode->i_op = &qnx4_dir_inode_operations;
503 inode->i_fop = &qnx4_dir_operations;
504 } else if (S_ISLNK(inode->i_mode)) {
505 inode->i_op = &page_symlink_inode_operations;
506 inode->i_mapping->a_ops = &qnx4_aops;
507 qnx4_i(inode)->mmu_private = inode->i_size;
David Howells2b7e5bc2008-02-07 00:15:45 -0800508 } else {
509 printk(KERN_ERR "qnx4: bad inode %lu on dev %s\n",
510 ino, sb->s_id);
511 iget_failed(inode);
512 brelse(bh);
513 return ERR_PTR(-EIO);
514 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 brelse(bh);
David Howells2b7e5bc2008-02-07 00:15:45 -0800516 unlock_new_inode(inode);
517 return inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518}
519
Christoph Lametere18b8902006-12-06 20:33:20 -0800520static struct kmem_cache *qnx4_inode_cachep;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521
522static struct inode *qnx4_alloc_inode(struct super_block *sb)
523{
524 struct qnx4_inode_info *ei;
Christoph Lametere94b1762006-12-06 20:33:17 -0800525 ei = kmem_cache_alloc(qnx4_inode_cachep, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 if (!ei)
527 return NULL;
528 return &ei->vfs_inode;
529}
530
531static void qnx4_destroy_inode(struct inode *inode)
532{
533 kmem_cache_free(qnx4_inode_cachep, qnx4_i(inode));
534}
535
Alexey Dobriyan51cc5062008-07-25 19:45:34 -0700536static void init_once(void *foo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537{
538 struct qnx4_inode_info *ei = (struct qnx4_inode_info *) foo;
539
Christoph Lametera35afb82007-05-16 22:10:57 -0700540 inode_init_once(&ei->vfs_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541}
542
543static int init_inodecache(void)
544{
545 qnx4_inode_cachep = kmem_cache_create("qnx4_inode_cache",
546 sizeof(struct qnx4_inode_info),
Paul Jacksonfffb60f2006-03-24 03:16:06 -0800547 0, (SLAB_RECLAIM_ACCOUNT|
548 SLAB_MEM_SPREAD),
Paul Mundt20c2df82007-07-20 10:11:58 +0900549 init_once);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 if (qnx4_inode_cachep == NULL)
551 return -ENOMEM;
552 return 0;
553}
554
555static void destroy_inodecache(void)
556{
Alexey Dobriyan1a1d92c2006-09-27 01:49:40 -0700557 kmem_cache_destroy(qnx4_inode_cachep);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558}
559
David Howells454e2392006-06-23 02:02:57 -0700560static int qnx4_get_sb(struct file_system_type *fs_type,
561 int flags, const char *dev_name, void *data, struct vfsmount *mnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562{
David Howells454e2392006-06-23 02:02:57 -0700563 return get_sb_bdev(fs_type, flags, dev_name, data, qnx4_fill_super,
564 mnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565}
566
567static struct file_system_type qnx4_fs_type = {
568 .owner = THIS_MODULE,
569 .name = "qnx4",
570 .get_sb = qnx4_get_sb,
571 .kill_sb = kill_block_super,
572 .fs_flags = FS_REQUIRES_DEV,
573};
574
575static int __init init_qnx4_fs(void)
576{
577 int err;
578
579 err = init_inodecache();
580 if (err)
581 return err;
582
583 err = register_filesystem(&qnx4_fs_type);
584 if (err) {
585 destroy_inodecache();
586 return err;
587 }
588
589 printk("QNX4 filesystem 0.2.3 registered.\n");
590 return 0;
591}
592
593static void __exit exit_qnx4_fs(void)
594{
595 unregister_filesystem(&qnx4_fs_type);
596 destroy_inodecache();
597}
598
599module_init(init_qnx4_fs)
600module_exit(exit_qnx4_fs)
601MODULE_LICENSE("GPL");
602