static struct inode *simplefs_iget(struct super_block *sb, int ino) { struct inode *inode; struct simplefs_inode *sfs_inode; sfs_inode = simplefs_get_inode(sb, ino); inode = new_inode(sb); inode->i_ino = ino; inode->i_sb = sb; inode->i_op = &simplefs_inode_ops; if (S_ISDIR(sfs_inode->mode)) inode->i_fop = &simplefs_dir_operations; else if (S_ISREG(sfs_inode->mode) || ino == SIMPLEFS_JOURNAL_INODE_NUMBER) inode->i_fop = &simplefs_file_operations; else printk(KERN_ERR "Unknown inode type. Neither a directory nor a file"); /* FIXME: We should store these times to disk and retrieve them */ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; inode->i_private = sfs_inode; return inode; }
struct dentry *simplefs_lookup(struct inode *parent_inode, struct dentry *child_dentry, unsigned int flags) { struct simplefs_inode *parent = SIMPLEFS_INODE(parent_inode); struct super_block *sb = parent_inode->i_sb; struct buffer_head *bh; struct simplefs_dir_record *record; int i; bh = (struct buffer_head *)sb_bread(sb, parent->data_block_number); record = (struct simplefs_dir_record *)bh->b_data; for (i = 0; i < parent->dir_children_count; i++) { if (!strcmp(record->filename, child_dentry->d_name.name)) { /* FIXME: There is a corner case where if an allocated inode, * is not written to the inode store, but the inodes_count is * incremented. Then if the random string on the disk matches * with the filename that we are comparing above, then we * will use an invalid unintialized inode */ struct inode *inode; struct simplefs_inode *sfs_inode; /* FIXME: This simplefs_inode is leaking */ sfs_inode = simplefs_get_inode(sb, record->inode_no); /* FIXME: This inode is leaking */ inode = new_inode(sb); inode->i_ino = record->inode_no; inode_init_owner(inode, parent_inode, sfs_inode->mode); inode->i_sb = sb; inode->i_op = &simplefs_inode_ops; if (S_ISDIR(inode->i_mode)) inode->i_fop = &simplefs_dir_operations; else if (S_ISREG(inode->i_mode)) inode->i_fop = &simplefs_file_operations; else printk(KERN_ERR "Unknown inode type. Neither a directory nor a file"); /* FIXME: We should store these times to disk and retrieve them */ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; inode->i_private = sfs_inode; d_add(child_dentry, inode); return NULL; } record++; } printk(KERN_ERR "No inode found for the filename [%s]\n", child_dentry->d_name.name); return NULL; }
/* This function, as the name implies, Makes the super_block valid and * fills filesystem specific information in the super block */ int simplefs_fill_super(struct super_block *sb, void *data, int silent) { struct inode *root_inode; struct buffer_head *bh; struct simplefs_super_block *sb_disk; bh = (struct buffer_head *)sb_bread(sb, SIMPLEFS_SUPERBLOCK_BLOCK_NUMBER); sb_disk = (struct simplefs_super_block *)bh->b_data; /* FIXME: bh->b_data is probably leaking */ printk(KERN_INFO "The magic number obtained in disk is: [%llu]\n", sb_disk->magic); if (unlikely(sb_disk->magic != SIMPLEFS_MAGIC)) { printk(KERN_ERR "The filesystem that you try to mount is not of type simplefs. Magicnumber mismatch."); return -EPERM; } if (unlikely(sb_disk->block_size != SIMPLEFS_DEFAULT_BLOCK_SIZE)) { printk(KERN_ERR "simplefs seem to be formatted using a non-standard block size."); return -EPERM; } printk(KERN_INFO "simplefs filesystem of version [%llu] formatted with a block size of [%llu] detected in the device.\n", sb_disk->version, sb_disk->block_size); /* A magic number that uniquely identifies our filesystem type */ sb->s_magic = SIMPLEFS_MAGIC; /* For all practical purposes, we will be using this s_fs_info as the super block */ sb->s_fs_info = sb_disk; root_inode = new_inode(sb); root_inode->i_ino = SIMPLEFS_ROOTDIR_INODE_NUMBER; inode_init_owner(root_inode, NULL, S_IFDIR); root_inode->i_sb = sb; root_inode->i_op = &simplefs_inode_ops; root_inode->i_fop = &simplefs_dir_operations; root_inode->i_atime = root_inode->i_mtime = root_inode->i_ctime = CURRENT_TIME; root_inode->i_private = simplefs_get_inode(sb, SIMPLEFS_ROOTDIR_INODE_NUMBER); sb->s_root = d_make_root(root_inode); if (!sb->s_root) return -ENOMEM; return 0; }
/* This function, as the name implies, Makes the super_block valid and * fills filesystem specific information in the super block */ int simplefs_fill_super(struct super_block *sb, void *data, int silent) { struct inode *root_inode; struct buffer_head *bh; struct simplefs_super_block *sb_disk; int ret = -EPERM; bh = sb_bread(sb, SIMPLEFS_SUPERBLOCK_BLOCK_NUMBER); BUG_ON(!bh); sb_disk = (struct simplefs_super_block *)bh->b_data; printk(KERN_INFO "The magic number obtained in disk is: [%llu]\n", sb_disk->magic); if (unlikely(sb_disk->magic != SIMPLEFS_MAGIC)) { printk(KERN_ERR "The filesystem that you try to mount is not of type simplefs. Magicnumber mismatch."); goto release; } if (unlikely(sb_disk->block_size != SIMPLEFS_DEFAULT_BLOCK_SIZE)) { printk(KERN_ERR "simplefs seem to be formatted using a non-standard block size."); goto release; } /** XXX: Avoid this hack, by adding one more sb wrapper, but non-disk */ sb_disk->journal = NULL; printk(KERN_INFO "simplefs filesystem of version [%llu] formatted with a block size of [%llu] detected in the device.\n", sb_disk->version, sb_disk->block_size); /* A magic number that uniquely identifies our filesystem type */ sb->s_magic = SIMPLEFS_MAGIC; /* For all practical purposes, we will be using this s_fs_info as the super block */ sb->s_fs_info = sb_disk; sb->s_maxbytes = SIMPLEFS_DEFAULT_BLOCK_SIZE; sb->s_op = &simplefs_sops; root_inode = new_inode(sb); root_inode->i_ino = SIMPLEFS_ROOTDIR_INODE_NUMBER; inode_init_owner(root_inode, NULL, S_IFDIR); root_inode->i_sb = sb; root_inode->i_op = &simplefs_inode_ops; root_inode->i_fop = &simplefs_dir_operations; root_inode->i_atime = root_inode->i_mtime = root_inode->i_ctime = CURRENT_TIME; root_inode->i_private = simplefs_get_inode(sb, SIMPLEFS_ROOTDIR_INODE_NUMBER); /* TODO: move such stuff into separate header. */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0) sb->s_root = d_make_root(root_inode); #else sb->s_root = d_alloc_root(root_inode); if (!sb->s_root) iput(root_inode); #endif if (!sb->s_root) { ret = -ENOMEM; goto release; } if ((ret = simplefs_parse_options(sb, data))) goto release; if (!sb_disk->journal) { struct inode *journal_inode; journal_inode = simplefs_iget(sb, SIMPLEFS_JOURNAL_INODE_NUMBER); ret = simplefs_sb_load_journal(sb, journal_inode); goto release; } ret = jbd2_journal_load(sb_disk->journal); release: brelse(bh); return ret; }
static int simplefs_create_fs_object(struct inode *dir, struct dentry *dentry, umode_t mode) { struct inode *inode; struct simplefs_inode *sfs_inode; struct simplefs_inode *inode_iterator; struct super_block *sb; struct simplefs_dir_record *record; struct simplefs_inode *parent_dir_inode; struct buffer_head *bh; struct simplefs_dir_record *dir_contents_datablock; uint64_t count; int ret; if (mutex_lock_interruptible(&simplefs_directory_children_update_lock)) { printk(KERN_ERR "Failed to acquire mutex lock %s +%d\n", __FILE__, __LINE__); return -EINTR; } sb = dir->i_sb; ret = simplefs_sb_get_objects_count(sb, &count); if (ret < 0) { mutex_unlock(&simplefs_directory_children_update_lock); return ret; } if (unlikely(count >= SIMPLEFS_MAX_FILESYSTEM_OBJECTS_SUPPORTED)) { /* The above condition can be just == insted of the >= */ printk(KERN_ERR "Maximum number of objects supported by simplefs is already reached"); mutex_unlock(&simplefs_directory_children_update_lock); return -ENOSPC; } if (!S_ISDIR(mode) && !S_ISREG(mode)) { printk(KERN_ERR "Creation request but for neither a file nor a directory"); mutex_unlock(&simplefs_directory_children_update_lock); return -EINVAL; } inode = new_inode(sb); if (!inode) { mutex_unlock(&simplefs_directory_children_update_lock); return -ENOMEM; } inode->i_sb = sb; inode->i_op = &simplefs_inode_ops; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; inode->i_ino = 10; /* Loop until we get an unique inode number */ while (simplefs_get_inode(sb, inode->i_ino)) { /* inode inode->i_ino already exists */ inode->i_ino++; } /* FIXME: This is leaking. We need to free all in-memory inodes sometime */ sfs_inode = kmalloc(sizeof(struct simplefs_inode), GFP_KERNEL); sfs_inode->inode_no = inode->i_ino; inode->i_private = sfs_inode; sfs_inode->mode = mode; if (S_ISDIR(mode)) { printk(KERN_INFO "New directory creation request\n"); sfs_inode->dir_children_count = 0; inode->i_fop = &simplefs_dir_operations; } else if (S_ISREG(mode)) { printk(KERN_INFO "New file creation request\n"); sfs_inode->file_size = 0; inode->i_fop = &simplefs_file_operations; } /* First get a free block and update the free map, * Then add inode to the inode store and update the sb inodes_count, * Then update the parent directory's inode with the new child. * * The above ordering helps us to maintain fs consistency * even in most crashes */ ret = simplefs_sb_get_a_freeblock(sb, &sfs_inode->data_block_number); if (ret < 0) { printk(KERN_ERR "simplefs could not get a freeblock"); mutex_unlock(&simplefs_directory_children_update_lock); return ret; } simplefs_inode_add(sb, sfs_inode); record = kmalloc(sizeof(struct simplefs_dir_record), GFP_KERNEL); record->inode_no = sfs_inode->inode_no; strcpy(record->filename, dentry->d_name.name); parent_dir_inode = SIMPLEFS_INODE(dir); bh = sb_bread(sb, parent_dir_inode->data_block_number); dir_contents_datablock = (struct simplefs_dir_record *)bh->b_data; /* Navigate to the last record in the directory contents */ dir_contents_datablock += parent_dir_inode->dir_children_count; memcpy(dir_contents_datablock, record, sizeof(struct simplefs_dir_record)); mark_buffer_dirty(bh); sync_dirty_buffer(bh); brelse(bh); if (mutex_lock_interruptible(&simplefs_inodes_mgmt_lock)) { mutex_unlock(&simplefs_directory_children_update_lock); printk(KERN_ERR "Failed to acquire mutex lock %s +%d\n", __FILE__, __LINE__); return -EINTR; } bh = (struct buffer_head *)sb_bread(sb, SIMPLEFS_INODESTORE_BLOCK_NUMBER); inode_iterator = (struct simplefs_inode *)bh->b_data; if (mutex_lock_interruptible(&simplefs_sb_lock)) { printk(KERN_ERR "Failed to acquire mutex lock %s +%d\n", __FILE__, __LINE__); return -EINTR; } count = 0; while (inode_iterator->inode_no != parent_dir_inode->inode_no && count < SIMPLEFS_SB(sb)->inodes_count) { count++; inode_iterator++; } if (likely(inode_iterator->inode_no == parent_dir_inode->inode_no)) { parent_dir_inode->dir_children_count++; inode_iterator->dir_children_count = parent_dir_inode->dir_children_count; /* Updated the parent inode's dir count to reflect the new child too */ mark_buffer_dirty(bh); sync_dirty_buffer(bh); } else { printk(KERN_ERR "The updated childcount could not be stored to the dir inode."); /* TODO: Remove the newly created inode from the disk and in-memory inode store * and also update the superblock, freemaps etc. to reflect the same. * Basically, Undo all actions done during this create call */ } brelse(bh); mutex_unlock(&simplefs_sb_lock); mutex_unlock(&simplefs_inodes_mgmt_lock); mutex_unlock(&simplefs_directory_children_update_lock); inode_init_owner(inode, dir, mode); d_add(dentry, inode); return 0; }