mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-21 19:53:59 +08:00
813e0c46c9
Following on from the recent clean up of gfs2_quotad, this patch moves the processing of "truncate in progress" inodes from the glock workqueue into gfs2_quotad. This fixes a hang due to the "truncate in progress" processing requiring glocks in order to complete. It might seem odd to use gfs2_quotad for this particular item, but we have to use a pre-existing thread since creating a thread implies a GFP_KERNEL memory allocation which is not allowed from the glock workqueue context. Of the existing threads, gfs2_logd and gfs2_recoverd may deadlock if used for this operation. gfs2_scand and gfs2_glockd are both scheduled for removal at some (hopefully not too distant) future point. That leaves only gfs2_quotad whose workload is generally fairly light and is easily adapted for this extra task. Also, as a result of this change, it opens the way for a future patch to make the reading of the inode's information asynchronous with respect to the glock workqueue, which is another improvement that has been on the list for some time now. Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
169 lines
3.7 KiB
C
169 lines
3.7 KiB
C
/*
|
|
* Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
|
|
* Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
|
|
*
|
|
* This copyrighted material is made available to anyone wishing to use,
|
|
* modify, copy, or redistribute it subject to the terms and conditions
|
|
* of the GNU General Public License version 2.
|
|
*/
|
|
|
|
#include <linux/slab.h>
|
|
#include <linux/spinlock.h>
|
|
#include <linux/completion.h>
|
|
#include <linux/buffer_head.h>
|
|
#include <linux/module.h>
|
|
#include <linux/init.h>
|
|
#include <linux/gfs2_ondisk.h>
|
|
#include <linux/lm_interface.h>
|
|
#include <asm/atomic.h>
|
|
|
|
#include "gfs2.h"
|
|
#include "incore.h"
|
|
#include "super.h"
|
|
#include "sys.h"
|
|
#include "util.h"
|
|
#include "glock.h"
|
|
|
|
static void gfs2_init_inode_once(void *foo)
|
|
{
|
|
struct gfs2_inode *ip = foo;
|
|
|
|
inode_init_once(&ip->i_inode);
|
|
init_rwsem(&ip->i_rw_mutex);
|
|
INIT_LIST_HEAD(&ip->i_trunc_list);
|
|
ip->i_alloc = NULL;
|
|
}
|
|
|
|
static void gfs2_init_glock_once(void *foo)
|
|
{
|
|
struct gfs2_glock *gl = foo;
|
|
|
|
INIT_HLIST_NODE(&gl->gl_list);
|
|
spin_lock_init(&gl->gl_spin);
|
|
INIT_LIST_HEAD(&gl->gl_holders);
|
|
gl->gl_lvb = NULL;
|
|
atomic_set(&gl->gl_lvb_count, 0);
|
|
INIT_LIST_HEAD(&gl->gl_reclaim);
|
|
INIT_LIST_HEAD(&gl->gl_ail_list);
|
|
atomic_set(&gl->gl_ail_count, 0);
|
|
}
|
|
|
|
/**
|
|
* init_gfs2_fs - Register GFS2 as a filesystem
|
|
*
|
|
* Returns: 0 on success, error code on failure
|
|
*/
|
|
|
|
static int __init init_gfs2_fs(void)
|
|
{
|
|
int error;
|
|
|
|
error = gfs2_sys_init();
|
|
if (error)
|
|
return error;
|
|
|
|
error = gfs2_glock_init();
|
|
if (error)
|
|
goto fail;
|
|
|
|
error = -ENOMEM;
|
|
gfs2_glock_cachep = kmem_cache_create("gfs2_glock",
|
|
sizeof(struct gfs2_glock),
|
|
0, 0,
|
|
gfs2_init_glock_once);
|
|
if (!gfs2_glock_cachep)
|
|
goto fail;
|
|
|
|
gfs2_inode_cachep = kmem_cache_create("gfs2_inode",
|
|
sizeof(struct gfs2_inode),
|
|
0, SLAB_RECLAIM_ACCOUNT|
|
|
SLAB_MEM_SPREAD,
|
|
gfs2_init_inode_once);
|
|
if (!gfs2_inode_cachep)
|
|
goto fail;
|
|
|
|
gfs2_bufdata_cachep = kmem_cache_create("gfs2_bufdata",
|
|
sizeof(struct gfs2_bufdata),
|
|
0, 0, NULL);
|
|
if (!gfs2_bufdata_cachep)
|
|
goto fail;
|
|
|
|
gfs2_rgrpd_cachep = kmem_cache_create("gfs2_rgrpd",
|
|
sizeof(struct gfs2_rgrpd),
|
|
0, 0, NULL);
|
|
if (!gfs2_rgrpd_cachep)
|
|
goto fail;
|
|
|
|
gfs2_quotad_cachep = kmem_cache_create("gfs2_quotad",
|
|
sizeof(struct gfs2_quota_data),
|
|
0, 0, NULL);
|
|
if (!gfs2_quotad_cachep)
|
|
goto fail;
|
|
|
|
error = register_filesystem(&gfs2_fs_type);
|
|
if (error)
|
|
goto fail;
|
|
|
|
error = register_filesystem(&gfs2meta_fs_type);
|
|
if (error)
|
|
goto fail_unregister;
|
|
|
|
gfs2_register_debugfs();
|
|
|
|
printk("GFS2 (built %s %s) installed\n", __DATE__, __TIME__);
|
|
|
|
return 0;
|
|
|
|
fail_unregister:
|
|
unregister_filesystem(&gfs2_fs_type);
|
|
fail:
|
|
gfs2_glock_exit();
|
|
|
|
if (gfs2_quotad_cachep)
|
|
kmem_cache_destroy(gfs2_quotad_cachep);
|
|
|
|
if (gfs2_rgrpd_cachep)
|
|
kmem_cache_destroy(gfs2_rgrpd_cachep);
|
|
|
|
if (gfs2_bufdata_cachep)
|
|
kmem_cache_destroy(gfs2_bufdata_cachep);
|
|
|
|
if (gfs2_inode_cachep)
|
|
kmem_cache_destroy(gfs2_inode_cachep);
|
|
|
|
if (gfs2_glock_cachep)
|
|
kmem_cache_destroy(gfs2_glock_cachep);
|
|
|
|
gfs2_sys_uninit();
|
|
return error;
|
|
}
|
|
|
|
/**
|
|
* exit_gfs2_fs - Unregister the file system
|
|
*
|
|
*/
|
|
|
|
static void __exit exit_gfs2_fs(void)
|
|
{
|
|
gfs2_glock_exit();
|
|
gfs2_unregister_debugfs();
|
|
unregister_filesystem(&gfs2_fs_type);
|
|
unregister_filesystem(&gfs2meta_fs_type);
|
|
|
|
kmem_cache_destroy(gfs2_quotad_cachep);
|
|
kmem_cache_destroy(gfs2_rgrpd_cachep);
|
|
kmem_cache_destroy(gfs2_bufdata_cachep);
|
|
kmem_cache_destroy(gfs2_inode_cachep);
|
|
kmem_cache_destroy(gfs2_glock_cachep);
|
|
|
|
gfs2_sys_uninit();
|
|
}
|
|
|
|
MODULE_DESCRIPTION("Global File System");
|
|
MODULE_AUTHOR("Red Hat, Inc.");
|
|
MODULE_LICENSE("GPL");
|
|
|
|
module_init(init_gfs2_fs);
|
|
module_exit(exit_gfs2_fs);
|
|
|