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