int qnx4_is_free(struct super_block *sb, long block) { int start = le32_to_cpu(qnx4_sb(sb)->BitMap->di_first_xtnt.xtnt_blk) - 1; int size = le32_to_cpu(qnx4_sb(sb)->BitMap->di_size); struct buffer_head *bh; const char *g; int ret = -EIO; start += block / (QNX4_BLOCK_SIZE * 8); QNX4DEBUG(("qnx4: is_free requesting block [%lu], bitmap in block [%lu]\n", (unsigned long) block, (unsigned long) start)); (void) size; /* CHECKME */ bh = sb_bread(sb, start); if (bh == NULL) { return -EIO; } g = bh->b_data + (block % QNX4_BLOCK_SIZE); if (((*g) & (1 << (block % 8))) == 0) { QNX4DEBUG(("qnx4: is_free -> block is free\n")); ret = 1; } else { QNX4DEBUG(("qnx4: is_free -> block is busy\n")); ret = 0; } brelse(bh); return ret; }
int qnx4_set_bitmap(struct super_block *sb, long block, int busy) { int start = le32_to_cpu(qnx4_sb(sb)->BitMap->di_first_xtnt.xtnt_blk) - 1; int size = le32_to_cpu(qnx4_sb(sb)->BitMap->di_size); struct buffer_head *bh; char *g; start += block / (QNX4_BLOCK_SIZE * 8); QNX4DEBUG(("qnx4: set_bitmap requesting block [%lu], bitmap in block [%lu]\n", (unsigned long) block, (unsigned long) start)); (void) size; /* CHECKME */ bh = sb_bread(sb, start); if (bh == NULL) { return -EIO; } g = bh->b_data + (block % QNX4_BLOCK_SIZE); if (busy == 0) { (*g) &= ~(1 << (block % 8)); } else { (*g) |= (1 << (block % 8)); } mark_buffer_dirty(bh); brelse(bh); return 0; }
/* * Check the root directory of the filesystem to make sure * it really _is_ a qnx4 filesystem, and to check the size * of the directory entry. */ static const char *qnx4_checkroot(struct super_block *sb) { struct buffer_head *bh; struct qnx4_inode_entry *rootdir; int rd, rl; int i, j; if (*(qnx4_sb(sb)->sb->RootDir.di_fname) != '/') return "no qnx4 filesystem (no root dir)."; QNX4DEBUG((KERN_NOTICE "QNX4 filesystem found on dev %s.\n", sb->s_id)); rd = le32_to_cpu(qnx4_sb(sb)->sb->RootDir.di_first_xtnt.xtnt_blk) - 1; rl = le32_to_cpu(qnx4_sb(sb)->sb->RootDir.di_first_xtnt.xtnt_size); for (j = 0; j < rl; j++) { bh = sb_bread(sb, rd + j); /* root dir, first block */ if (bh == NULL) return "unable to read root entry."; rootdir = (struct qnx4_inode_entry *) bh->b_data; for (i = 0; i < QNX4_INODES_PER_BLOCK; i++, rootdir++) { QNX4DEBUG((KERN_INFO "rootdir entry found : [%s]\n", rootdir->di_fname)); if (strcmp(rootdir->di_fname, QNX4_BMNAME) != 0) continue; qnx4_sb(sb)->BitMap = kmemdup(rootdir, sizeof(struct qnx4_inode_entry), GFP_KERNEL); brelse(bh); if (!qnx4_sb(sb)->BitMap) return "not enough memory for bitmap inode"; /* keep bitmap inode known */ return NULL; } brelse(bh); } return "bitmap file not found."; }
static void qnx4_put_super(struct super_block *sb) { struct qnx4_sb_info *qs = qnx4_sb(sb); kfree( qs->BitMap ); kfree( qs ); sb->s_fs_info = NULL; return; }
static int qnx4_remount(struct super_block *sb, int *flags, char *data) { struct qnx4_sb_info *qs; qs = qnx4_sb(sb); qs->Version = QNX4_VERSION; *flags |= MS_RDONLY; return 0; }
unsigned long qnx4_count_free_blocks(struct super_block *sb) { int start = le32_to_cpu(qnx4_sb(sb)->BitMap->di_first_xtnt.xtnt_blk) - 1; int total = 0; int total_free = 0; int offset = 0; int size = le32_to_cpu(qnx4_sb(sb)->BitMap->di_size); struct buffer_head *bh; while (total < size) { if ((bh = sb_bread(sb, start + offset)) == NULL) { printk("qnx4: I/O error in counting free blocks\n"); break; } count_bits(bh->b_data, size - total, &total_free); brelse(bh); total += QNX4_BLOCK_SIZE; offset++; } return total_free; }
static int qnx4_statfs(struct super_block *sb, struct kstatfs *buf) { lock_kernel(); buf->f_type = sb->s_magic; buf->f_bsize = sb->s_blocksize; buf->f_blocks = le32_to_cpu(qnx4_sb(sb)->BitMap->di_size) * 8; buf->f_bfree = qnx4_count_free_blocks(sb); buf->f_bavail = buf->f_bfree; buf->f_namelen = QNX4_NAME_MAX; unlock_kernel(); return 0; }
static int qnx4_statfs(struct dentry *dentry, struct kstatfs *buf) { struct super_block *sb = dentry->d_sb; u64 id = huge_encode_dev(sb->s_bdev->bd_dev); buf->f_type = sb->s_magic; buf->f_bsize = sb->s_blocksize; buf->f_blocks = le32_to_cpu(qnx4_sb(sb)->BitMap->di_size) * 8; buf->f_bfree = qnx4_count_free_blocks(sb); buf->f_bavail = buf->f_bfree; buf->f_namelen = QNX4_NAME_MAX; buf->f_fsid.val[0] = (u32)id; buf->f_fsid.val[1] = (u32)(id >> 32); return 0; }
static int qnx4_remount(struct super_block *sb, int *flags, char *data) { struct qnx4_sb_info *qs; qs = qnx4_sb(sb); qs->Version = QNX4_VERSION; #ifndef CONFIG_QNX4FS_RW *flags |= MS_RDONLY; #endif if (*flags & MS_RDONLY) { return 0; } mark_buffer_dirty(qs->sb_buf); return 0; }
/* * Check the root directory of the filesystem to make sure * it really _is_ a qnx4 filesystem, and to check the size * of the directory entry. */ static const char *qnx4_checkroot(struct super_block *sb) { struct buffer_head *bh; struct qnx4_inode_entry *rootdir; int rd, rl; int i, j; int found = 0; if (*(qnx4_sb(sb)->sb->RootDir.di_fname) != '/') { return "no qnx4 filesystem (no root dir)."; } else { QNX4DEBUG(("QNX4 filesystem found on dev %s.\n", sb->s_id)); rd = le32_to_cpu(qnx4_sb(sb)->sb->RootDir.di_first_xtnt.xtnt_blk) - 1; rl = le32_to_cpu(qnx4_sb(sb)->sb->RootDir.di_first_xtnt.xtnt_size); for (j = 0; j < rl; j++) { bh = sb_bread(sb, rd + j); /* root dir, first block */ if (bh == NULL) { return "unable to read root entry."; } for (i = 0; i < QNX4_INODES_PER_BLOCK; i++) { rootdir = (struct qnx4_inode_entry *) (bh->b_data + i * QNX4_DIR_ENTRY_SIZE); if (rootdir->di_fname != NULL) { QNX4DEBUG(("Rootdir entry found : [%s]\n", rootdir->di_fname)); if (!strncmp(rootdir->di_fname, QNX4_BMNAME, sizeof QNX4_BMNAME)) { found = 1; qnx4_sb(sb)->BitMap = kmalloc( sizeof( struct qnx4_inode_entry ), GFP_KERNEL ); if (!qnx4_sb(sb)->BitMap) { brelse (bh); return "not enough memory for bitmap inode"; } memcpy( qnx4_sb(sb)->BitMap, rootdir, sizeof( struct qnx4_inode_entry ) ); /* keep bitmap inode known */ break; } } } brelse(bh); if (found != 0) { break; } } if (found == 0) { return "bitmap file not found."; } } return NULL; }
static int qnx4_fill_super(struct super_block *s, void *data, int silent) { struct buffer_head *bh; struct inode *root; const char *errmsg; struct qnx4_sb_info *qs; int ret = -EINVAL; qs = kzalloc(sizeof(struct qnx4_sb_info), GFP_KERNEL); if (!qs) return -ENOMEM; s->s_fs_info = qs; sb_set_blocksize(s, QNX4_BLOCK_SIZE); /* Check the superblock signature. Since the qnx4 code is dangerous, we should leave as quickly as possible if we don't belong here... */ bh = sb_bread(s, 1); if (!bh) { printk(KERN_ERR "qnx4: unable to read the superblock\n"); goto outnobh; } if ( le32_to_cpup((__le32*) bh->b_data) != QNX4_SUPER_MAGIC ) { if (!silent) printk(KERN_ERR "qnx4: wrong fsid in superblock.\n"); goto out; } s->s_op = &qnx4_sops; s->s_magic = QNX4_SUPER_MAGIC; s->s_flags |= MS_RDONLY; /* Yup, read-only yet */ qnx4_sb(s)->sb_buf = bh; qnx4_sb(s)->sb = (struct qnx4_super_block *) bh->b_data; /* check before allocating dentries, inodes, .. */ errmsg = qnx4_checkroot(s); if (errmsg != NULL) { if (!silent) printk(KERN_ERR "qnx4: %s\n", errmsg); goto out; } /* does root not have inode number QNX4_ROOT_INO ?? */ root = qnx4_iget(s, QNX4_ROOT_INO * QNX4_INODES_PER_BLOCK); if (IS_ERR(root)) { printk(KERN_ERR "qnx4: get inode failed\n"); ret = PTR_ERR(root); goto out; } ret = -ENOMEM; s->s_root = d_alloc_root(root); if (s->s_root == NULL) goto outi; brelse(bh); return 0; outi: iput(root); out: brelse(bh); outnobh: kfree(qs); s->s_fs_info = NULL; return ret; }