11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * QNX4 file system, Linux implementation. 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Version : 0.2.1 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * Using parts of the xiafs filesystem. 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * History : 91da177e4SLinus Torvalds * 101da177e4SLinus Torvalds * 01-06-1998 by Richard Frowijn : first release. 111da177e4SLinus Torvalds * 20-06-1998 by Frank Denis : Linux 2.1.99+ support, boot signature, misc. 121da177e4SLinus Torvalds * 30-06-1998 by Frank Denis : first step to write inodes. 131da177e4SLinus Torvalds */ 141da177e4SLinus Torvalds 151da177e4SLinus Torvalds #include <linux/config.h> 161da177e4SLinus Torvalds #include <linux/module.h> 171da177e4SLinus Torvalds #include <linux/types.h> 181da177e4SLinus Torvalds #include <linux/string.h> 191da177e4SLinus Torvalds #include <linux/errno.h> 201da177e4SLinus Torvalds #include <linux/slab.h> 211da177e4SLinus Torvalds #include <linux/fs.h> 221da177e4SLinus Torvalds #include <linux/qnx4_fs.h> 231da177e4SLinus Torvalds #include <linux/init.h> 241da177e4SLinus Torvalds #include <linux/highuid.h> 251da177e4SLinus Torvalds #include <linux/smp_lock.h> 261da177e4SLinus Torvalds #include <linux/pagemap.h> 271da177e4SLinus Torvalds #include <linux/buffer_head.h> 281da177e4SLinus Torvalds #include <linux/vfs.h> 291da177e4SLinus Torvalds #include <asm/uaccess.h> 301da177e4SLinus Torvalds 311da177e4SLinus Torvalds #define QNX4_VERSION 4 321da177e4SLinus Torvalds #define QNX4_BMNAME ".bitmap" 331da177e4SLinus Torvalds 341da177e4SLinus Torvalds static struct super_operations qnx4_sops; 351da177e4SLinus Torvalds 361da177e4SLinus Torvalds #ifdef CONFIG_QNX4FS_RW 371da177e4SLinus Torvalds 381da177e4SLinus Torvalds int qnx4_sync_inode(struct inode *inode) 391da177e4SLinus Torvalds { 401da177e4SLinus Torvalds int err = 0; 411da177e4SLinus Torvalds # if 0 421da177e4SLinus Torvalds struct buffer_head *bh; 431da177e4SLinus Torvalds 441da177e4SLinus Torvalds bh = qnx4_update_inode(inode); 451da177e4SLinus Torvalds if (bh && buffer_dirty(bh)) 461da177e4SLinus Torvalds { 471da177e4SLinus Torvalds sync_dirty_buffer(bh); 481da177e4SLinus Torvalds if (buffer_req(bh) && !buffer_uptodate(bh)) 491da177e4SLinus Torvalds { 501da177e4SLinus Torvalds printk ("IO error syncing qnx4 inode [%s:%08lx]\n", 511da177e4SLinus Torvalds inode->i_sb->s_id, inode->i_ino); 521da177e4SLinus Torvalds err = -1; 531da177e4SLinus Torvalds } 541da177e4SLinus Torvalds brelse (bh); 551da177e4SLinus Torvalds } else if (!bh) { 561da177e4SLinus Torvalds err = -1; 571da177e4SLinus Torvalds } 581da177e4SLinus Torvalds # endif 591da177e4SLinus Torvalds 601da177e4SLinus Torvalds return err; 611da177e4SLinus Torvalds } 621da177e4SLinus Torvalds 631da177e4SLinus Torvalds static void qnx4_delete_inode(struct inode *inode) 641da177e4SLinus Torvalds { 651da177e4SLinus Torvalds QNX4DEBUG(("qnx4: deleting inode [%lu]\n", (unsigned long) inode->i_ino)); 66fef26658SMark Fasheh truncate_inode_pages(&inode->i_data, 0); 671da177e4SLinus Torvalds inode->i_size = 0; 681da177e4SLinus Torvalds qnx4_truncate(inode); 691da177e4SLinus Torvalds lock_kernel(); 701da177e4SLinus Torvalds qnx4_free_inode(inode); 711da177e4SLinus Torvalds unlock_kernel(); 721da177e4SLinus Torvalds } 731da177e4SLinus Torvalds 741da177e4SLinus Torvalds static void qnx4_write_super(struct super_block *sb) 751da177e4SLinus Torvalds { 761da177e4SLinus Torvalds lock_kernel(); 771da177e4SLinus Torvalds QNX4DEBUG(("qnx4: write_super\n")); 781da177e4SLinus Torvalds sb->s_dirt = 0; 791da177e4SLinus Torvalds unlock_kernel(); 801da177e4SLinus Torvalds } 811da177e4SLinus Torvalds 821da177e4SLinus Torvalds static int qnx4_write_inode(struct inode *inode, int unused) 831da177e4SLinus Torvalds { 841da177e4SLinus Torvalds struct qnx4_inode_entry *raw_inode; 851da177e4SLinus Torvalds int block, ino; 861da177e4SLinus Torvalds struct buffer_head *bh; 871da177e4SLinus Torvalds ino = inode->i_ino; 881da177e4SLinus Torvalds 891da177e4SLinus Torvalds QNX4DEBUG(("qnx4: write inode 1.\n")); 901da177e4SLinus Torvalds if (inode->i_nlink == 0) { 911da177e4SLinus Torvalds return 0; 921da177e4SLinus Torvalds } 931da177e4SLinus Torvalds if (!ino) { 941da177e4SLinus Torvalds printk("qnx4: bad inode number on dev %s: %d is out of range\n", 951da177e4SLinus Torvalds inode->i_sb->s_id, ino); 961da177e4SLinus Torvalds return -EIO; 971da177e4SLinus Torvalds } 981da177e4SLinus Torvalds QNX4DEBUG(("qnx4: write inode 2.\n")); 991da177e4SLinus Torvalds block = ino / QNX4_INODES_PER_BLOCK; 1001da177e4SLinus Torvalds lock_kernel(); 1011da177e4SLinus Torvalds if (!(bh = sb_bread(inode->i_sb, block))) { 1021da177e4SLinus Torvalds printk("qnx4: major problem: unable to read inode from dev " 1031da177e4SLinus Torvalds "%s\n", inode->i_sb->s_id); 1041da177e4SLinus Torvalds unlock_kernel(); 1051da177e4SLinus Torvalds return -EIO; 1061da177e4SLinus Torvalds } 1071da177e4SLinus Torvalds raw_inode = ((struct qnx4_inode_entry *) bh->b_data) + 1081da177e4SLinus Torvalds (ino % QNX4_INODES_PER_BLOCK); 1091da177e4SLinus Torvalds raw_inode->di_mode = cpu_to_le16(inode->i_mode); 1101da177e4SLinus Torvalds raw_inode->di_uid = cpu_to_le16(fs_high2lowuid(inode->i_uid)); 1111da177e4SLinus Torvalds raw_inode->di_gid = cpu_to_le16(fs_high2lowgid(inode->i_gid)); 1121da177e4SLinus Torvalds raw_inode->di_nlink = cpu_to_le16(inode->i_nlink); 1131da177e4SLinus Torvalds raw_inode->di_size = cpu_to_le32(inode->i_size); 1141da177e4SLinus Torvalds raw_inode->di_mtime = cpu_to_le32(inode->i_mtime.tv_sec); 1151da177e4SLinus Torvalds raw_inode->di_atime = cpu_to_le32(inode->i_atime.tv_sec); 1161da177e4SLinus Torvalds raw_inode->di_ctime = cpu_to_le32(inode->i_ctime.tv_sec); 1171da177e4SLinus Torvalds raw_inode->di_first_xtnt.xtnt_size = cpu_to_le32(inode->i_blocks); 1181da177e4SLinus Torvalds mark_buffer_dirty(bh); 1191da177e4SLinus Torvalds brelse(bh); 1201da177e4SLinus Torvalds unlock_kernel(); 1211da177e4SLinus Torvalds return 0; 1221da177e4SLinus Torvalds } 1231da177e4SLinus Torvalds 1241da177e4SLinus Torvalds #endif 1251da177e4SLinus Torvalds 1261da177e4SLinus Torvalds static void qnx4_put_super(struct super_block *sb); 1271da177e4SLinus Torvalds static struct inode *qnx4_alloc_inode(struct super_block *sb); 1281da177e4SLinus Torvalds static void qnx4_destroy_inode(struct inode *inode); 1291da177e4SLinus Torvalds static void qnx4_read_inode(struct inode *); 1301da177e4SLinus Torvalds static int qnx4_remount(struct super_block *sb, int *flags, char *data); 131726c3342SDavid Howells static int qnx4_statfs(struct dentry *, struct kstatfs *); 1321da177e4SLinus Torvalds 1331da177e4SLinus Torvalds static struct super_operations qnx4_sops = 1341da177e4SLinus Torvalds { 1351da177e4SLinus Torvalds .alloc_inode = qnx4_alloc_inode, 1361da177e4SLinus Torvalds .destroy_inode = qnx4_destroy_inode, 1371da177e4SLinus Torvalds .read_inode = qnx4_read_inode, 1381da177e4SLinus Torvalds .put_super = qnx4_put_super, 1391da177e4SLinus Torvalds .statfs = qnx4_statfs, 1401da177e4SLinus Torvalds .remount_fs = qnx4_remount, 1411da177e4SLinus Torvalds #ifdef CONFIG_QNX4FS_RW 1421da177e4SLinus Torvalds .write_inode = qnx4_write_inode, 1431da177e4SLinus Torvalds .delete_inode = qnx4_delete_inode, 1441da177e4SLinus Torvalds .write_super = qnx4_write_super, 1451da177e4SLinus Torvalds #endif 1461da177e4SLinus Torvalds }; 1471da177e4SLinus Torvalds 1481da177e4SLinus Torvalds static int qnx4_remount(struct super_block *sb, int *flags, char *data) 1491da177e4SLinus Torvalds { 1501da177e4SLinus Torvalds struct qnx4_sb_info *qs; 1511da177e4SLinus Torvalds 1521da177e4SLinus Torvalds qs = qnx4_sb(sb); 1531da177e4SLinus Torvalds qs->Version = QNX4_VERSION; 1541da177e4SLinus Torvalds #ifndef CONFIG_QNX4FS_RW 1551da177e4SLinus Torvalds *flags |= MS_RDONLY; 1561da177e4SLinus Torvalds #endif 1571da177e4SLinus Torvalds if (*flags & MS_RDONLY) { 1581da177e4SLinus Torvalds return 0; 1591da177e4SLinus Torvalds } 1601da177e4SLinus Torvalds 1611da177e4SLinus Torvalds mark_buffer_dirty(qs->sb_buf); 1621da177e4SLinus Torvalds 1631da177e4SLinus Torvalds return 0; 1641da177e4SLinus Torvalds } 1651da177e4SLinus Torvalds 1661da177e4SLinus Torvalds static struct buffer_head *qnx4_getblk(struct inode *inode, int nr, 1671da177e4SLinus Torvalds int create) 1681da177e4SLinus Torvalds { 1691da177e4SLinus Torvalds struct buffer_head *result = NULL; 1701da177e4SLinus Torvalds 1711da177e4SLinus Torvalds if ( nr >= 0 ) 1721da177e4SLinus Torvalds nr = qnx4_block_map( inode, nr ); 1731da177e4SLinus Torvalds if (nr) { 1741da177e4SLinus Torvalds result = sb_getblk(inode->i_sb, nr); 1751da177e4SLinus Torvalds return result; 1761da177e4SLinus Torvalds } 1771da177e4SLinus Torvalds if (!create) { 1781da177e4SLinus Torvalds return NULL; 1791da177e4SLinus Torvalds } 1801da177e4SLinus Torvalds #if 0 1811da177e4SLinus Torvalds tmp = qnx4_new_block(inode->i_sb); 1821da177e4SLinus Torvalds if (!tmp) { 1831da177e4SLinus Torvalds return NULL; 1841da177e4SLinus Torvalds } 1851da177e4SLinus Torvalds result = sb_getblk(inode->i_sb, tmp); 1861da177e4SLinus Torvalds if (tst) { 1871da177e4SLinus Torvalds qnx4_free_block(inode->i_sb, tmp); 1881da177e4SLinus Torvalds brelse(result); 1891da177e4SLinus Torvalds goto repeat; 1901da177e4SLinus Torvalds } 1911da177e4SLinus Torvalds tst = tmp; 1921da177e4SLinus Torvalds #endif 1931da177e4SLinus Torvalds inode->i_ctime = CURRENT_TIME_SEC; 1941da177e4SLinus Torvalds mark_inode_dirty(inode); 1951da177e4SLinus Torvalds return result; 1961da177e4SLinus Torvalds } 1971da177e4SLinus Torvalds 1981da177e4SLinus Torvalds struct buffer_head *qnx4_bread(struct inode *inode, int block, int create) 1991da177e4SLinus Torvalds { 2001da177e4SLinus Torvalds struct buffer_head *bh; 2011da177e4SLinus Torvalds 2021da177e4SLinus Torvalds bh = qnx4_getblk(inode, block, create); 2031da177e4SLinus Torvalds if (!bh || buffer_uptodate(bh)) { 2041da177e4SLinus Torvalds return bh; 2051da177e4SLinus Torvalds } 2061da177e4SLinus Torvalds ll_rw_block(READ, 1, &bh); 2071da177e4SLinus Torvalds wait_on_buffer(bh); 2081da177e4SLinus Torvalds if (buffer_uptodate(bh)) { 2091da177e4SLinus Torvalds return bh; 2101da177e4SLinus Torvalds } 2111da177e4SLinus Torvalds brelse(bh); 2121da177e4SLinus Torvalds 2131da177e4SLinus Torvalds return NULL; 2141da177e4SLinus Torvalds } 2151da177e4SLinus Torvalds 2161da177e4SLinus Torvalds static int qnx4_get_block( struct inode *inode, sector_t iblock, struct buffer_head *bh, int create ) 2171da177e4SLinus Torvalds { 2181da177e4SLinus Torvalds unsigned long phys; 2191da177e4SLinus Torvalds 2201da177e4SLinus Torvalds QNX4DEBUG(("qnx4: qnx4_get_block inode=[%ld] iblock=[%ld]\n",inode->i_ino,iblock)); 2211da177e4SLinus Torvalds 2221da177e4SLinus Torvalds phys = qnx4_block_map( inode, iblock ); 2231da177e4SLinus Torvalds if ( phys ) { 2241da177e4SLinus Torvalds // logical block is before EOF 2251da177e4SLinus Torvalds map_bh(bh, inode->i_sb, phys); 2261da177e4SLinus Torvalds } else if ( create ) { 2271da177e4SLinus Torvalds // to be done. 2281da177e4SLinus Torvalds } 2291da177e4SLinus Torvalds return 0; 2301da177e4SLinus Torvalds } 2311da177e4SLinus Torvalds 2321da177e4SLinus Torvalds unsigned long qnx4_block_map( struct inode *inode, long iblock ) 2331da177e4SLinus Torvalds { 2341da177e4SLinus Torvalds int ix; 2351da177e4SLinus Torvalds long offset, i_xblk; 2361da177e4SLinus Torvalds unsigned long block = 0; 2371da177e4SLinus Torvalds struct buffer_head *bh = NULL; 2381da177e4SLinus Torvalds struct qnx4_xblk *xblk = NULL; 2391da177e4SLinus Torvalds struct qnx4_inode_entry *qnx4_inode = qnx4_raw_inode(inode); 24075043cb5SAlexey Dobriyan u16 nxtnt = le16_to_cpu(qnx4_inode->di_num_xtnts); 2411da177e4SLinus Torvalds 2421da177e4SLinus Torvalds if ( iblock < le32_to_cpu(qnx4_inode->di_first_xtnt.xtnt_size) ) { 2431da177e4SLinus Torvalds // iblock is in the first extent. This is easy. 2441da177e4SLinus Torvalds block = le32_to_cpu(qnx4_inode->di_first_xtnt.xtnt_blk) + iblock - 1; 2451da177e4SLinus Torvalds } else { 2461da177e4SLinus Torvalds // iblock is beyond first extent. We have to follow the extent chain. 2471da177e4SLinus Torvalds i_xblk = le32_to_cpu(qnx4_inode->di_xblk); 2481da177e4SLinus Torvalds offset = iblock - le32_to_cpu(qnx4_inode->di_first_xtnt.xtnt_size); 2491da177e4SLinus Torvalds ix = 0; 2501da177e4SLinus Torvalds while ( --nxtnt > 0 ) { 2511da177e4SLinus Torvalds if ( ix == 0 ) { 2521da177e4SLinus Torvalds // read next xtnt block. 2531da177e4SLinus Torvalds bh = sb_bread(inode->i_sb, i_xblk - 1); 2541da177e4SLinus Torvalds if ( !bh ) { 2551da177e4SLinus Torvalds QNX4DEBUG(("qnx4: I/O error reading xtnt block [%ld])\n", i_xblk - 1)); 2561da177e4SLinus Torvalds return -EIO; 2571da177e4SLinus Torvalds } 2581da177e4SLinus Torvalds xblk = (struct qnx4_xblk*)bh->b_data; 2591da177e4SLinus Torvalds if ( memcmp( xblk->xblk_signature, "IamXblk", 7 ) ) { 2601da177e4SLinus Torvalds QNX4DEBUG(("qnx4: block at %ld is not a valid xtnt\n", qnx4_inode->i_xblk)); 2611da177e4SLinus Torvalds return -EIO; 2621da177e4SLinus Torvalds } 2631da177e4SLinus Torvalds } 2641da177e4SLinus Torvalds if ( offset < le32_to_cpu(xblk->xblk_xtnts[ix].xtnt_size) ) { 2651da177e4SLinus Torvalds // got it! 2661da177e4SLinus Torvalds block = le32_to_cpu(xblk->xblk_xtnts[ix].xtnt_blk) + offset - 1; 2671da177e4SLinus Torvalds break; 2681da177e4SLinus Torvalds } 2691da177e4SLinus Torvalds offset -= le32_to_cpu(xblk->xblk_xtnts[ix].xtnt_size); 2701da177e4SLinus Torvalds if ( ++ix >= xblk->xblk_num_xtnts ) { 2711da177e4SLinus Torvalds i_xblk = le32_to_cpu(xblk->xblk_next_xblk); 2721da177e4SLinus Torvalds ix = 0; 2731da177e4SLinus Torvalds brelse( bh ); 2741da177e4SLinus Torvalds bh = NULL; 2751da177e4SLinus Torvalds } 2761da177e4SLinus Torvalds } 2771da177e4SLinus Torvalds if ( bh ) 2781da177e4SLinus Torvalds brelse( bh ); 2791da177e4SLinus Torvalds } 2801da177e4SLinus Torvalds 2811da177e4SLinus Torvalds QNX4DEBUG(("qnx4: mapping block %ld of inode %ld = %ld\n",iblock,inode->i_ino,block)); 2821da177e4SLinus Torvalds return block; 2831da177e4SLinus Torvalds } 2841da177e4SLinus Torvalds 285726c3342SDavid Howells static int qnx4_statfs(struct dentry *dentry, struct kstatfs *buf) 2861da177e4SLinus Torvalds { 287726c3342SDavid Howells struct super_block *sb = dentry->d_sb; 288726c3342SDavid Howells 2891da177e4SLinus Torvalds lock_kernel(); 2901da177e4SLinus Torvalds 2911da177e4SLinus Torvalds buf->f_type = sb->s_magic; 2921da177e4SLinus Torvalds buf->f_bsize = sb->s_blocksize; 2931da177e4SLinus Torvalds buf->f_blocks = le32_to_cpu(qnx4_sb(sb)->BitMap->di_size) * 8; 2941da177e4SLinus Torvalds buf->f_bfree = qnx4_count_free_blocks(sb); 2951da177e4SLinus Torvalds buf->f_bavail = buf->f_bfree; 2961da177e4SLinus Torvalds buf->f_namelen = QNX4_NAME_MAX; 2971da177e4SLinus Torvalds 2981da177e4SLinus Torvalds unlock_kernel(); 2991da177e4SLinus Torvalds 3001da177e4SLinus Torvalds return 0; 3011da177e4SLinus Torvalds } 3021da177e4SLinus Torvalds 3031da177e4SLinus Torvalds /* 3041da177e4SLinus Torvalds * Check the root directory of the filesystem to make sure 3051da177e4SLinus Torvalds * it really _is_ a qnx4 filesystem, and to check the size 3061da177e4SLinus Torvalds * of the directory entry. 3071da177e4SLinus Torvalds */ 3081da177e4SLinus Torvalds static const char *qnx4_checkroot(struct super_block *sb) 3091da177e4SLinus Torvalds { 3101da177e4SLinus Torvalds struct buffer_head *bh; 3111da177e4SLinus Torvalds struct qnx4_inode_entry *rootdir; 3121da177e4SLinus Torvalds int rd, rl; 3131da177e4SLinus Torvalds int i, j; 3141da177e4SLinus Torvalds int found = 0; 3151da177e4SLinus Torvalds 3161da177e4SLinus Torvalds if (*(qnx4_sb(sb)->sb->RootDir.di_fname) != '/') { 3171da177e4SLinus Torvalds return "no qnx4 filesystem (no root dir)."; 3181da177e4SLinus Torvalds } else { 3191da177e4SLinus Torvalds QNX4DEBUG(("QNX4 filesystem found on dev %s.\n", sb->s_id)); 3201da177e4SLinus Torvalds rd = le32_to_cpu(qnx4_sb(sb)->sb->RootDir.di_first_xtnt.xtnt_blk) - 1; 3211da177e4SLinus Torvalds rl = le32_to_cpu(qnx4_sb(sb)->sb->RootDir.di_first_xtnt.xtnt_size); 3221da177e4SLinus Torvalds for (j = 0; j < rl; j++) { 3231da177e4SLinus Torvalds bh = sb_bread(sb, rd + j); /* root dir, first block */ 3241da177e4SLinus Torvalds if (bh == NULL) { 3251da177e4SLinus Torvalds return "unable to read root entry."; 3261da177e4SLinus Torvalds } 3271da177e4SLinus Torvalds for (i = 0; i < QNX4_INODES_PER_BLOCK; i++) { 3281da177e4SLinus Torvalds rootdir = (struct qnx4_inode_entry *) (bh->b_data + i * QNX4_DIR_ENTRY_SIZE); 3291da177e4SLinus Torvalds if (rootdir->di_fname != NULL) { 3301da177e4SLinus Torvalds QNX4DEBUG(("Rootdir entry found : [%s]\n", rootdir->di_fname)); 3311da177e4SLinus Torvalds if (!strncmp(rootdir->di_fname, QNX4_BMNAME, sizeof QNX4_BMNAME)) { 3321da177e4SLinus Torvalds found = 1; 3331da177e4SLinus Torvalds qnx4_sb(sb)->BitMap = kmalloc( sizeof( struct qnx4_inode_entry ), GFP_KERNEL ); 3341da177e4SLinus Torvalds if (!qnx4_sb(sb)->BitMap) { 3351da177e4SLinus Torvalds brelse (bh); 3361da177e4SLinus Torvalds return "not enough memory for bitmap inode"; 3371da177e4SLinus Torvalds } 3381da177e4SLinus Torvalds memcpy( qnx4_sb(sb)->BitMap, rootdir, sizeof( struct qnx4_inode_entry ) ); /* keep bitmap inode known */ 3391da177e4SLinus Torvalds break; 3401da177e4SLinus Torvalds } 3411da177e4SLinus Torvalds } 3421da177e4SLinus Torvalds } 3431da177e4SLinus Torvalds brelse(bh); 3441da177e4SLinus Torvalds if (found != 0) { 3451da177e4SLinus Torvalds break; 3461da177e4SLinus Torvalds } 3471da177e4SLinus Torvalds } 3481da177e4SLinus Torvalds if (found == 0) { 3491da177e4SLinus Torvalds return "bitmap file not found."; 3501da177e4SLinus Torvalds } 3511da177e4SLinus Torvalds } 3521da177e4SLinus Torvalds return NULL; 3531da177e4SLinus Torvalds } 3541da177e4SLinus Torvalds 3551da177e4SLinus Torvalds static int qnx4_fill_super(struct super_block *s, void *data, int silent) 3561da177e4SLinus Torvalds { 3571da177e4SLinus Torvalds struct buffer_head *bh; 3581da177e4SLinus Torvalds struct inode *root; 3591da177e4SLinus Torvalds const char *errmsg; 3601da177e4SLinus Torvalds struct qnx4_sb_info *qs; 3611da177e4SLinus Torvalds 3621da177e4SLinus Torvalds qs = kmalloc(sizeof(struct qnx4_sb_info), GFP_KERNEL); 3631da177e4SLinus Torvalds if (!qs) 3641da177e4SLinus Torvalds return -ENOMEM; 3651da177e4SLinus Torvalds s->s_fs_info = qs; 3661da177e4SLinus Torvalds memset(qs, 0, sizeof(struct qnx4_sb_info)); 3671da177e4SLinus Torvalds 3681da177e4SLinus Torvalds sb_set_blocksize(s, QNX4_BLOCK_SIZE); 3691da177e4SLinus Torvalds 3701da177e4SLinus Torvalds /* Check the superblock signature. Since the qnx4 code is 3711da177e4SLinus Torvalds dangerous, we should leave as quickly as possible 3721da177e4SLinus Torvalds if we don't belong here... */ 3731da177e4SLinus Torvalds bh = sb_bread(s, 1); 3741da177e4SLinus Torvalds if (!bh) { 3751da177e4SLinus Torvalds printk("qnx4: unable to read the superblock\n"); 3761da177e4SLinus Torvalds goto outnobh; 3771da177e4SLinus Torvalds } 37875043cb5SAlexey Dobriyan if ( le32_to_cpup((__le32*) bh->b_data) != QNX4_SUPER_MAGIC ) { 3791da177e4SLinus Torvalds if (!silent) 3801da177e4SLinus Torvalds printk("qnx4: wrong fsid in superblock.\n"); 3811da177e4SLinus Torvalds goto out; 3821da177e4SLinus Torvalds } 3831da177e4SLinus Torvalds s->s_op = &qnx4_sops; 3841da177e4SLinus Torvalds s->s_magic = QNX4_SUPER_MAGIC; 3851da177e4SLinus Torvalds #ifndef CONFIG_QNX4FS_RW 3861da177e4SLinus Torvalds s->s_flags |= MS_RDONLY; /* Yup, read-only yet */ 3871da177e4SLinus Torvalds #endif 3881da177e4SLinus Torvalds qnx4_sb(s)->sb_buf = bh; 3891da177e4SLinus Torvalds qnx4_sb(s)->sb = (struct qnx4_super_block *) bh->b_data; 3901da177e4SLinus Torvalds 3911da177e4SLinus Torvalds 3921da177e4SLinus Torvalds /* check before allocating dentries, inodes, .. */ 3931da177e4SLinus Torvalds errmsg = qnx4_checkroot(s); 3941da177e4SLinus Torvalds if (errmsg != NULL) { 3951da177e4SLinus Torvalds if (!silent) 3961da177e4SLinus Torvalds printk("qnx4: %s\n", errmsg); 3971da177e4SLinus Torvalds goto out; 3981da177e4SLinus Torvalds } 3991da177e4SLinus Torvalds 4001da177e4SLinus Torvalds /* does root not have inode number QNX4_ROOT_INO ?? */ 4011da177e4SLinus Torvalds root = iget(s, QNX4_ROOT_INO * QNX4_INODES_PER_BLOCK); 4021da177e4SLinus Torvalds if (!root) { 4031da177e4SLinus Torvalds printk("qnx4: get inode failed\n"); 4041da177e4SLinus Torvalds goto out; 4051da177e4SLinus Torvalds } 4061da177e4SLinus Torvalds 4071da177e4SLinus Torvalds s->s_root = d_alloc_root(root); 4081da177e4SLinus Torvalds if (s->s_root == NULL) 4091da177e4SLinus Torvalds goto outi; 4101da177e4SLinus Torvalds 4111da177e4SLinus Torvalds brelse(bh); 4121da177e4SLinus Torvalds 4131da177e4SLinus Torvalds return 0; 4141da177e4SLinus Torvalds 4151da177e4SLinus Torvalds outi: 4161da177e4SLinus Torvalds iput(root); 4171da177e4SLinus Torvalds out: 4181da177e4SLinus Torvalds brelse(bh); 4191da177e4SLinus Torvalds outnobh: 4201da177e4SLinus Torvalds kfree(qs); 4211da177e4SLinus Torvalds s->s_fs_info = NULL; 4221da177e4SLinus Torvalds return -EINVAL; 4231da177e4SLinus Torvalds } 4241da177e4SLinus Torvalds 4251da177e4SLinus Torvalds static void qnx4_put_super(struct super_block *sb) 4261da177e4SLinus Torvalds { 4271da177e4SLinus Torvalds struct qnx4_sb_info *qs = qnx4_sb(sb); 4281da177e4SLinus Torvalds kfree( qs->BitMap ); 4291da177e4SLinus Torvalds kfree( qs ); 4301da177e4SLinus Torvalds sb->s_fs_info = NULL; 4311da177e4SLinus Torvalds return; 4321da177e4SLinus Torvalds } 4331da177e4SLinus Torvalds 4341da177e4SLinus Torvalds static int qnx4_writepage(struct page *page, struct writeback_control *wbc) 4351da177e4SLinus Torvalds { 4361da177e4SLinus Torvalds return block_write_full_page(page,qnx4_get_block, wbc); 4371da177e4SLinus Torvalds } 4381da177e4SLinus Torvalds static int qnx4_readpage(struct file *file, struct page *page) 4391da177e4SLinus Torvalds { 4401da177e4SLinus Torvalds return block_read_full_page(page,qnx4_get_block); 4411da177e4SLinus Torvalds } 4421da177e4SLinus Torvalds static int qnx4_prepare_write(struct file *file, struct page *page, 4431da177e4SLinus Torvalds unsigned from, unsigned to) 4441da177e4SLinus Torvalds { 4451da177e4SLinus Torvalds struct qnx4_inode_info *qnx4_inode = qnx4_i(page->mapping->host); 4461da177e4SLinus Torvalds return cont_prepare_write(page, from, to, qnx4_get_block, 4471da177e4SLinus Torvalds &qnx4_inode->mmu_private); 4481da177e4SLinus Torvalds } 4491da177e4SLinus Torvalds static sector_t qnx4_bmap(struct address_space *mapping, sector_t block) 4501da177e4SLinus Torvalds { 4511da177e4SLinus Torvalds return generic_block_bmap(mapping,block,qnx4_get_block); 4521da177e4SLinus Torvalds } 453f5e54d6eSChristoph Hellwig static const struct address_space_operations qnx4_aops = { 4541da177e4SLinus Torvalds .readpage = qnx4_readpage, 4551da177e4SLinus Torvalds .writepage = qnx4_writepage, 4561da177e4SLinus Torvalds .sync_page = block_sync_page, 4571da177e4SLinus Torvalds .prepare_write = qnx4_prepare_write, 4581da177e4SLinus Torvalds .commit_write = generic_commit_write, 4591da177e4SLinus Torvalds .bmap = qnx4_bmap 4601da177e4SLinus Torvalds }; 4611da177e4SLinus Torvalds 4621da177e4SLinus Torvalds static void qnx4_read_inode(struct inode *inode) 4631da177e4SLinus Torvalds { 4641da177e4SLinus Torvalds struct buffer_head *bh; 4651da177e4SLinus Torvalds struct qnx4_inode_entry *raw_inode; 4661da177e4SLinus Torvalds int block, ino; 4671da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 4681da177e4SLinus Torvalds struct qnx4_inode_entry *qnx4_inode = qnx4_raw_inode(inode); 4691da177e4SLinus Torvalds 4701da177e4SLinus Torvalds ino = inode->i_ino; 4711da177e4SLinus Torvalds inode->i_mode = 0; 4721da177e4SLinus Torvalds 4731da177e4SLinus Torvalds QNX4DEBUG(("Reading inode : [%d]\n", ino)); 4741da177e4SLinus Torvalds if (!ino) { 4751da177e4SLinus Torvalds printk("qnx4: bad inode number on dev %s: %d is out of range\n", 4761da177e4SLinus Torvalds sb->s_id, ino); 4771da177e4SLinus Torvalds return; 4781da177e4SLinus Torvalds } 4791da177e4SLinus Torvalds block = ino / QNX4_INODES_PER_BLOCK; 4801da177e4SLinus Torvalds 4811da177e4SLinus Torvalds if (!(bh = sb_bread(sb, block))) { 4821da177e4SLinus Torvalds printk("qnx4: major problem: unable to read inode from dev " 4831da177e4SLinus Torvalds "%s\n", sb->s_id); 4841da177e4SLinus Torvalds return; 4851da177e4SLinus Torvalds } 4861da177e4SLinus Torvalds raw_inode = ((struct qnx4_inode_entry *) bh->b_data) + 4871da177e4SLinus Torvalds (ino % QNX4_INODES_PER_BLOCK); 4881da177e4SLinus Torvalds 4891da177e4SLinus Torvalds inode->i_mode = le16_to_cpu(raw_inode->di_mode); 4901da177e4SLinus Torvalds inode->i_uid = (uid_t)le16_to_cpu(raw_inode->di_uid); 4911da177e4SLinus Torvalds inode->i_gid = (gid_t)le16_to_cpu(raw_inode->di_gid); 4921da177e4SLinus Torvalds inode->i_nlink = le16_to_cpu(raw_inode->di_nlink); 4931da177e4SLinus Torvalds inode->i_size = le32_to_cpu(raw_inode->di_size); 4941da177e4SLinus Torvalds inode->i_mtime.tv_sec = le32_to_cpu(raw_inode->di_mtime); 4951da177e4SLinus Torvalds inode->i_mtime.tv_nsec = 0; 4961da177e4SLinus Torvalds inode->i_atime.tv_sec = le32_to_cpu(raw_inode->di_atime); 4971da177e4SLinus Torvalds inode->i_atime.tv_nsec = 0; 4981da177e4SLinus Torvalds inode->i_ctime.tv_sec = le32_to_cpu(raw_inode->di_ctime); 4991da177e4SLinus Torvalds inode->i_ctime.tv_nsec = 0; 5001da177e4SLinus Torvalds inode->i_blocks = le32_to_cpu(raw_inode->di_first_xtnt.xtnt_size); 5011da177e4SLinus Torvalds inode->i_blksize = QNX4_DIR_ENTRY_SIZE; 5021da177e4SLinus Torvalds 5031da177e4SLinus Torvalds memcpy(qnx4_inode, raw_inode, QNX4_DIR_ENTRY_SIZE); 5041da177e4SLinus Torvalds if (S_ISREG(inode->i_mode)) { 5051da177e4SLinus Torvalds inode->i_op = &qnx4_file_inode_operations; 5061da177e4SLinus Torvalds inode->i_fop = &qnx4_file_operations; 5071da177e4SLinus Torvalds inode->i_mapping->a_ops = &qnx4_aops; 5081da177e4SLinus Torvalds qnx4_i(inode)->mmu_private = inode->i_size; 5091da177e4SLinus Torvalds } else if (S_ISDIR(inode->i_mode)) { 5101da177e4SLinus Torvalds inode->i_op = &qnx4_dir_inode_operations; 5111da177e4SLinus Torvalds inode->i_fop = &qnx4_dir_operations; 5121da177e4SLinus Torvalds } else if (S_ISLNK(inode->i_mode)) { 5131da177e4SLinus Torvalds inode->i_op = &page_symlink_inode_operations; 5141da177e4SLinus Torvalds inode->i_mapping->a_ops = &qnx4_aops; 5151da177e4SLinus Torvalds qnx4_i(inode)->mmu_private = inode->i_size; 5161da177e4SLinus Torvalds } else 5171da177e4SLinus Torvalds printk("qnx4: bad inode %d on dev %s\n",ino,sb->s_id); 5181da177e4SLinus Torvalds brelse(bh); 5191da177e4SLinus Torvalds } 5201da177e4SLinus Torvalds 5211da177e4SLinus Torvalds static kmem_cache_t *qnx4_inode_cachep; 5221da177e4SLinus Torvalds 5231da177e4SLinus Torvalds static struct inode *qnx4_alloc_inode(struct super_block *sb) 5241da177e4SLinus Torvalds { 5251da177e4SLinus Torvalds struct qnx4_inode_info *ei; 5261da177e4SLinus Torvalds ei = kmem_cache_alloc(qnx4_inode_cachep, SLAB_KERNEL); 5271da177e4SLinus Torvalds if (!ei) 5281da177e4SLinus Torvalds return NULL; 5291da177e4SLinus Torvalds return &ei->vfs_inode; 5301da177e4SLinus Torvalds } 5311da177e4SLinus Torvalds 5321da177e4SLinus Torvalds static void qnx4_destroy_inode(struct inode *inode) 5331da177e4SLinus Torvalds { 5341da177e4SLinus Torvalds kmem_cache_free(qnx4_inode_cachep, qnx4_i(inode)); 5351da177e4SLinus Torvalds } 5361da177e4SLinus Torvalds 5371da177e4SLinus Torvalds static void init_once(void *foo, kmem_cache_t * cachep, 5381da177e4SLinus Torvalds unsigned long flags) 5391da177e4SLinus Torvalds { 5401da177e4SLinus Torvalds struct qnx4_inode_info *ei = (struct qnx4_inode_info *) foo; 5411da177e4SLinus Torvalds 5421da177e4SLinus Torvalds if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) == 5431da177e4SLinus Torvalds SLAB_CTOR_CONSTRUCTOR) 5441da177e4SLinus Torvalds inode_init_once(&ei->vfs_inode); 5451da177e4SLinus Torvalds } 5461da177e4SLinus Torvalds 5471da177e4SLinus Torvalds static int init_inodecache(void) 5481da177e4SLinus Torvalds { 5491da177e4SLinus Torvalds qnx4_inode_cachep = kmem_cache_create("qnx4_inode_cache", 5501da177e4SLinus Torvalds sizeof(struct qnx4_inode_info), 551fffb60f9SPaul Jackson 0, (SLAB_RECLAIM_ACCOUNT| 552fffb60f9SPaul Jackson SLAB_MEM_SPREAD), 5531da177e4SLinus Torvalds init_once, NULL); 5541da177e4SLinus Torvalds if (qnx4_inode_cachep == NULL) 5551da177e4SLinus Torvalds return -ENOMEM; 5561da177e4SLinus Torvalds return 0; 5571da177e4SLinus Torvalds } 5581da177e4SLinus Torvalds 5591da177e4SLinus Torvalds static void destroy_inodecache(void) 5601da177e4SLinus Torvalds { 5611da177e4SLinus Torvalds if (kmem_cache_destroy(qnx4_inode_cachep)) 5621da177e4SLinus Torvalds printk(KERN_INFO 5631da177e4SLinus Torvalds "qnx4_inode_cache: not all structures were freed\n"); 5641da177e4SLinus Torvalds } 5651da177e4SLinus Torvalds 566454e2398SDavid Howells static int qnx4_get_sb(struct file_system_type *fs_type, 567454e2398SDavid Howells int flags, const char *dev_name, void *data, struct vfsmount *mnt) 5681da177e4SLinus Torvalds { 569454e2398SDavid Howells return get_sb_bdev(fs_type, flags, dev_name, data, qnx4_fill_super, 570454e2398SDavid Howells mnt); 5711da177e4SLinus Torvalds } 5721da177e4SLinus Torvalds 5731da177e4SLinus Torvalds static struct file_system_type qnx4_fs_type = { 5741da177e4SLinus Torvalds .owner = THIS_MODULE, 5751da177e4SLinus Torvalds .name = "qnx4", 5761da177e4SLinus Torvalds .get_sb = qnx4_get_sb, 5771da177e4SLinus Torvalds .kill_sb = kill_block_super, 5781da177e4SLinus Torvalds .fs_flags = FS_REQUIRES_DEV, 5791da177e4SLinus Torvalds }; 5801da177e4SLinus Torvalds 5811da177e4SLinus Torvalds static int __init init_qnx4_fs(void) 5821da177e4SLinus Torvalds { 5831da177e4SLinus Torvalds int err; 5841da177e4SLinus Torvalds 5851da177e4SLinus Torvalds err = init_inodecache(); 5861da177e4SLinus Torvalds if (err) 5871da177e4SLinus Torvalds return err; 5881da177e4SLinus Torvalds 5891da177e4SLinus Torvalds err = register_filesystem(&qnx4_fs_type); 5901da177e4SLinus Torvalds if (err) { 5911da177e4SLinus Torvalds destroy_inodecache(); 5921da177e4SLinus Torvalds return err; 5931da177e4SLinus Torvalds } 5941da177e4SLinus Torvalds 5951da177e4SLinus Torvalds printk("QNX4 filesystem 0.2.3 registered.\n"); 5961da177e4SLinus Torvalds return 0; 5971da177e4SLinus Torvalds } 5981da177e4SLinus Torvalds 5991da177e4SLinus Torvalds static void __exit exit_qnx4_fs(void) 6001da177e4SLinus Torvalds { 6011da177e4SLinus Torvalds unregister_filesystem(&qnx4_fs_type); 6021da177e4SLinus Torvalds destroy_inodecache(); 6031da177e4SLinus Torvalds } 6041da177e4SLinus Torvalds 6051da177e4SLinus Torvalds module_init(init_qnx4_fs) 6061da177e4SLinus Torvalds module_exit(exit_qnx4_fs) 6071da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 6081da177e4SLinus Torvalds 609