X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=fs%2Fjfs%2Fsuper.c;h=35a7cc797725b8184c0b53157685f403c5ba4d25;hb=refs%2Fheads%2Fvserver;hp=72ae53817dfd5984c85ec5bf0c397954562ed3c9;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/fs/jfs/super.c b/fs/jfs/super.c index 72ae53817..35a7cc797 100644 --- a/fs/jfs/super.c +++ b/fs/jfs/super.c @@ -4,29 +4,35 @@ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include -#include #include #include #include #include +#include +#include +#include +#include +#include #include +#include #include "jfs_incore.h" #include "jfs_filsys.h" +#include "jfs_inode.h" #include "jfs_metapage.h" #include "jfs_superblock.h" #include "jfs_dmap.h" @@ -38,53 +44,27 @@ MODULE_DESCRIPTION("The Journaled Filesystem (JFS)"); MODULE_AUTHOR("Steve Best/Dave Kleikamp/Barry Arndt, IBM"); MODULE_LICENSE("GPL"); -static kmem_cache_t * jfs_inode_cachep; +static struct kmem_cache * jfs_inode_cachep; static struct super_operations jfs_super_operations; static struct export_operations jfs_export_operations; static struct file_system_type jfs_fs_type; -int jfs_stop_threads; -static pid_t jfsIOthread; -static pid_t jfsCommitThread; -static pid_t jfsSyncThread; -DECLARE_COMPLETION(jfsIOwait); +#define MAX_COMMIT_THREADS 64 +static int commit_threads = 0; +module_param(commit_threads, int, 0); +MODULE_PARM_DESC(commit_threads, "Number of commit threads"); + +static struct task_struct *jfsCommitThread[MAX_COMMIT_THREADS]; +struct task_struct *jfsIOthread; +struct task_struct *jfsSyncThread; #ifdef CONFIG_JFS_DEBUG int jfsloglevel = JFS_LOGLEVEL_WARN; -MODULE_PARM(jfsloglevel, "i"); +module_param(jfsloglevel, int, 0644); MODULE_PARM_DESC(jfsloglevel, "Specify JFS loglevel (0, 1 or 2)"); #endif -/* - * External declarations - */ -extern int jfs_mount(struct super_block *); -extern int jfs_mount_rw(struct super_block *, int); -extern int jfs_umount(struct super_block *); -extern int jfs_umount_rw(struct super_block *); - -extern int jfsIOWait(void *); -extern int jfs_lazycommit(void *); -extern int jfs_sync(void *); - -extern void jfs_read_inode(struct inode *inode); -extern void jfs_dirty_inode(struct inode *inode); -extern void jfs_delete_inode(struct inode *inode); -extern void jfs_write_inode(struct inode *inode, int wait); - -extern struct dentry *jfs_get_parent(struct dentry *dentry); -extern int jfs_extendfs(struct super_block *, s64, int); - -#ifdef PROC_FS_JFS /* see jfs_debug.h */ -extern void jfs_proc_init(void); -extern void jfs_proc_clean(void); -#endif - -extern wait_queue_head_t jfs_IO_thread_wait; -extern wait_queue_head_t jfs_commit_thread_wait; -extern wait_queue_head_t jfs_sync_thread_wait; - static void jfs_handle_error(struct super_block *sb) { struct jfs_sb_info *sbi = JFS_SBI(sb); @@ -102,7 +82,7 @@ static void jfs_handle_error(struct super_block *sb) "as read-only\n", sb->s_id); sb->s_flags |= MS_RDONLY; - } + } /* nothing is done for continue beyond marking the superblock dirty */ } @@ -113,7 +93,7 @@ void jfs_error(struct super_block *sb, const char * function, ...) va_list args; va_start(args, function); - vsprintf(error_buf, function, args); + vsnprintf(error_buf, sizeof(error_buf), function, args); va_end(args); printk(KERN_ERR "ERROR: (device %s): %s\n", sb->s_id, error_buf); @@ -135,10 +115,15 @@ static void jfs_destroy_inode(struct inode *inode) { struct jfs_inode_info *ji = JFS_IP(inode); + BUG_ON(!list_empty(&ji->anon_inode_list)); + + spin_lock_irq(&ji->ag_lock); if (ji->active_ag != -1) { struct bmap *bmap = JFS_SBI(inode->i_sb)->bmap; atomic_dec(&bmap->db_active[ji->active_ag]); + ji->active_ag = -1; } + spin_unlock_irq(&ji->ag_lock); #ifdef CONFIG_JFS_POSIX_ACL if (ji->i_acl != JFS_ACL_NOT_CACHED) { @@ -154,9 +139,9 @@ static void jfs_destroy_inode(struct inode *inode) kmem_cache_free(jfs_inode_cachep, ji); } -static int jfs_statfs(struct super_block *sb, struct kstatfs *buf) +static int jfs_statfs(struct dentry *dentry, struct kstatfs *buf) { - struct jfs_sb_info *sbi = JFS_SBI(sb); + struct jfs_sb_info *sbi = JFS_SBI(dentry->d_sb); s64 maxinodes; struct inomap *imap = JFS_IP(sbi->ipimap)->i_imap; @@ -199,12 +184,18 @@ static void jfs_put_super(struct super_block *sb) unload_nls(sbi->nls_tab); sbi->nls_tab = NULL; + truncate_inode_pages(sbi->direct_inode->i_mapping, 0); + iput(sbi->direct_inode); + sbi->direct_inode = NULL; + kfree(sbi); } enum { Opt_integrity, Opt_nointegrity, Opt_iocharset, Opt_resize, - Opt_resize_nosize, Opt_errors, Opt_ignore, Opt_err, + Opt_resize_nosize, Opt_errors, Opt_ignore, Opt_err, Opt_quota, + Opt_usrquota, Opt_grpquota, Opt_uid, Opt_gid, Opt_umask, + Opt_tag, Opt_notag, Opt_tagid }; static match_table_t tokens = { @@ -214,17 +205,24 @@ static match_table_t tokens = { {Opt_resize, "resize=%u"}, {Opt_resize_nosize, "resize"}, {Opt_errors, "errors=%s"}, + {Opt_tag, "tag"}, + {Opt_notag, "notag"}, + {Opt_tagid, "tagid=%u"}, + {Opt_tag, "tagxid"}, {Opt_ignore, "noquota"}, {Opt_ignore, "quota"}, - {Opt_ignore, "usrquota"}, - {Opt_ignore, "grpquota"}, + {Opt_usrquota, "usrquota"}, + {Opt_grpquota, "grpquota"}, + {Opt_uid, "uid=%u"}, + {Opt_gid, "gid=%u"}, + {Opt_umask, "umask=%u"}, {Opt_err, NULL} }; static int parse_options(char *options, struct super_block *sb, s64 *newLVSize, int *flag) { - void *nls_map = NULL; + void *nls_map = (void *)-1; /* -1: no change; NULL: none */ char *p; struct jfs_sb_info *sbi = JFS_SBI(sb); @@ -252,12 +250,17 @@ static int parse_options(char *options, struct super_block *sb, s64 *newLVSize, /* Don't do anything ;-) */ break; case Opt_iocharset: - if (nls_map) /* specified iocharset twice! */ + if (nls_map && nls_map != (void *) -1) unload_nls(nls_map); - nls_map = load_nls(args[0].from); - if (!nls_map) { - printk(KERN_ERR "JFS: charset not found\n"); - goto cleanup; + if (!strcmp(args[0].from, "none")) + nls_map = NULL; + else { + nls_map = load_nls(args[0].from); + if (!nls_map) { + printk(KERN_ERR + "JFS: charset not found\n"); + goto cleanup; + } } break; case Opt_resize: @@ -300,6 +303,60 @@ static int parse_options(char *options, struct super_block *sb, s64 *newLVSize, } break; } + +#ifdef CONFIG_QUOTA + case Opt_quota: + case Opt_usrquota: + *flag |= JFS_USRQUOTA; + break; + case Opt_grpquota: + *flag |= JFS_GRPQUOTA; + break; +#else + case Opt_usrquota: + case Opt_grpquota: + case Opt_quota: + printk(KERN_ERR + "JFS: quota operations not supported\n"); + break; +#endif + case Opt_uid: + { + char *uid = args[0].from; + sbi->uid = simple_strtoul(uid, &uid, 0); + break; + } + case Opt_gid: + { + char *gid = args[0].from; + sbi->gid = simple_strtoul(gid, &gid, 0); + break; + } + case Opt_umask: + { + char *umask = args[0].from; + sbi->umask = simple_strtoul(umask, &umask, 8); + if (sbi->umask & ~0777) { + printk(KERN_ERR + "JFS: Invalid value of umask\n"); + goto cleanup; + } + break; + } +#ifndef CONFIG_TAGGING_NONE + case Opt_tag: + *flag |= JFS_TAGGED; + break; + case Opt_notag: + *flag &= JFS_TAGGED; + break; +#endif +#ifdef CONFIG_PROPAGATE + case Opt_tagid: + /* use args[0] */ + *flag |= JFS_TAGGED; + break; +#endif default: printk("jfs: Unrecognized mount option \"%s\" " " or missing value\n", p); @@ -307,7 +364,7 @@ static int parse_options(char *options, struct super_block *sb, s64 *newLVSize, } } - if (nls_map) { + if (nls_map != (void *) -1) { /* Discard old (if remount) */ if (sbi->nls_tab) unload_nls(sbi->nls_tab); @@ -316,7 +373,7 @@ static int parse_options(char *options, struct super_block *sb, s64 *newLVSize, return 1; cleanup: - if (nls_map) + if (nls_map && nls_map != (void *) -1) unload_nls(nls_map); return 0; } @@ -330,6 +387,13 @@ static int jfs_remount(struct super_block *sb, int *flags, char *data) if (!parse_options(data, sb, &newLVSize, &flag)) { return -EINVAL; } + + if ((flag & JFS_TAGGED) && !(sb->s_flags & MS_TAGGED)) { + printk(KERN_ERR "JFS: %s: tagging not permitted on remount.\n", + sb->s_id); + return -EINVAL; + } + if (newLVSize) { if (sb->s_flags & MS_RDONLY) { printk(KERN_ERR @@ -342,6 +406,12 @@ static int jfs_remount(struct super_block *sb, int *flags, char *data) } if ((sb->s_flags & MS_RDONLY) && !(*flags & MS_RDONLY)) { + /* + * Invalidate any previously read metadata. fsck may have + * changed the on-disk data since we mounted r/o + */ + truncate_inode_pages(JFS_SBI(sb)->direct_inode->i_mapping, 0); + JFS_SBI(sb)->flag = flag; return jfs_mount_rw(sb, 1); } @@ -376,12 +446,12 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent) if (!new_valid_dev(sb->s_bdev->bd_dev)) return -EOVERFLOW; - sbi = kmalloc(sizeof (struct jfs_sb_info), GFP_KERNEL); + sbi = kzalloc(sizeof (struct jfs_sb_info), GFP_KERNEL); if (!sbi) - return -ENOSPC; - memset(sbi, 0, sizeof (struct jfs_sb_info)); + return -ENOMEM; sb->s_fs_info = sbi; sbi->sb = sb; + sbi->uid = sbi->gid = sbi->umask = -1; /* initialize the mount flag and determine the default error handler */ flag = JFS_ERR_REMOUNT_RO; @@ -392,6 +462,13 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent) } sbi->flag = flag; +#ifdef CONFIG_JFS_POSIX_ACL + sb->s_flags |= MS_POSIXACL; +#endif + /* map mount option tagxid */ + if (sbi->flag & JFS_TAGGED) + sb->s_flags |= MS_TAGGED; + if (newLVSize) { printk(KERN_ERR "resize option for remount only\n"); return -EINVAL; @@ -408,15 +485,30 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent) sb->s_op = &jfs_super_operations; sb->s_export_op = &jfs_export_operations; + /* + * Initialize direct-mapping inode/address-space + */ + inode = new_inode(sb); + if (inode == NULL) + goto out_kfree; + inode->i_ino = 0; + inode->i_nlink = 1; + inode->i_size = sb->s_bdev->bd_inode->i_size; + inode->i_mapping->a_ops = &jfs_metapage_aops; + insert_inode_hash(inode); + mapping_set_gfp_mask(inode->i_mapping, GFP_NOFS); + + sbi->direct_inode = inode; + rc = jfs_mount(sb); if (rc) { if (!silent) { jfs_err("jfs_mount failed w/return code = %d", rc); } - goto out_kfree; + goto out_mount_failed; } if (sb->s_flags & MS_RDONLY) - sbi->log = 0; + sbi->log = NULL; else { rc = jfs_mount_rw(sb, 0); if (rc) { @@ -437,6 +529,9 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent) if (!sb->s_root) goto out_no_root; + if (sbi->mntflag & JFS_OS2) + sb->s_root->d_op = &jfs_ci_dentry_operations; + /* logical blocks are represented by 40 bits in pxd_t, etc. */ sb->s_maxbytes = ((u64) sb->s_blocksize) << 40; #if BITS_PER_LONG == 32 @@ -446,7 +541,7 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent) */ sb->s_maxbytes = min(((u64) PAGE_CACHE_SIZE << 32) - 1, sb->s_maxbytes); #endif - + sb->s_time_gran = 1; return 0; out_no_root: @@ -459,6 +554,12 @@ out_no_rw: if (rc) { jfs_err("jfs_umount failed with return code %d", rc); } +out_mount_failed: + filemap_write_and_wait(sbi->direct_inode->i_mapping); + truncate_inode_pages(sbi->direct_inode->i_mapping, 0); + make_bad_inode(sbi->direct_inode); + iput(sbi->direct_inode); + sbi->direct_inode = NULL; out_kfree: if (sbi->nls_tab) unload_nls(sbi->nls_tab); @@ -493,10 +594,11 @@ static void jfs_unlockfs(struct super_block *sb) } } -static struct super_block *jfs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int jfs_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, struct vfsmount *mnt) { - return get_sb_bdev(fs_type, flags, dev_name, data, jfs_fill_super); + return get_sb_bdev(fs_type, flags, dev_name, data, jfs_fill_super, + mnt); } static int jfs_sync_fs(struct super_block *sb, int wait) @@ -504,12 +606,145 @@ static int jfs_sync_fs(struct super_block *sb, int wait) struct jfs_log *log = JFS_SBI(sb)->log; /* log == NULL indicates read-only mount */ - if (log) + if (log) { jfs_flush_journal(log, wait); + jfs_syncpt(log, 0); + } + + return 0; +} + +static int jfs_show_options(struct seq_file *seq, struct vfsmount *vfs) +{ + struct jfs_sb_info *sbi = JFS_SBI(vfs->mnt_sb); + + if (sbi->uid != -1) + seq_printf(seq, ",uid=%d", sbi->uid); + if (sbi->gid != -1) + seq_printf(seq, ",gid=%d", sbi->gid); + if (sbi->umask != -1) + seq_printf(seq, ",umask=%03o", sbi->umask); + if (sbi->flag & JFS_NOINTEGRITY) + seq_puts(seq, ",nointegrity"); + +#ifdef CONFIG_QUOTA + if (sbi->flag & JFS_USRQUOTA) + seq_puts(seq, ",usrquota"); + + if (sbi->flag & JFS_GRPQUOTA) + seq_puts(seq, ",grpquota"); +#endif return 0; } +#ifdef CONFIG_QUOTA + +/* Read data from quotafile - avoid pagecache and such because we cannot afford + * acquiring the locks... As quota files are never truncated and quota code + * itself serializes the operations (and noone else should touch the files) + * we don't have to be afraid of races */ +static ssize_t jfs_quota_read(struct super_block *sb, int type, char *data, + size_t len, loff_t off) +{ + struct inode *inode = sb_dqopt(sb)->files[type]; + sector_t blk = off >> sb->s_blocksize_bits; + int err = 0; + int offset = off & (sb->s_blocksize - 1); + int tocopy; + size_t toread; + struct buffer_head tmp_bh; + struct buffer_head *bh; + loff_t i_size = i_size_read(inode); + + if (off > i_size) + return 0; + if (off+len > i_size) + len = i_size-off; + toread = len; + while (toread > 0) { + tocopy = sb->s_blocksize - offset < toread ? + sb->s_blocksize - offset : toread; + + tmp_bh.b_state = 0; + tmp_bh.b_size = 1 << inode->i_blkbits; + err = jfs_get_block(inode, blk, &tmp_bh, 0); + if (err) + return err; + if (!buffer_mapped(&tmp_bh)) /* A hole? */ + memset(data, 0, tocopy); + else { + bh = sb_bread(sb, tmp_bh.b_blocknr); + if (!bh) + return -EIO; + memcpy(data, bh->b_data+offset, tocopy); + brelse(bh); + } + offset = 0; + toread -= tocopy; + data += tocopy; + blk++; + } + return len; +} + +/* Write to quotafile */ +static ssize_t jfs_quota_write(struct super_block *sb, int type, + const char *data, size_t len, loff_t off) +{ + struct inode *inode = sb_dqopt(sb)->files[type]; + sector_t blk = off >> sb->s_blocksize_bits; + int err = 0; + int offset = off & (sb->s_blocksize - 1); + int tocopy; + size_t towrite = len; + struct buffer_head tmp_bh; + struct buffer_head *bh; + + mutex_lock(&inode->i_mutex); + while (towrite > 0) { + tocopy = sb->s_blocksize - offset < towrite ? + sb->s_blocksize - offset : towrite; + + tmp_bh.b_state = 0; + tmp_bh.b_size = 1 << inode->i_blkbits; + err = jfs_get_block(inode, blk, &tmp_bh, 1); + if (err) + goto out; + if (offset || tocopy != sb->s_blocksize) + bh = sb_bread(sb, tmp_bh.b_blocknr); + else + bh = sb_getblk(sb, tmp_bh.b_blocknr); + if (!bh) { + err = -EIO; + goto out; + } + lock_buffer(bh); + memcpy(bh->b_data+offset, data, tocopy); + flush_dcache_page(bh->b_page); + set_buffer_uptodate(bh); + mark_buffer_dirty(bh); + unlock_buffer(bh); + brelse(bh); + offset = 0; + towrite -= tocopy; + data += tocopy; + blk++; + } +out: + if (len == towrite) + return err; + if (inode->i_size < off+len-towrite) + i_size_write(inode, off+len-towrite); + inode->i_version++; + inode->i_mtime = inode->i_ctime = CURRENT_TIME; + mark_inode_dirty(inode); + mutex_unlock(&inode->i_mutex); + return len - towrite; +} + +#endif + static struct super_operations jfs_super_operations = { .alloc_inode = jfs_alloc_inode, .destroy_inode = jfs_destroy_inode, @@ -523,6 +758,11 @@ static struct super_operations jfs_super_operations = { .unlockfs = jfs_unlockfs, .statfs = jfs_statfs, .remount_fs = jfs_remount, + .show_options = jfs_show_options, +#ifdef CONFIG_QUOTA + .quota_read = jfs_quota_read, + .quota_write = jfs_quota_write, +#endif }; static struct export_operations jfs_export_operations = { @@ -537,12 +777,7 @@ static struct file_system_type jfs_fs_type = { .fs_flags = FS_REQUIRES_DEV, }; -extern int metapage_init(void); -extern int txInit(void); -extern void txExit(void); -extern void metapage_exit(void); - -static void init_once(void *foo, kmem_cache_t * cachep, unsigned long flags) +static void init_once(void *foo, struct kmem_cache * cachep, unsigned long flags) { struct jfs_inode_info *jfs_ip = (struct jfs_inode_info *) foo; @@ -551,8 +786,9 @@ static void init_once(void *foo, kmem_cache_t * cachep, unsigned long flags) memset(jfs_ip, 0, sizeof(struct jfs_inode_info)); INIT_LIST_HEAD(&jfs_ip->anon_inode_list); init_rwsem(&jfs_ip->rdwrlock); - init_MUTEX(&jfs_ip->commit_sem); + mutex_init(&jfs_ip->commit_mutex); init_rwsem(&jfs_ip->xattr_sem); + spin_lock_init(&jfs_ip->ag_lock); jfs_ip->active_ag = -1; #ifdef CONFIG_JFS_POSIX_ACL jfs_ip->i_acl = JFS_ACL_NOT_CACHED; @@ -564,11 +800,13 @@ static void init_once(void *foo, kmem_cache_t * cachep, unsigned long flags) static int __init init_jfs_fs(void) { + int i; int rc; jfs_inode_cachep = - kmem_cache_create("jfs_ip", sizeof(struct jfs_inode_info), 0, - SLAB_RECLAIM_ACCOUNT, init_once, NULL); + kmem_cache_create("jfs_ip", sizeof(struct jfs_inode_info), 0, + SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, + init_once, NULL); if (jfs_inode_cachep == NULL) return -ENOMEM; @@ -593,26 +831,34 @@ static int __init init_jfs_fs(void) /* * I/O completion thread (endio) */ - jfsIOthread = kernel_thread(jfsIOWait, 0, CLONE_KERNEL); - if (jfsIOthread < 0) { - jfs_err("init_jfs_fs: fork failed w/rc = %d", jfsIOthread); + jfsIOthread = kthread_run(jfsIOWait, NULL, "jfsIO"); + if (IS_ERR(jfsIOthread)) { + rc = PTR_ERR(jfsIOthread); + jfs_err("init_jfs_fs: fork failed w/rc = %d", rc); goto end_txmngr; } - wait_for_completion(&jfsIOwait); /* Wait until thread starts */ - jfsCommitThread = kernel_thread(jfs_lazycommit, 0, CLONE_KERNEL); - if (jfsCommitThread < 0) { - jfs_err("init_jfs_fs: fork failed w/rc = %d", jfsCommitThread); - goto kill_iotask; + if (commit_threads < 1) + commit_threads = num_online_cpus(); + if (commit_threads > MAX_COMMIT_THREADS) + commit_threads = MAX_COMMIT_THREADS; + + for (i = 0; i < commit_threads; i++) { + jfsCommitThread[i] = kthread_run(jfs_lazycommit, NULL, "jfsCommit"); + if (IS_ERR(jfsCommitThread[i])) { + rc = PTR_ERR(jfsCommitThread[i]); + jfs_err("init_jfs_fs: fork failed w/rc = %d", rc); + commit_threads = i; + goto kill_committask; + } } - wait_for_completion(&jfsIOwait); /* Wait until thread starts */ - jfsSyncThread = kernel_thread(jfs_sync, 0, CLONE_KERNEL); - if (jfsSyncThread < 0) { - jfs_err("init_jfs_fs: fork failed w/rc = %d", jfsSyncThread); + jfsSyncThread = kthread_run(jfs_sync, NULL, "jfsSync"); + if (IS_ERR(jfsSyncThread)) { + rc = PTR_ERR(jfsSyncThread); + jfs_err("init_jfs_fs: fork failed w/rc = %d", rc); goto kill_committask; } - wait_for_completion(&jfsIOwait); /* Wait until thread starts */ #ifdef PROC_FS_JFS jfs_proc_init(); @@ -621,13 +867,9 @@ static int __init init_jfs_fs(void) return register_filesystem(&jfs_fs_type); kill_committask: - jfs_stop_threads = 1; - wake_up(&jfs_commit_thread_wait); - wait_for_completion(&jfsIOwait); /* Wait for thread exit */ -kill_iotask: - jfs_stop_threads = 1; - wake_up(&jfs_IO_thread_wait); - wait_for_completion(&jfsIOwait); /* Wait for thread exit */ + for (i = 0; i < commit_threads; i++) + kthread_stop(jfsCommitThread[i]); + kthread_stop(jfsIOthread); end_txmngr: txExit(); free_metapage: @@ -639,17 +881,17 @@ free_slab: static void __exit exit_jfs_fs(void) { + int i; + jfs_info("exit_jfs_fs called"); - jfs_stop_threads = 1; txExit(); metapage_exit(); - wake_up(&jfs_IO_thread_wait); - wait_for_completion(&jfsIOwait); /* Wait until IO thread exits */ - wake_up(&jfs_commit_thread_wait); - wait_for_completion(&jfsIOwait); /* Wait until Commit thread exits */ - wake_up(&jfs_sync_thread_wait); - wait_for_completion(&jfsIOwait); /* Wait until Sync thread exits */ + + kthread_stop(jfsIOthread); + for (i = 0; i < commit_threads; i++) + kthread_stop(jfsCommitThread[i]); + kthread_stop(jfsSyncThread); #ifdef PROC_FS_JFS jfs_proc_clean(); #endif