Skip to content

Commit

Permalink
Fixes to the BFS filesystem driver
Browse files Browse the repository at this point in the history
I found a few bugs in the BFS driver.  Detailed description of the bugs as
well as the steps to reproduce the errors are given in the kernel bugzilla.
 Please follow these links for more information:

http://bugzilla.kernel.org/show_bug.cgi?id=9363
http://bugzilla.kernel.org/show_bug.cgi?id=9364
http://bugzilla.kernel.org/show_bug.cgi?id=9365
http://bugzilla.kernel.org/show_bug.cgi?id=9366

This patch fixes the bugs described above.  Besides, the patch introduces
coding style changes to make the BFS driver conform to the requirements
specified for Linux kernel code.  Finally, I made a few cosmetic changes
such as removal of trivial debug output.

Also, the patch removes the fields `si_lf_ioff' and `si_lf_sblk' of the
in-core superblock structure.  These fields are initialized but never
actually used.

If you are wondering why I need BFS, here is the answer: I am using this
driver in the context of Linux kernel classes I am teaching in the Moscow
State University and in the International Institute of Information
Technology in Pune, India.

Signed-off-by: Dmitri Vorobiev <[email protected]>
Cc: Tigran Aivazian <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
dmvo authored and Linus Torvalds committed Nov 15, 2007
1 parent cfb5285 commit f433dc5
Show file tree
Hide file tree
Showing 4 changed files with 184 additions and 155 deletions.
4 changes: 1 addition & 3 deletions fs/bfs/bfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ struct bfs_sb_info {
unsigned long si_blocks;
unsigned long si_freeb;
unsigned long si_freei;
unsigned long si_lf_ioff;
unsigned long si_lf_sblk;
unsigned long si_lf_eblk;
unsigned long si_lasti;
unsigned long * si_imap;
Expand All @@ -39,7 +37,7 @@ static inline struct bfs_sb_info *BFS_SB(struct super_block *sb)

static inline struct bfs_inode_info *BFS_I(struct inode *inode)
{
return list_entry(inode, struct bfs_inode_info, vfs_inode);
return container_of(inode, struct bfs_inode_info, vfs_inode);
}


Expand Down
146 changes: 78 additions & 68 deletions fs/bfs/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,29 +21,32 @@
#define dprintf(x...)
#endif

static int bfs_add_entry(struct inode * dir, const unsigned char * name, int namelen, int ino);
static struct buffer_head * bfs_find_entry(struct inode * dir,
const unsigned char * name, int namelen, struct bfs_dirent ** res_dir);
static int bfs_add_entry(struct inode *dir, const unsigned char *name,
int namelen, int ino);
static struct buffer_head *bfs_find_entry(struct inode *dir,
const unsigned char *name, int namelen,
struct bfs_dirent **res_dir);

static int bfs_readdir(struct file * f, void * dirent, filldir_t filldir)
static int bfs_readdir(struct file *f, void *dirent, filldir_t filldir)
{
struct inode * dir = f->f_path.dentry->d_inode;
struct buffer_head * bh;
struct bfs_dirent * de;
struct inode *dir = f->f_path.dentry->d_inode;
struct buffer_head *bh;
struct bfs_dirent *de;
unsigned int offset;
int block;

lock_kernel();

if (f->f_pos & (BFS_DIRENT_SIZE-1)) {
printf("Bad f_pos=%08lx for %s:%08lx\n", (unsigned long)f->f_pos,
dir->i_sb->s_id, dir->i_ino);
if (f->f_pos & (BFS_DIRENT_SIZE - 1)) {
printf("Bad f_pos=%08lx for %s:%08lx\n",
(unsigned long)f->f_pos,
dir->i_sb->s_id, dir->i_ino);
unlock_kernel();
return -EBADF;
}

while (f->f_pos < dir->i_size) {
offset = f->f_pos & (BFS_BSIZE-1);
offset = f->f_pos & (BFS_BSIZE - 1);
block = BFS_I(dir)->i_sblock + (f->f_pos >> BFS_BSIZE_BITS);
bh = sb_bread(dir->i_sb, block);
if (!bh) {
Expand All @@ -54,15 +57,17 @@ static int bfs_readdir(struct file * f, void * dirent, filldir_t filldir)
de = (struct bfs_dirent *)(bh->b_data + offset);
if (de->ino) {
int size = strnlen(de->name, BFS_NAMELEN);
if (filldir(dirent, de->name, size, f->f_pos, le16_to_cpu(de->ino), DT_UNKNOWN) < 0) {
if (filldir(dirent, de->name, size, f->f_pos,
le16_to_cpu(de->ino),
DT_UNKNOWN) < 0) {
brelse(bh);
unlock_kernel();
return 0;
}
}
offset += BFS_DIRENT_SIZE;
f->f_pos += BFS_DIRENT_SIZE;
} while (offset < BFS_BSIZE && f->f_pos < dir->i_size);
} while ((offset < BFS_BSIZE) && (f->f_pos < dir->i_size));
brelse(bh);
}

Expand All @@ -78,13 +83,13 @@ const struct file_operations bfs_dir_operations = {

extern void dump_imap(const char *, struct super_block *);

static int bfs_create(struct inode * dir, struct dentry * dentry, int mode,
struct nameidata *nd)
static int bfs_create(struct inode *dir, struct dentry *dentry, int mode,
struct nameidata *nd)
{
int err;
struct inode * inode;
struct super_block * s = dir->i_sb;
struct bfs_sb_info * info = BFS_SB(s);
struct inode *inode;
struct super_block *s = dir->i_sb;
struct bfs_sb_info *info = BFS_SB(s);
unsigned long ino;

inode = new_inode(s);
Expand All @@ -97,7 +102,7 @@ static int bfs_create(struct inode * dir, struct dentry * dentry, int mode,
iput(inode);
return -ENOSPC;
}
set_bit(ino, info->si_imap);
set_bit(ino, info->si_imap);
info->si_freei--;
inode->i_uid = current->fsuid;
inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
Expand All @@ -113,9 +118,10 @@ static int bfs_create(struct inode * dir, struct dentry * dentry, int mode,
BFS_I(inode)->i_eblock = 0;
insert_inode_hash(inode);
mark_inode_dirty(inode);
dump_imap("create",s);
dump_imap("create", s);

err = bfs_add_entry(dir, dentry->d_name.name, dentry->d_name.len, inode->i_ino);
err = bfs_add_entry(dir, dentry->d_name.name, dentry->d_name.len,
inode->i_ino);
if (err) {
inode_dec_link_count(inode);
iput(inode);
Expand All @@ -127,11 +133,12 @@ static int bfs_create(struct inode * dir, struct dentry * dentry, int mode,
return 0;
}

static struct dentry * bfs_lookup(struct inode * dir, struct dentry * dentry, struct nameidata *nd)
static struct dentry *bfs_lookup(struct inode *dir, struct dentry *dentry,
struct nameidata *nd)
{
struct inode * inode = NULL;
struct buffer_head * bh;
struct bfs_dirent * de;
struct inode *inode = NULL;
struct buffer_head *bh;
struct bfs_dirent *de;

if (dentry->d_name.len > BFS_NAMELEN)
return ERR_PTR(-ENAMETOOLONG);
Expand All @@ -152,13 +159,15 @@ static struct dentry * bfs_lookup(struct inode * dir, struct dentry * dentry, st
return NULL;
}

static int bfs_link(struct dentry * old, struct inode * dir, struct dentry * new)
static int bfs_link(struct dentry *old, struct inode *dir,
struct dentry *new)
{
struct inode * inode = old->d_inode;
struct inode *inode = old->d_inode;
int err;

lock_kernel();
err = bfs_add_entry(dir, new->d_name.name, new->d_name.len, inode->i_ino);
err = bfs_add_entry(dir, new->d_name.name, new->d_name.len,
inode->i_ino);
if (err) {
unlock_kernel();
return err;
Expand All @@ -172,23 +181,23 @@ static int bfs_link(struct dentry * old, struct inode * dir, struct dentry * new
return 0;
}


static int bfs_unlink(struct inode * dir, struct dentry * dentry)
static int bfs_unlink(struct inode *dir, struct dentry *dentry)
{
int error = -ENOENT;
struct inode * inode;
struct buffer_head * bh;
struct bfs_dirent * de;
struct inode *inode;
struct buffer_head *bh;
struct bfs_dirent *de;

inode = dentry->d_inode;
lock_kernel();
bh = bfs_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de);
if (!bh || le16_to_cpu(de->ino) != inode->i_ino)
if (!bh || (le16_to_cpu(de->ino) != inode->i_ino))
goto out_brelse;

if (!inode->i_nlink) {
printf("unlinking non-existent file %s:%lu (nlink=%d)\n", inode->i_sb->s_id,
inode->i_ino, inode->i_nlink);
printf("unlinking non-existent file %s:%lu (nlink=%d)\n",
inode->i_sb->s_id, inode->i_ino,
inode->i_nlink);
inode->i_nlink = 1;
}
de->ino = 0;
Expand All @@ -205,12 +214,12 @@ static int bfs_unlink(struct inode * dir, struct dentry * dentry)
return error;
}

static int bfs_rename(struct inode * old_dir, struct dentry * old_dentry,
struct inode * new_dir, struct dentry * new_dentry)
static int bfs_rename(struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry)
{
struct inode * old_inode, * new_inode;
struct buffer_head * old_bh, * new_bh;
struct bfs_dirent * old_de, * new_de;
struct inode *old_inode, *new_inode;
struct buffer_head *old_bh, *new_bh;
struct bfs_dirent *old_de, *new_de;
int error = -ENOENT;

old_bh = new_bh = NULL;
Expand All @@ -223,7 +232,7 @@ static int bfs_rename(struct inode * old_dir, struct dentry * old_dentry,
old_dentry->d_name.name,
old_dentry->d_name.len, &old_de);

if (!old_bh || le16_to_cpu(old_de->ino) != old_inode->i_ino)
if (!old_bh || (le16_to_cpu(old_de->ino) != old_inode->i_ino))
goto end_rename;

error = -EPERM;
Expand All @@ -239,7 +248,8 @@ static int bfs_rename(struct inode * old_dir, struct dentry * old_dentry,
if (!new_bh) {
error = bfs_add_entry(new_dir,
new_dentry->d_name.name,
new_dentry->d_name.len, old_inode->i_ino);
new_dentry->d_name.len,
old_inode->i_ino);
if (error)
goto end_rename;
}
Expand Down Expand Up @@ -268,11 +278,12 @@ const struct inode_operations bfs_dir_inops = {
.rename = bfs_rename,
};

static int bfs_add_entry(struct inode * dir, const unsigned char * name, int namelen, int ino)
static int bfs_add_entry(struct inode *dir, const unsigned char *name,
int namelen, int ino)
{
struct buffer_head * bh;
struct bfs_dirent * de;
int block, sblock, eblock, off, eoff;
struct buffer_head *bh;
struct bfs_dirent *de;
int block, sblock, eblock, off, pos;
int i;

dprintf("name=%s, namelen=%d\n", name, namelen);
Expand All @@ -284,27 +295,24 @@ static int bfs_add_entry(struct inode * dir, const unsigned char * name, int nam

sblock = BFS_I(dir)->i_sblock;
eblock = BFS_I(dir)->i_eblock;
eoff = dir->i_size % BFS_BSIZE;
for (block=sblock; block<=eblock; block++) {
for (block = sblock; block <= eblock; block++) {
bh = sb_bread(dir->i_sb, block);
if(!bh)
if (!bh)
return -ENOSPC;
for (off=0; off<BFS_BSIZE; off+=BFS_DIRENT_SIZE) {
for (off = 0; off < BFS_BSIZE; off += BFS_DIRENT_SIZE) {
de = (struct bfs_dirent *)(bh->b_data + off);
if (block==eblock && off>=eoff) {
/* Do not read/interpret the garbage in the end of eblock. */
de->ino = 0;
}
if (!de->ino) {
if ((block-sblock)*BFS_BSIZE + off >= dir->i_size) {
pos = (block - sblock) * BFS_BSIZE + off;
if (pos >= dir->i_size) {
dir->i_size += BFS_DIRENT_SIZE;
dir->i_ctime = CURRENT_TIME_SEC;
}
dir->i_mtime = CURRENT_TIME_SEC;
mark_inode_dirty(dir);
de->ino = cpu_to_le16((u16)ino);
for (i=0; i<BFS_NAMELEN; i++)
de->name[i] = (i < namelen) ? name[i] : 0;
for (i = 0; i < BFS_NAMELEN; i++)
de->name[i] =
(i < namelen) ? name[i] : 0;
mark_buffer_dirty(bh);
brelse(bh);
return 0;
Expand All @@ -315,25 +323,26 @@ static int bfs_add_entry(struct inode * dir, const unsigned char * name, int nam
return -ENOSPC;
}

static inline int bfs_namecmp(int len, const unsigned char * name, const char * buffer)
static inline int bfs_namecmp(int len, const unsigned char *name,
const char *buffer)
{
if (len < BFS_NAMELEN && buffer[len])
if ((len < BFS_NAMELEN) && buffer[len])
return 0;
return !memcmp(name, buffer, len);
}

static struct buffer_head * bfs_find_entry(struct inode * dir,
const unsigned char * name, int namelen, struct bfs_dirent ** res_dir)
static struct buffer_head *bfs_find_entry(struct inode *dir,
const unsigned char *name, int namelen,
struct bfs_dirent **res_dir)
{
unsigned long block, offset;
struct buffer_head * bh;
struct bfs_dirent * de;
unsigned long block = 0, offset = 0;
struct buffer_head *bh = NULL;
struct bfs_dirent *de;

*res_dir = NULL;
if (namelen > BFS_NAMELEN)
return NULL;
bh = NULL;
block = offset = 0;

while (block * BFS_BSIZE + offset < dir->i_size) {
if (!bh) {
bh = sb_bread(dir->i_sb, BFS_I(dir)->i_sblock + block);
Expand All @@ -344,7 +353,8 @@ static struct buffer_head * bfs_find_entry(struct inode * dir,
}
de = (struct bfs_dirent *)(bh->b_data + offset);
offset += BFS_DIRENT_SIZE;
if (le16_to_cpu(de->ino) && bfs_namecmp(namelen, name, de->name)) {
if (le16_to_cpu(de->ino) &&
bfs_namecmp(namelen, name, de->name)) {
*res_dir = de;
return bh;
}
Expand Down
Loading

0 comments on commit f433dc5

Please sign in to comment.