From dad5b1c50e05868f65cee88f20eae5ae9b23f03e Mon Sep 17 00:00:00 2001 From: Azat Khuzhin Date: Sun, 13 Jul 2014 00:00:36 +0400 Subject: [PATCH 01/16] Initial support of journaling - Reorder block numbers to make it more sequental for mkfs - mkfs: adjust writing, to make it correct write journal blocks and ino too - simplefs_iget: use fops for journal inode - simplefs_iget: check sfs_inode->mode instead of i_mode (not initialized yet) --- mkfs-simplefs.c | 59 +++++++++++++++++++++++++++------- simple.c | 85 ++++++++++++++++++++++++++++++++++--------------- simple.h | 19 +++++++++-- 3 files changed, 125 insertions(+), 38 deletions(-) diff --git a/mkfs-simplefs.c b/mkfs-simplefs.c index 44a8955..b75a651 100644 --- a/mkfs-simplefs.c +++ b/mkfs-simplefs.c @@ -9,8 +9,8 @@ #include "simple.h" -const uint64_t WELCOMEFILE_DATABLOCK_NUMBER = 3; -const uint64_t WELCOMEFILE_INODE_NUMBER = 2; +#define WELCOMEFILE_DATABLOCK_NUMBER (SIMPLEFS_LAST_RESERVED_BLOCK + 1) +#define WELCOMEFILE_INODE_NUMBER (SIMPLEFS_LAST_RESERVED_INODE + 1) static int write_superblock(int fd) { @@ -18,10 +18,9 @@ static int write_superblock(int fd) .version = 1, .magic = SIMPLEFS_MAGIC, .block_size = SIMPLEFS_DEFAULT_BLOCK_SIZE, - /* One inode for rootdirectory and another for a welcome file that we are going to create */ - .inodes_count = 2, + .inodes_count = WELCOMEFILE_INODE_NUMBER, /* FIXME: Free blocks management is not implemented yet */ - .free_blocks = (~0) & ~(1 << WELCOMEFILE_DATABLOCK_NUMBER), + .free_blocks = (~0) & ~(1 << SIMPLEFS_LAST_RESERVED_BLOCK), }; ssize_t ret; @@ -37,7 +36,7 @@ static int write_superblock(int fd) return 0; } -static int write_inode_store(int fd) +static int write_root_inode(int fd) { ssize_t ret; @@ -59,8 +58,26 @@ static int write_inode_store(int fd) printf("root directory inode written succesfully\n"); return 0; } +static int write_journal_inode(int fd) +{ + ssize_t ret; + + struct simplefs_inode journal; + + journal.inode_no = SIMPLEFS_JOURNAL_INODE_NUMBER; + journal.data_block_number = SIMPLEFS_JOURNAL_BLOCK_NUMBER; + + ret = write(fd, &journal, sizeof(journal)); + + if (ret != sizeof(journal)) { + printf("Error while writing journal inode. Retry your mkfs\n"); + return -1; + } -static int write_inode(int fd, const struct simplefs_inode *i) + printf("journal inode written succesfully\n"); + return 0; +} +static int write_welcome_inode(int fd, const struct simplefs_inode *i) { off_t nbytes; ssize_t ret; @@ -73,7 +90,7 @@ static int write_inode(int fd, const struct simplefs_inode *i) } printf("welcomefile inode written succesfully\n"); - nbytes = SIMPLEFS_DEFAULT_BLOCK_SIZE - sizeof(*i) - sizeof(*i); + nbytes = SIMPLEFS_DEFAULT_BLOCK_SIZE - (sizeof(*i) * 3); ret = lseek(fd, nbytes, SEEK_CUR); if (ret == (off_t)-1) { printf @@ -82,9 +99,23 @@ static int write_inode(int fd, const struct simplefs_inode *i) } printf - ("inode store padding bytes (after the two inodes) written sucessfully\n"); + ("inode store padding bytes (after the three inodes) written sucessfully\n"); + return 0; +} + +int write_journal(int fd) +{ + ssize_t ret; + ret = lseek(fd, SIMPLEFS_DEFAULT_BLOCK_SIZE * SIMPLEFS_JOURNAL_BLOCKS, SEEK_CUR); + if (ret == (off_t)-1) { + printf("Can't write journal. Retry you mkfs\n"); + return -1; + } + + printf("Journal written successfully\n"); return 0; } + int write_dirent(int fd, const struct simplefs_dir_record *record) { ssize_t nbytes = sizeof(*record), ret; @@ -154,11 +185,17 @@ int main(int argc, char *argv[]) do { if (write_superblock(fd)) break; - if (write_inode_store(fd)) + + if (write_root_inode(fd)) + break; + if (write_journal_inode(fd)) + break; + if (write_welcome_inode(fd, &welcome)) break; - if (write_inode(fd, &welcome)) + if (write_journal(fd)) break; + if (write_dirent(fd, &record)) break; if (write_block(fd, welcomefile_body, welcome.file_size)) diff --git a/simple.c b/simple.c index 53c384a..7b1e2a8 100644 --- a/simple.c +++ b/simple.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "super.h" @@ -584,6 +585,35 @@ static int simplefs_create(struct inode *dir, struct dentry *dentry, return simplefs_create_fs_object(dir, dentry, mode); } +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) { @@ -605,31 +635,8 @@ struct dentry *simplefs_lookup(struct inode *parent_inode, * with the filename that we are comparing above, then we * will use an invalid uninitialized inode */ - struct inode *inode; - struct simplefs_inode *sfs_inode; - - sfs_inode = simplefs_get_inode(sb, record->inode_no); - - 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; - + struct inode *inode = simplefs_iget(sb, record->inode_no); + inode_init_owner(inode, parent_inode, SIMPLEFS_INODE(inode)->mode); d_add(child_dentry, inode); return NULL; } @@ -656,10 +663,35 @@ void simplefs_destory_inode(struct inode *inode) kmem_cache_free(sfs_inode_cachep, sfs_inode); } +static void simplefs_put_super(struct super_block *sb) +{ + struct simplefs_super_block *sfs_sb = SIMPLEFS_SB(sb); + if (sfs_sb->journal) + WARN_ON(jbd2_journal_destroy(sfs_sb->journal) < 0); + sfs_sb->journal = NULL; +} + static const struct super_operations simplefs_sops = { .destroy_inode = simplefs_destory_inode, + .put_super = simplefs_put_super, }; +static int simplefs_load_journal(struct super_block *sb) +{ + struct journal_s *journal; + struct inode *inode; + struct simplefs_super_block *sfs_sb = SIMPLEFS_SB(sb); + + inode = simplefs_iget(sb, SIMPLEFS_JOURNAL_INODE_NUMBER); + + journal = jbd2_journal_init_inode(inode); + journal->j_private = sb; + + sfs_sb->journal = journal; + + 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) @@ -728,6 +760,9 @@ int simplefs_fill_super(struct super_block *sb, void *data, int silent) goto release; } + if ((ret = simplefs_load_journal(sb))) + goto release; + ret = 0; release: brelse(bh); diff --git a/simple.h b/simple.h index e7f1f96..a6e7aa1 100644 --- a/simple.h +++ b/simple.h @@ -1,6 +1,8 @@ #define SIMPLEFS_MAGIC 0x10032013 +#define SIMPLEFS_JOURNAL_MAGIC = 0x20032013 + #define SIMPLEFS_DEFAULT_BLOCK_SIZE 4096 #define SIMPLEFS_FILENAME_MAXLEN 255 #define SIMPLEFS_START_INO 10 @@ -32,9 +34,17 @@ const int SIMPLEFS_SUPERBLOCK_BLOCK_NUMBER = 0; /* The disk block where the inodes are stored */ const int SIMPLEFS_INODESTORE_BLOCK_NUMBER = 1; +/** Journal settings */ +const int SIMPLEFS_JOURNAL_INODE_NUMBER = 2; +const int SIMPLEFS_JOURNAL_BLOCK_NUMBER = 2; +const int SIMPLEFS_JOURNAL_BLOCKS = 2; + /* The disk block where the name+inode_number pairs of the * contents of the root directory are stored */ -const int SIMPLEFS_ROOTDIR_DATABLOCK_NUMBER = 2; +const int SIMPLEFS_ROOTDIR_DATABLOCK_NUMBER = 4; + +#define SIMPLEFS_LAST_RESERVED_BLOCK SIMPLEFS_ROOTDIR_DATABLOCK_NUMBER +#define SIMPLEFS_LAST_RESERVED_INODE SIMPLEFS_JOURNAL_INODE_NUMBER /* The name+inode_number pair for each file in a directory. * This gets stored as the data for a directory */ @@ -63,6 +73,8 @@ const int SIMPLEFS_MAX_FILESYSTEM_OBJECTS_SUPPORTED = 64; /* FIXME: Move the struct to its own file and not expose the members * Always access using the simplefs_sb_* functions and * do not access the members directly */ + +struct journal_s; struct simplefs_super_block { uint64_t version; uint64_t magic; @@ -73,5 +85,8 @@ struct simplefs_super_block { uint64_t free_blocks; - char padding[SIMPLEFS_DEFAULT_BLOCK_SIZE - (5 * sizeof(uint64_t))]; + /** FIXME: move this into separate struct */ + struct journal_s *journal; + + char padding[4048]; }; From f8009d2223fb8acc068eed92c4ca8d3e159ad77b Mon Sep 17 00:00:00 2001 From: Azat Khuzhin Date: Sun, 13 Jul 2014 00:44:35 +0400 Subject: [PATCH 02/16] simplefs_write: add journaling using jbd2 --- simple.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/simple.c b/simple.c index 7b1e2a8..2c64d53 100644 --- a/simple.c +++ b/simple.c @@ -359,19 +359,25 @@ ssize_t simplefs_write(struct file * filp, const char __user * buf, size_t len, struct simplefs_inode *sfs_inode; struct buffer_head *bh; struct super_block *sb; + struct simplefs_super_block *sfs_sb; + handle_t *handle; char *buffer; int retval; + sb = filp->f_path.dentry->d_inode->i_sb; + sfs_sb = SIMPLEFS_SB(sb); + + handle = jbd2_journal_start(sfs_sb->journal, 1); + if (IS_ERR(handle)) + return PTR_ERR(handle); retval = generic_write_checks(filp, ppos, &len, 0); - if (retval) { + if (retval) return retval; - } inode = filp->f_path.dentry->d_inode; sfs_inode = SIMPLEFS_INODE(inode); - sb = inode->i_sb; bh = sb_bread(filp->f_path.dentry->d_inode->i_sb, sfs_inode->data_block_number); @@ -386,6 +392,13 @@ ssize_t simplefs_write(struct file * filp, const char __user * buf, size_t len, /* Move the pointer until the required byte offset */ buffer += *ppos; + retval = jbd2_journal_get_write_access(handle, bh); + if (WARN_ON(retval)) { + brelse(bh); + sfs_trace("Can't get write access for bh\n"); + return retval; + } + if (copy_from_user(buffer, buf, len)) { brelse(bh); printk(KERN_ERR @@ -394,6 +407,17 @@ ssize_t simplefs_write(struct file * filp, const char __user * buf, size_t len, } *ppos += len; + retval = jbd2_journal_dirty_metadata(handle, bh); + if (WARN_ON(retval)) { + brelse(bh); + return retval; + } + retval = jbd2_journal_stop(handle); + if (WARN_ON(retval)) { + brelse(bh); + return retval; + } + mark_buffer_dirty(bh); sync_dirty_buffer(bh); brelse(bh); From 57a1e15c0fd62e892b77115c30750ed191d37ba3 Mon Sep 17 00:00:00 2001 From: Azat Khuzhin Date: Sun, 13 Jul 2014 15:26:02 +0400 Subject: [PATCH 03/16] Implement external journal device instead of internal --- simple.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 46 insertions(+), 5 deletions(-) diff --git a/simple.c b/simple.c index 2c64d53..26714ce 100644 --- a/simple.c +++ b/simple.c @@ -15,6 +15,8 @@ #include #include #include +#include +#include #include "super.h" @@ -700,15 +702,23 @@ static const struct super_operations simplefs_sops = { .put_super = simplefs_put_super, }; -static int simplefs_load_journal(struct super_block *sb) +static int simplefs_load_journal(struct super_block *sb, int devnum) { struct journal_s *journal; - struct inode *inode; + dev_t dev; + struct block_device *bdev; + int hblock, blocksize, len; struct simplefs_super_block *sfs_sb = SIMPLEFS_SB(sb); - inode = simplefs_iget(sb, SIMPLEFS_JOURNAL_INODE_NUMBER); + dev = new_decode_dev(devnum); + bdev = blkdev_get_by_dev(dev, FMODE_READ|FMODE_WRITE|FMODE_EXCL, sb); + if (IS_ERR(bdev)) + return 1; + blocksize = sb->s_blocksize; + hblock = bdev_logical_block_size(bdev); + len = SIMPLEFS_MAX_FILESYSTEM_OBJECTS_SUPPORTED; - journal = jbd2_journal_init_inode(inode); + journal = jbd2_journal_init_dev(bdev, sb->s_bdev, 1, len, blocksize); journal->j_private = sb; sfs_sb->journal = journal; @@ -716,6 +726,37 @@ static int simplefs_load_journal(struct super_block *sb) return 0; } +#define SIMPLEFS_OPT_JOURNAL_DEV 1 +static const match_table_t tokens = { + {SIMPLEFS_OPT_JOURNAL_DEV, "journal_dev=%u"}, +}; +static int simplefs_parse_options(struct super_block *sb, char *options) +{ + substring_t args[MAX_OPT_ARGS]; + int token, ret, arg; + char *p; + + while ((p = strsep(&options, ",")) != NULL) { + if (!*p) + continue; + + args[0].to = args[0].from = NULL; + token = match_token(p, tokens, args); + + switch (token) { + case SIMPLEFS_OPT_JOURNAL_DEV: + if (args->from && match_int(args, &arg)) + return 1; + printk(KERN_INFO "Loading journal devnum: %i\n", arg); + if ((ret = simplefs_load_journal(sb, arg))) + return ret; + break; + } + } + + 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) @@ -784,7 +825,7 @@ int simplefs_fill_super(struct super_block *sb, void *data, int silent) goto release; } - if ((ret = simplefs_load_journal(sb))) + if ((ret = simplefs_parse_options(sb, data))) goto release; ret = 0; From aa630d8e0f0415cb26f9000cdab77c9eaae2eb43 Mon Sep 17 00:00:00 2001 From: Azat Khuzhin Date: Sun, 13 Jul 2014 17:30:40 +0400 Subject: [PATCH 04/16] Write journal device name --- simple.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/simple.c b/simple.c index 26714ce..0b4f0b7 100644 --- a/simple.c +++ b/simple.c @@ -705,12 +705,15 @@ static const struct super_operations simplefs_sops = { static int simplefs_load_journal(struct super_block *sb, int devnum) { struct journal_s *journal; + char b[BDEVNAME_SIZE]; dev_t dev; struct block_device *bdev; int hblock, blocksize, len; struct simplefs_super_block *sfs_sb = SIMPLEFS_SB(sb); dev = new_decode_dev(devnum); + printk(KERN_INFO "Journal device is: %s\n", __bdevname(dev, b)); + bdev = blkdev_get_by_dev(dev, FMODE_READ|FMODE_WRITE|FMODE_EXCL, sb); if (IS_ERR(bdev)) return 1; From a619accdc7c192aedfdbee3aace894be6b262321 Mon Sep 17 00:00:00 2001 From: Azat Khuzhin Date: Sun, 13 Jul 2014 18:02:33 +0400 Subject: [PATCH 05/16] Check that journal was initialized successfully Otherwise you will next trace: [ 964.775061] The magic number obtained in disk is: [268640275] [ 964.775554] simplefs filesystem of version [1] formatted with a block size of [4096] detected in the device. [ 964.776308] Loading journal devnum: 63 [ 964.776724] Journal device is: unknown-block(0,63) [ 964.779494] simplefs superblock is destroyed. Unmount succesful. [ 964.781366] Freeing private data of inode ffff88007babe3a8 (1) [ 964.781903] simplefs is succesfully mounted on [/dev/loop0] [ 964.782393] BUG: unable to handle kernel NULL pointer dereference at 0000000000000069 [ 964.783381] IP: [] mount_fs+0x71/0x148 [ 964.783977] PGD 7a545067 PUD 7a514067 PMD 0 [ 964.784814] Oops: 0000 [#1] PREEMPT SMP [ 964.785176] Modules linked in: simplefs(PO) loop fuse joydev hid_generic usbhid hid snd_pcm microcode snd_timer snd psmouse soundcore evdev pcspkr serio_raw ohci_pci ohci_hcd ehci_hcd processor parport_pc usbcore button battery ac thermal_sys parport i2c_piix4 usb_common i2c_core ext4 crc16 jbd2 mbcache sg sd_mod sr_mod crc_t10dif cdrom crct10dif_common ata_generic ahci libahci ata_piix libata scsi_mod e1000 [last unloaded: simplefs] [ 964.785176] CPU: 0 PID: 3507 Comm: mount Tainted: P O 3.14.0-rc6+ #101 [ 964.785176] Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006 [ 964.785176] task: ffff88007cb8c6d0 ti: ffff88007ad04000 task.ti: ffff88007ad04000 [ 964.785176] RIP: 0010:[] [] mount_fs+0x71/0x148 [ 964.785176] RSP: 0018:ffff88007ad05e40 EFLAGS: 00010203 [ 964.785176] RAX: 0000000000000001 RBX: ffff88007c0fd000 RCX: 0000000000000007 [ 964.785176] RDX: 0000000000000001 RSI: 0000000000000046 RDI: 00000000ffffffff [ 964.785176] RBP: ffff88007ad05e70 R08: 0000000000000004 R09: ffff8800000bbca0 [ 964.785176] R10: fffffff000007bf4 R11: 0000000000000000 R12: ffff88007a329000 [ 964.785176] R13: 0000000000000001 R14: ffffffffa01d2000 R15: 0000000000000000 [ 964.785176] FS: 00007f195521f840(0000) GS:ffff88007fc00000(0000) knlGS:0000000000000000 [ 964.785176] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b [ 964.785176] CR2: 0000000000000069 CR3: 000000007a540000 CR4: 00000000000006f0 [ 964.785176] Stack: [ 964.785176] ffff88007a1de080 ffff88007a1de080 ffffffffa01d2000 ffff8800377b2220 [ 964.785176] ffff88007c0fd000 ffffffffa01d2000 ffff88007ad05ea8 ffffffff81143628 [ 964.785176] 0000000081142d1b ffff88007c0fd000 ffff8800377b2220 0000000000000027 [ 964.785176] Call Trace: [ 964.785176] [] vfs_kern_mount+0x5f/0xd3 [ 964.785176] [] do_mount+0x6f9/0x7f0 [ 964.785176] [] SyS_mount+0x80/0xb9 [ 964.785176] [] system_call_fastpath+0x16/0x1b [ 964.785176] Code: cf 06 00 85 c0 0f 85 d0 00 00 00 4c 89 ea 48 89 d9 44 89 fe 4c 89 f7 41 ff 56 10 49 89 c5 49 81 fd 00 f0 ff ff 0f 87 b0 00 00 00 <49> 8b 5d 68 48 85 db 75 02 0f 0b 48 83 bb d0 00 00 00 00 75 11 [ 964.785176] RIP [] mount_fs+0x71/0x148 [ 964.785176] RSP [ 964.785176] CR2: 0000000000000069 [ 964.820009] ---[ end trace fc63610f0693bff7 ]--- --- simple.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/simple.c b/simple.c index 0b4f0b7..504352f 100644 --- a/simple.c +++ b/simple.c @@ -722,6 +722,10 @@ static int simplefs_load_journal(struct super_block *sb, int devnum) len = SIMPLEFS_MAX_FILESYSTEM_OBJECTS_SUPPORTED; journal = jbd2_journal_init_dev(bdev, sb->s_bdev, 1, len, blocksize); + if (!journal) { + printk(KERN_ERR "Can't load journal\n"); + return 1; + } journal->j_private = sb; sfs_sb->journal = journal; From 65ab062528aef1ed0883bb40bd7861ecda04ac5b Mon Sep 17 00:00:00 2001 From: Azat Khuzhin Date: Wed, 17 Sep 2014 13:31:51 +0400 Subject: [PATCH 06/16] simple-test: enable jbd2-debug --- simple-test.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/simple-test.sh b/simple-test.sh index 5985566..45d153c 100755 --- a/simple-test.sh +++ b/simple-test.sh @@ -15,6 +15,8 @@ set -e +echo 1 >| /sys/module/jbd2/parameters/jbd2_debug + root_pwd="$PWD" test_dir="test-dir-$RANDOM" test_mount_point="test-mount-point-$RANDOM" From bd1188801c019f5b54b3d43870fe6fbcf7f58316 Mon Sep 17 00:00:00 2001 From: Azat Khuzhin Date: Wed, 17 Sep 2014 17:19:05 +0400 Subject: [PATCH 07/16] Add sfs_trace for lookup and compare inside it --- simple.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/simple.c b/simple.c index 504352f..8b562b0 100644 --- a/simple.c +++ b/simple.c @@ -651,9 +651,14 @@ struct dentry *simplefs_lookup(struct inode *parent_inode, bh = sb_bread(sb, parent->data_block_number); BUG_ON(!bh); + sfs_trace("Lookup in: ino=%llu, b=%llu\n", + parent->inode_no, parent->data_block_number); record = (struct simplefs_dir_record *)bh->b_data; for (i = 0; i < parent->dir_children_count; i++) { + sfs_trace("Have file: '%s' (ino=%llu)\n", + record->filename, record->inode_no); + 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 From fd1dc7a9514962a68c5f9b6a9872ccbf3f13f42c Mon Sep 17 00:00:00 2001 From: Azat Khuzhin Date: Wed, 17 Sep 2014 18:55:11 +0400 Subject: [PATCH 08/16] Add loader for internal journal (we need to update mkfs to support this) For internal journal we need enhance mkfs to use ext2fs lib, that will allow us to create journal (with proper header). --- simple.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/simple.c b/simple.c index 8b562b0..e8506a4 100644 --- a/simple.c +++ b/simple.c @@ -737,6 +737,24 @@ static int simplefs_load_journal(struct super_block *sb, int devnum) return 0; } +static int simplefs_sb_load_journal(struct super_block *sb) +{ + struct journal_s *journal; + struct simplefs_super_block *sfs_sb = SIMPLEFS_SB(sb); + struct inode *journal_inode; + + journal_inode = simplefs_iget(sb, SIMPLEFS_JOURNAL_INODE_NUMBER); + journal = jbd2_journal_init_inode(journal_inode); + if (!journal) { + printk(KERN_ERR "Can't load journal\n"); + return 1; + } + journal->j_private = sb; + + sfs_sb->journal = journal; + + return 0; +} #define SIMPLEFS_OPT_JOURNAL_DEV 1 static const match_table_t tokens = { @@ -797,6 +815,8 @@ int simplefs_fill_super(struct super_block *sb, void *data, int silent) "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", @@ -840,6 +860,10 @@ int simplefs_fill_super(struct super_block *sb, void *data, int silent) if ((ret = simplefs_parse_options(sb, data))) goto release; + if (!sb_disk->journal && (ret = simplefs_sb_load_journal(sb))) { + goto release; + } + ret = 0; release: brelse(bh); From 33f5f117df042cfc3df2c5b213e0295f33c06af9 Mon Sep 17 00:00:00 2001 From: Azat Khuzhin Date: Wed, 17 Sep 2014 20:52:09 +0400 Subject: [PATCH 09/16] Implement journal_path option --- simple.c | 39 ++++++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/simple.c b/simple.c index e8506a4..2817dad 100644 --- a/simple.c +++ b/simple.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -737,14 +738,12 @@ static int simplefs_load_journal(struct super_block *sb, int devnum) return 0; } -static int simplefs_sb_load_journal(struct super_block *sb) +static int simplefs_sb_load_journal(struct super_block *sb, struct inode *inode) { struct journal_s *journal; struct simplefs_super_block *sfs_sb = SIMPLEFS_SB(sb); - struct inode *journal_inode; - journal_inode = simplefs_iget(sb, SIMPLEFS_JOURNAL_INODE_NUMBER); - journal = jbd2_journal_init_inode(journal_inode); + journal = jbd2_journal_init_inode(inode); if (!journal) { printk(KERN_ERR "Can't load journal\n"); return 1; @@ -757,8 +756,10 @@ static int simplefs_sb_load_journal(struct super_block *sb) } #define SIMPLEFS_OPT_JOURNAL_DEV 1 +#define SIMPLEFS_OPT_JOURNAL_PATH 2 static const match_table_t tokens = { {SIMPLEFS_OPT_JOURNAL_DEV, "journal_dev=%u"}, + {SIMPLEFS_OPT_JOURNAL_PATH, "journal_path=%s"}, }; static int simplefs_parse_options(struct super_block *sb, char *options) { @@ -781,6 +782,30 @@ static int simplefs_parse_options(struct super_block *sb, char *options) if ((ret = simplefs_load_journal(sb, arg))) return ret; break; + + case SIMPLEFS_OPT_JOURNAL_PATH: + { + char *journal_path; + struct inode *journal_inode; + struct path path; + + BUG_ON(!(journal_path = match_strdup(&args[0]))); + ret = kern_path(journal_path, LOOKUP_FOLLOW, &path); + if (ret) { + printk(KERN_ERR "could not find journal device path: error %d\n", ret); + kfree(journal_path); + } + + journal_inode = path.dentry->d_inode; + + path_put(&path); + kfree(journal_path); + + if ((ret = simplefs_sb_load_journal(sb, journal_inode))) + return ret; + + break; + } } } @@ -860,7 +885,11 @@ int simplefs_fill_super(struct super_block *sb, void *data, int silent) if ((ret = simplefs_parse_options(sb, data))) goto release; - if (!sb_disk->journal && (ret = simplefs_sb_load_journal(sb))) { + 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; } From e21bfc88e3273b4beb1386a6b4cc14188e3d3b78 Mon Sep 17 00:00:00 2001 From: Azat Khuzhin Date: Wed, 17 Sep 2014 21:04:06 +0400 Subject: [PATCH 10/16] simple-test: mount fs with journal --- simple-test.sh | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/simple-test.sh b/simple-test.sh index 45d153c..d0102f2 100755 --- a/simple-test.sh +++ b/simple-test.sh @@ -21,6 +21,11 @@ root_pwd="$PWD" test_dir="test-dir-$RANDOM" test_mount_point="test-mount-point-$RANDOM" +function create_journal() +{ + dd bs=1M count=10 if=/dev/zero of="$1" + mke2fs -O journal_dev "$1" +} function create_test_image() { dd bs=4096 count=100 if=/dev/zero of="$1" @@ -29,7 +34,7 @@ function create_test_image() function mount_fs_image() { insmod simplefs.ko - mount -o loop,owner,group,users -t simplefs "$1" "$2" + mount -o loop,owner,group,users,journal_path="$1" -t simplefs "$2" "$3" dmesg | tail -n20 } function unmount_fs() @@ -108,15 +113,16 @@ cleanup trap cleanup SIGINT EXIT mkdir "$test_dir" "$test_mount_point" create_test_image "$test_dir/image" +create_journal "$test_dir/journal" # 1 -mount_fs_image "$test_dir/image" "$test_mount_point" +mount_fs_image "$test_dir/journal" "$test_dir/image" "$test_mount_point" do_some_operations "$test_mount_point" cd "$root_pwd" unmount_fs "$test_mount_point" # 2 -mount_fs_image "$test_dir/image" "$test_mount_point" +mount_fs_image "$test_dir/journal" "$test_dir/image" "$test_mount_point" do_read_operations "$test_mount_point" cd "$root_pwd" unmount_fs "$test_mount_point" From 87e3751725f0938d88b2f9a82056ca82824af5e8 Mon Sep 17 00:00:00 2001 From: Azat Khuzhin Date: Wed, 17 Sep 2014 21:09:54 +0400 Subject: [PATCH 11/16] Actually load journal by calling jbd2_journal_load() --- simple.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simple.c b/simple.c index 2817dad..e01b56e 100644 --- a/simple.c +++ b/simple.c @@ -892,8 +892,8 @@ int simplefs_fill_super(struct super_block *sb, void *data, int silent) ret = simplefs_sb_load_journal(sb, journal_inode); goto release; } + ret = jbd2_journal_load(sb_disk->journal); - ret = 0; release: brelse(bh); From cb833cd5916e91c47fd2a2942df766c243a1ba43 Mon Sep 17 00:00:00 2001 From: Azat Khuzhin Date: Thu, 18 Sep 2014 02:26:44 +0400 Subject: [PATCH 12/16] Handle bdevs for journal_path= mount flag --- simple.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/simple.c b/simple.c index e01b56e..b689658 100644 --- a/simple.c +++ b/simple.c @@ -801,8 +801,15 @@ static int simplefs_parse_options(struct super_block *sb, char *options) path_put(&path); kfree(journal_path); - if ((ret = simplefs_sb_load_journal(sb, journal_inode))) - return ret; + if (S_ISBLK(journal_inode->i_mode)) { + unsigned long journal_devnum = new_encode_dev(journal_inode->i_rdev); + if ((ret = simplefs_load_journal(sb, journal_devnum))) + return ret; + } else { + /** Seems didn't work properly */ + if ((ret = simplefs_sb_load_journal(sb, journal_inode))) + return ret; + } break; } From 3384ede4bda04421e64dc149846f4432364632bf Mon Sep 17 00:00:00 2001 From: Azat Khuzhin Date: Thu, 18 Sep 2014 02:29:00 +0400 Subject: [PATCH 13/16] simple-test: use losetup+journal_path=/dev/loopX for mounting with journal --- simple-test.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/simple-test.sh b/simple-test.sh index d0102f2..d5c1008 100755 --- a/simple-test.sh +++ b/simple-test.sh @@ -20,6 +20,7 @@ echo 1 >| /sys/module/jbd2/parameters/jbd2_debug root_pwd="$PWD" test_dir="test-dir-$RANDOM" test_mount_point="test-mount-point-$RANDOM" +test_journal_dev="" function create_journal() { @@ -34,12 +35,14 @@ function create_test_image() function mount_fs_image() { insmod simplefs.ko - mount -o loop,owner,group,users,journal_path="$1" -t simplefs "$2" "$3" + test_journal_dev=$(losetup -f --show "$1") + mount -o loop,owner,group,users,journal_path="$test_journal_dev" -t simplefs "$2" "$3" dmesg | tail -n20 } function unmount_fs() { umount "$1" + losetup -d $test_journal_dev rmmod simplefs.ko dmesg | tail -n20 } From 7023aebf18eea82a2fe29fcd433a464aca2e9930 Mon Sep 17 00:00:00 2001 From: Azat Khuzhin Date: Thu, 18 Sep 2014 02:37:38 +0400 Subject: [PATCH 14/16] simple-test: create journal with 4k block size This must avoid next error: [ 6.694339] Journal device is: unknown-block(7,0) [ 6.695620] JBD2: no valid journal superblock found --- simple-test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simple-test.sh b/simple-test.sh index d5c1008..f499066 100755 --- a/simple-test.sh +++ b/simple-test.sh @@ -25,7 +25,7 @@ test_journal_dev="" function create_journal() { dd bs=1M count=10 if=/dev/zero of="$1" - mke2fs -O journal_dev "$1" + mke2fs -b 4096 -O journal_dev "$1" } function create_test_image() { From 49937e8acf4f2c00793f3225bee1a46cd6b6d453 Mon Sep 17 00:00:00 2001 From: Azat Khuzhin Date: Thu, 18 Sep 2014 02:47:51 +0400 Subject: [PATCH 15/16] Use max available journal size with jbd2_journal_init_dev() Avoid next error: JBD2: journal file too short --- simple.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simple.c b/simple.c index b689658..42549fc 100644 --- a/simple.c +++ b/simple.c @@ -727,7 +727,7 @@ static int simplefs_load_journal(struct super_block *sb, int devnum) hblock = bdev_logical_block_size(bdev); len = SIMPLEFS_MAX_FILESYSTEM_OBJECTS_SUPPORTED; - journal = jbd2_journal_init_dev(bdev, sb->s_bdev, 1, len, blocksize); + journal = jbd2_journal_init_dev(bdev, sb->s_bdev, 1, -1, blocksize); if (!journal) { printk(KERN_ERR "Can't load journal\n"); return 1; From 4c486f751bc1e27a7222006fcacae030068800b9 Mon Sep 17 00:00:00 2001 From: Azat Khuzhin Date: Tue, 23 Sep 2014 00:16:49 +0400 Subject: [PATCH 16/16] simplefs_write: install h_sync (sync on close) for jbd2 handle This will make simplefs journaling more robust. + head -n100 /proc/fs/jbd2/loop0/info 7 transactions (7 requested), each up to 640 blocks average: 0ms waiting for transaction 10ms request delay 26ms running transaction 0ms transaction was being locked 0ms flushing data (in ordered mode) 0ms logging transaction 3459us average transaction commit time 1 handles per transaction 1 blocks per transaction 2 logged blocks per transaction --- simple.c | 1 + 1 file changed, 1 insertion(+) diff --git a/simple.c b/simple.c index 42549fc..c2bb5e2 100644 --- a/simple.c +++ b/simple.c @@ -415,6 +415,7 @@ ssize_t simplefs_write(struct file * filp, const char __user * buf, size_t len, brelse(bh); return retval; } + handle->h_sync = 1; retval = jbd2_journal_stop(handle); if (WARN_ON(retval)) { brelse(bh);