Merge git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-2.6-nmw
* git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-2.6-nmw: (34 commits) [GFS2] Uncomment sprintf_symbol calling code [DLM] lowcomms style [GFS2] printk warning fixes [GFS2] Patch to fix mmap of stuffed files [GFS2] use lib/parser for parsing mount options [DLM] Lowcomms nodeid range & initialisation fixes [DLM] Fix dlm_lowcoms_stop hang [DLM] fix mode munging [GFS2] lockdump improvements [GFS2] Patch to detect corrupt number of dir entries in leaf and/or inode blocks [GFS2] bz 236008: Kernel gpf doing cat /debugfs/gfs2/xxx (lock dump) [DLM] fs/dlm/ast.c should #include "ast.h" [DLM] Consolidate transport protocols [DLM] Remove redundant assignment [GFS2] Fix bz 234168 (ignoring rgrp flags) [DLM] change lkid format [DLM] interface for purge (2/2) [DLM] add orphan purging code (1/2) [DLM] split create_message function [GFS2] Set drop_count to 0 (off) by default ...
This commit is contained in:
commit
5cefcab3db
|
@ -3,36 +3,19 @@ menu "Distributed Lock Manager"
|
|||
|
||||
config DLM
|
||||
tristate "Distributed Lock Manager (DLM)"
|
||||
depends on SYSFS && (IPV6 || IPV6=n)
|
||||
depends on IPV6 || IPV6=n
|
||||
select CONFIGFS_FS
|
||||
select IP_SCTP if DLM_SCTP
|
||||
select IP_SCTP
|
||||
help
|
||||
A general purpose distributed lock manager for kernel or userspace
|
||||
applications.
|
||||
|
||||
choice
|
||||
prompt "Select DLM communications protocol"
|
||||
depends on DLM
|
||||
default DLM_TCP
|
||||
help
|
||||
The DLM Can use TCP or SCTP for it's network communications.
|
||||
SCTP supports multi-homed operations whereas TCP doesn't.
|
||||
However, SCTP seems to have stability problems at the moment.
|
||||
|
||||
config DLM_TCP
|
||||
bool "TCP/IP"
|
||||
|
||||
config DLM_SCTP
|
||||
bool "SCTP"
|
||||
|
||||
endchoice
|
||||
A general purpose distributed lock manager for kernel or userspace
|
||||
applications.
|
||||
|
||||
config DLM_DEBUG
|
||||
bool "DLM debugging"
|
||||
depends on DLM
|
||||
help
|
||||
Under the debugfs mount point, the name of each lockspace will
|
||||
appear as a file in the "dlm" directory. The output is the
|
||||
list of resource and locks the local node knows about.
|
||||
Under the debugfs mount point, the name of each lockspace will
|
||||
appear as a file in the "dlm" directory. The output is the
|
||||
list of resource and locks the local node knows about.
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -8,14 +8,12 @@ dlm-y := ast.o \
|
|||
member.o \
|
||||
memory.o \
|
||||
midcomms.o \
|
||||
lowcomms.o \
|
||||
rcom.o \
|
||||
recover.o \
|
||||
recoverd.o \
|
||||
requestqueue.o \
|
||||
user.o \
|
||||
util.o
|
||||
util.o
|
||||
dlm-$(CONFIG_DLM_DEBUG) += debug_fs.o
|
||||
|
||||
dlm-$(CONFIG_DLM_TCP) += lowcomms-tcp.o
|
||||
|
||||
dlm-$(CONFIG_DLM_SCTP) += lowcomms-sctp.o
|
|
@ -14,6 +14,7 @@
|
|||
#include "dlm_internal.h"
|
||||
#include "lock.h"
|
||||
#include "user.h"
|
||||
#include "ast.h"
|
||||
|
||||
#define WAKE_ASTS 0
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
*******************************************************************************
|
||||
**
|
||||
** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
|
||||
** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
|
||||
** Copyright (C) 2004-2007 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
|
||||
|
@ -89,6 +89,7 @@ struct cluster {
|
|||
unsigned int cl_toss_secs;
|
||||
unsigned int cl_scan_secs;
|
||||
unsigned int cl_log_debug;
|
||||
unsigned int cl_protocol;
|
||||
};
|
||||
|
||||
enum {
|
||||
|
@ -101,6 +102,7 @@ enum {
|
|||
CLUSTER_ATTR_TOSS_SECS,
|
||||
CLUSTER_ATTR_SCAN_SECS,
|
||||
CLUSTER_ATTR_LOG_DEBUG,
|
||||
CLUSTER_ATTR_PROTOCOL,
|
||||
};
|
||||
|
||||
struct cluster_attribute {
|
||||
|
@ -159,6 +161,7 @@ CLUSTER_ATTR(recover_timer, 1);
|
|||
CLUSTER_ATTR(toss_secs, 1);
|
||||
CLUSTER_ATTR(scan_secs, 1);
|
||||
CLUSTER_ATTR(log_debug, 0);
|
||||
CLUSTER_ATTR(protocol, 0);
|
||||
|
||||
static struct configfs_attribute *cluster_attrs[] = {
|
||||
[CLUSTER_ATTR_TCP_PORT] = &cluster_attr_tcp_port.attr,
|
||||
|
@ -170,6 +173,7 @@ static struct configfs_attribute *cluster_attrs[] = {
|
|||
[CLUSTER_ATTR_TOSS_SECS] = &cluster_attr_toss_secs.attr,
|
||||
[CLUSTER_ATTR_SCAN_SECS] = &cluster_attr_scan_secs.attr,
|
||||
[CLUSTER_ATTR_LOG_DEBUG] = &cluster_attr_log_debug.attr,
|
||||
[CLUSTER_ATTR_PROTOCOL] = &cluster_attr_protocol.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
@ -904,6 +908,7 @@ int dlm_our_addr(struct sockaddr_storage *addr, int num)
|
|||
#define DEFAULT_TOSS_SECS 10
|
||||
#define DEFAULT_SCAN_SECS 5
|
||||
#define DEFAULT_LOG_DEBUG 0
|
||||
#define DEFAULT_PROTOCOL 0
|
||||
|
||||
struct dlm_config_info dlm_config = {
|
||||
.ci_tcp_port = DEFAULT_TCP_PORT,
|
||||
|
@ -914,6 +919,7 @@ struct dlm_config_info dlm_config = {
|
|||
.ci_recover_timer = DEFAULT_RECOVER_TIMER,
|
||||
.ci_toss_secs = DEFAULT_TOSS_SECS,
|
||||
.ci_scan_secs = DEFAULT_SCAN_SECS,
|
||||
.ci_log_debug = DEFAULT_LOG_DEBUG
|
||||
.ci_log_debug = DEFAULT_LOG_DEBUG,
|
||||
.ci_protocol = DEFAULT_PROTOCOL
|
||||
};
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
*******************************************************************************
|
||||
**
|
||||
** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
|
||||
** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
|
||||
** Copyright (C) 2004-2007 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
|
||||
|
@ -26,6 +26,7 @@ struct dlm_config_info {
|
|||
int ci_toss_secs;
|
||||
int ci_scan_secs;
|
||||
int ci_log_debug;
|
||||
int ci_protocol;
|
||||
};
|
||||
|
||||
extern struct dlm_config_info dlm_config;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
*******************************************************************************
|
||||
**
|
||||
** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
|
||||
** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
|
||||
** Copyright (C) 2004-2007 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
|
||||
|
@ -210,6 +210,9 @@ struct dlm_args {
|
|||
#define DLM_IFL_MSTCPY 0x00010000
|
||||
#define DLM_IFL_RESEND 0x00020000
|
||||
#define DLM_IFL_DEAD 0x00040000
|
||||
#define DLM_IFL_OVERLAP_UNLOCK 0x00080000
|
||||
#define DLM_IFL_OVERLAP_CANCEL 0x00100000
|
||||
#define DLM_IFL_ENDOFLIFE 0x00200000
|
||||
#define DLM_IFL_USER 0x00000001
|
||||
#define DLM_IFL_ORPHAN 0x00000002
|
||||
|
||||
|
@ -230,8 +233,8 @@ struct dlm_lkb {
|
|||
int8_t lkb_grmode; /* granted lock mode */
|
||||
int8_t lkb_bastmode; /* requested mode */
|
||||
int8_t lkb_highbast; /* highest mode bast sent for */
|
||||
|
||||
int8_t lkb_wait_type; /* type of reply waiting for */
|
||||
int8_t lkb_wait_count;
|
||||
int8_t lkb_ast_type; /* type of ast queued for */
|
||||
|
||||
struct list_head lkb_idtbl_list; /* lockspace lkbtbl */
|
||||
|
@ -339,6 +342,7 @@ struct dlm_header {
|
|||
#define DLM_MSG_LOOKUP 11
|
||||
#define DLM_MSG_REMOVE 12
|
||||
#define DLM_MSG_LOOKUP_REPLY 13
|
||||
#define DLM_MSG_PURGE 14
|
||||
|
||||
struct dlm_message {
|
||||
struct dlm_header m_header;
|
||||
|
@ -440,6 +444,9 @@ struct dlm_ls {
|
|||
struct mutex ls_waiters_mutex;
|
||||
struct list_head ls_waiters; /* lkbs needing a reply */
|
||||
|
||||
struct mutex ls_orphans_mutex;
|
||||
struct list_head ls_orphans;
|
||||
|
||||
struct list_head ls_nodes; /* current nodes in ls */
|
||||
struct list_head ls_nodes_gone; /* dead node list, recovery */
|
||||
int ls_num_nodes; /* number of nodes in ls */
|
||||
|
|
959
fs/dlm/lock.c
959
fs/dlm/lock.c
File diff suppressed because it is too large
Load Diff
|
@ -41,6 +41,8 @@ int dlm_user_unlock(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
|
|||
uint32_t flags, uint32_t lkid, char *lvb_in);
|
||||
int dlm_user_cancel(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
|
||||
uint32_t flags, uint32_t lkid);
|
||||
int dlm_user_purge(struct dlm_ls *ls, struct dlm_user_proc *proc,
|
||||
int nodeid, int pid);
|
||||
void dlm_clear_proc_locks(struct dlm_ls *ls, struct dlm_user_proc *proc);
|
||||
|
||||
static inline int is_master(struct dlm_rsb *r)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
*******************************************************************************
|
||||
**
|
||||
** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
|
||||
** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
|
||||
** Copyright (C) 2004-2007 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
|
||||
|
@ -459,6 +459,8 @@ static int new_lockspace(char *name, int namelen, void **lockspace,
|
|||
|
||||
INIT_LIST_HEAD(&ls->ls_waiters);
|
||||
mutex_init(&ls->ls_waiters_mutex);
|
||||
INIT_LIST_HEAD(&ls->ls_orphans);
|
||||
mutex_init(&ls->ls_orphans_mutex);
|
||||
|
||||
INIT_LIST_HEAD(&ls->ls_nodes);
|
||||
INIT_LIST_HEAD(&ls->ls_nodes_gone);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
161
fs/dlm/user.c
161
fs/dlm/user.c
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2006 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2006-2007 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
|
||||
|
@ -56,6 +56,7 @@ struct dlm_write_request32 {
|
|||
union {
|
||||
struct dlm_lock_params32 lock;
|
||||
struct dlm_lspace_params lspace;
|
||||
struct dlm_purge_params purge;
|
||||
} i;
|
||||
};
|
||||
|
||||
|
@ -92,6 +93,9 @@ static void compat_input(struct dlm_write_request *kb,
|
|||
kb->i.lspace.flags = kb32->i.lspace.flags;
|
||||
kb->i.lspace.minor = kb32->i.lspace.minor;
|
||||
strcpy(kb->i.lspace.name, kb32->i.lspace.name);
|
||||
} else if (kb->cmd == DLM_USER_PURGE) {
|
||||
kb->i.purge.nodeid = kb32->i.purge.nodeid;
|
||||
kb->i.purge.pid = kb32->i.purge.pid;
|
||||
} else {
|
||||
kb->i.lock.mode = kb32->i.lock.mode;
|
||||
kb->i.lock.namelen = kb32->i.lock.namelen;
|
||||
|
@ -111,8 +115,6 @@ static void compat_input(struct dlm_write_request *kb,
|
|||
static void compat_output(struct dlm_lock_result *res,
|
||||
struct dlm_lock_result32 *res32)
|
||||
{
|
||||
res32->length = res->length - (sizeof(struct dlm_lock_result) -
|
||||
sizeof(struct dlm_lock_result32));
|
||||
res32->user_astaddr = (__u32)(long)res->user_astaddr;
|
||||
res32->user_astparam = (__u32)(long)res->user_astparam;
|
||||
res32->user_lksb = (__u32)(long)res->user_lksb;
|
||||
|
@ -128,35 +130,30 @@ static void compat_output(struct dlm_lock_result *res,
|
|||
}
|
||||
#endif
|
||||
|
||||
/* we could possibly check if the cancel of an orphan has resulted in the lkb
|
||||
being removed and then remove that lkb from the orphans list and free it */
|
||||
|
||||
void dlm_user_add_ast(struct dlm_lkb *lkb, int type)
|
||||
{
|
||||
struct dlm_ls *ls;
|
||||
struct dlm_user_args *ua;
|
||||
struct dlm_user_proc *proc;
|
||||
int remove_ownqueue = 0;
|
||||
int eol = 0, ast_type;
|
||||
|
||||
/* dlm_clear_proc_locks() sets ORPHAN/DEAD flag on each
|
||||
lkb before dealing with it. We need to check this
|
||||
flag before taking ls_clear_proc_locks mutex because if
|
||||
it's set, dlm_clear_proc_locks() holds the mutex. */
|
||||
|
||||
if (lkb->lkb_flags & (DLM_IFL_ORPHAN | DLM_IFL_DEAD)) {
|
||||
/* log_print("user_add_ast skip1 %x", lkb->lkb_flags); */
|
||||
if (lkb->lkb_flags & (DLM_IFL_ORPHAN | DLM_IFL_DEAD))
|
||||
return;
|
||||
}
|
||||
|
||||
ls = lkb->lkb_resource->res_ls;
|
||||
mutex_lock(&ls->ls_clear_proc_locks);
|
||||
|
||||
/* If ORPHAN/DEAD flag is set, it means the process is dead so an ast
|
||||
can't be delivered. For ORPHAN's, dlm_clear_proc_locks() freed
|
||||
lkb->ua so we can't try to use it. */
|
||||
lkb->ua so we can't try to use it. This second check is necessary
|
||||
for cases where a completion ast is received for an operation that
|
||||
began before clear_proc_locks did its cancel/unlock. */
|
||||
|
||||
if (lkb->lkb_flags & (DLM_IFL_ORPHAN | DLM_IFL_DEAD)) {
|
||||
/* log_print("user_add_ast skip2 %x", lkb->lkb_flags); */
|
||||
if (lkb->lkb_flags & (DLM_IFL_ORPHAN | DLM_IFL_DEAD))
|
||||
goto out;
|
||||
}
|
||||
|
||||
DLM_ASSERT(lkb->lkb_astparam, dlm_print_lkb(lkb););
|
||||
ua = (struct dlm_user_args *)lkb->lkb_astparam;
|
||||
|
@ -166,28 +163,42 @@ void dlm_user_add_ast(struct dlm_lkb *lkb, int type)
|
|||
goto out;
|
||||
|
||||
spin_lock(&proc->asts_spin);
|
||||
if (!(lkb->lkb_ast_type & (AST_COMP | AST_BAST))) {
|
||||
|
||||
ast_type = lkb->lkb_ast_type;
|
||||
lkb->lkb_ast_type |= type;
|
||||
|
||||
if (!ast_type) {
|
||||
kref_get(&lkb->lkb_ref);
|
||||
list_add_tail(&lkb->lkb_astqueue, &proc->asts);
|
||||
lkb->lkb_ast_type |= type;
|
||||
wake_up_interruptible(&proc->wait);
|
||||
}
|
||||
if (type == AST_COMP && (ast_type & AST_COMP))
|
||||
log_debug(ls, "ast overlap %x status %x %x",
|
||||
lkb->lkb_id, ua->lksb.sb_status, lkb->lkb_flags);
|
||||
|
||||
/* noqueue requests that fail may need to be removed from the
|
||||
proc's locks list, there should be a better way of detecting
|
||||
this situation than checking all these things... */
|
||||
/* Figure out if this lock is at the end of its life and no longer
|
||||
available for the application to use. The lkb still exists until
|
||||
the final ast is read. A lock becomes EOL in three situations:
|
||||
1. a noqueue request fails with EAGAIN
|
||||
2. an unlock completes with EUNLOCK
|
||||
3. a cancel of a waiting request completes with ECANCEL
|
||||
An EOL lock needs to be removed from the process's list of locks.
|
||||
And we can't allow any new operation on an EOL lock. This is
|
||||
not related to the lifetime of the lkb struct which is managed
|
||||
entirely by refcount. */
|
||||
|
||||
if (type == AST_COMP && lkb->lkb_grmode == DLM_LOCK_IV &&
|
||||
ua->lksb.sb_status == -EAGAIN && !list_empty(&lkb->lkb_ownqueue))
|
||||
remove_ownqueue = 1;
|
||||
|
||||
/* unlocks or cancels of waiting requests need to be removed from the
|
||||
proc's unlocking list, again there must be a better way... */
|
||||
|
||||
if (ua->lksb.sb_status == -DLM_EUNLOCK ||
|
||||
if (type == AST_COMP &&
|
||||
lkb->lkb_grmode == DLM_LOCK_IV &&
|
||||
ua->lksb.sb_status == -EAGAIN)
|
||||
eol = 1;
|
||||
else if (ua->lksb.sb_status == -DLM_EUNLOCK ||
|
||||
(ua->lksb.sb_status == -DLM_ECANCEL &&
|
||||
lkb->lkb_grmode == DLM_LOCK_IV))
|
||||
remove_ownqueue = 1;
|
||||
eol = 1;
|
||||
if (eol) {
|
||||
lkb->lkb_ast_type &= ~AST_BAST;
|
||||
lkb->lkb_flags |= DLM_IFL_ENDOFLIFE;
|
||||
}
|
||||
|
||||
/* We want to copy the lvb to userspace when the completion
|
||||
ast is read if the status is 0, the lock has an lvb and
|
||||
|
@ -204,11 +215,13 @@ void dlm_user_add_ast(struct dlm_lkb *lkb, int type)
|
|||
|
||||
spin_unlock(&proc->asts_spin);
|
||||
|
||||
if (remove_ownqueue) {
|
||||
if (eol) {
|
||||
spin_lock(&ua->proc->locks_spin);
|
||||
list_del_init(&lkb->lkb_ownqueue);
|
||||
if (!list_empty(&lkb->lkb_ownqueue)) {
|
||||
list_del_init(&lkb->lkb_ownqueue);
|
||||
dlm_put_lkb(lkb);
|
||||
}
|
||||
spin_unlock(&ua->proc->locks_spin);
|
||||
dlm_put_lkb(lkb);
|
||||
}
|
||||
out:
|
||||
mutex_unlock(&ls->ls_clear_proc_locks);
|
||||
|
@ -286,11 +299,50 @@ static int device_user_unlock(struct dlm_user_proc *proc,
|
|||
return error;
|
||||
}
|
||||
|
||||
static int create_misc_device(struct dlm_ls *ls, char *name)
|
||||
{
|
||||
int error, len;
|
||||
|
||||
error = -ENOMEM;
|
||||
len = strlen(name) + strlen(name_prefix) + 2;
|
||||
ls->ls_device.name = kzalloc(len, GFP_KERNEL);
|
||||
if (!ls->ls_device.name)
|
||||
goto fail;
|
||||
|
||||
snprintf((char *)ls->ls_device.name, len, "%s_%s", name_prefix,
|
||||
name);
|
||||
ls->ls_device.fops = &device_fops;
|
||||
ls->ls_device.minor = MISC_DYNAMIC_MINOR;
|
||||
|
||||
error = misc_register(&ls->ls_device);
|
||||
if (error) {
|
||||
kfree(ls->ls_device.name);
|
||||
}
|
||||
fail:
|
||||
return error;
|
||||
}
|
||||
|
||||
static int device_user_purge(struct dlm_user_proc *proc,
|
||||
struct dlm_purge_params *params)
|
||||
{
|
||||
struct dlm_ls *ls;
|
||||
int error;
|
||||
|
||||
ls = dlm_find_lockspace_local(proc->lockspace);
|
||||
if (!ls)
|
||||
return -ENOENT;
|
||||
|
||||
error = dlm_user_purge(ls, proc, params->nodeid, params->pid);
|
||||
|
||||
dlm_put_lockspace(ls);
|
||||
return error;
|
||||
}
|
||||
|
||||
static int device_create_lockspace(struct dlm_lspace_params *params)
|
||||
{
|
||||
dlm_lockspace_t *lockspace;
|
||||
struct dlm_ls *ls;
|
||||
int error, len;
|
||||
int error;
|
||||
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return -EPERM;
|
||||
|
@ -304,29 +356,14 @@ static int device_create_lockspace(struct dlm_lspace_params *params)
|
|||
if (!ls)
|
||||
return -ENOENT;
|
||||
|
||||
error = -ENOMEM;
|
||||
len = strlen(params->name) + strlen(name_prefix) + 2;
|
||||
ls->ls_device.name = kzalloc(len, GFP_KERNEL);
|
||||
if (!ls->ls_device.name)
|
||||
goto fail;
|
||||
snprintf((char *)ls->ls_device.name, len, "%s_%s", name_prefix,
|
||||
params->name);
|
||||
ls->ls_device.fops = &device_fops;
|
||||
ls->ls_device.minor = MISC_DYNAMIC_MINOR;
|
||||
|
||||
error = misc_register(&ls->ls_device);
|
||||
if (error) {
|
||||
kfree(ls->ls_device.name);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
error = ls->ls_device.minor;
|
||||
error = create_misc_device(ls, params->name);
|
||||
dlm_put_lockspace(ls);
|
||||
return error;
|
||||
|
||||
fail:
|
||||
dlm_put_lockspace(ls);
|
||||
dlm_release_lockspace(lockspace, 0);
|
||||
if (error)
|
||||
dlm_release_lockspace(lockspace, 0);
|
||||
else
|
||||
error = ls->ls_device.minor;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -343,6 +380,10 @@ static int device_remove_lockspace(struct dlm_lspace_params *params)
|
|||
if (!ls)
|
||||
return -ENOENT;
|
||||
|
||||
/* Deregister the misc device first, so we don't have
|
||||
* a device that's not attached to a lockspace. If
|
||||
* dlm_release_lockspace fails then we can recreate it
|
||||
*/
|
||||
error = misc_deregister(&ls->ls_device);
|
||||
if (error) {
|
||||
dlm_put_lockspace(ls);
|
||||
|
@ -361,6 +402,8 @@ static int device_remove_lockspace(struct dlm_lspace_params *params)
|
|||
|
||||
dlm_put_lockspace(ls);
|
||||
error = dlm_release_lockspace(lockspace, force);
|
||||
if (error)
|
||||
create_misc_device(ls, ls->ls_name);
|
||||
out:
|
||||
return error;
|
||||
}
|
||||
|
@ -497,6 +540,14 @@ static ssize_t device_write(struct file *file, const char __user *buf,
|
|||
error = device_remove_lockspace(&kbuf->i.lspace);
|
||||
break;
|
||||
|
||||
case DLM_USER_PURGE:
|
||||
if (!proc) {
|
||||
log_print("no locking on control device");
|
||||
goto out_sig;
|
||||
}
|
||||
error = device_user_purge(proc, &kbuf->i.purge);
|
||||
break;
|
||||
|
||||
default:
|
||||
log_print("Unknown command passed to DLM device : %d\n",
|
||||
kbuf->cmd);
|
||||
|
|
|
@ -1262,9 +1262,10 @@ static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque,
|
|||
u64 leaf_no)
|
||||
{
|
||||
struct gfs2_inode *ip = GFS2_I(inode);
|
||||
struct gfs2_sbd *sdp = GFS2_SB(inode);
|
||||
struct buffer_head *bh;
|
||||
struct gfs2_leaf *lf;
|
||||
unsigned entries = 0;
|
||||
unsigned entries = 0, entries2 = 0;
|
||||
unsigned leaves = 0;
|
||||
const struct gfs2_dirent **darr, *dent;
|
||||
struct dirent_gather g;
|
||||
|
@ -1290,7 +1291,13 @@ static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque,
|
|||
return 0;
|
||||
|
||||
error = -ENOMEM;
|
||||
larr = vmalloc((leaves + entries) * sizeof(void *));
|
||||
/*
|
||||
* The extra 99 entries are not normally used, but are a buffer
|
||||
* zone in case the number of entries in the leaf is corrupt.
|
||||
* 99 is the maximum number of entries that can fit in a single
|
||||
* leaf block.
|
||||
*/
|
||||
larr = vmalloc((leaves + entries + 99) * sizeof(void *));
|
||||
if (!larr)
|
||||
goto out;
|
||||
darr = (const struct gfs2_dirent **)(larr + leaves);
|
||||
|
@ -1305,10 +1312,20 @@ static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque,
|
|||
lf = (struct gfs2_leaf *)bh->b_data;
|
||||
lfn = be64_to_cpu(lf->lf_next);
|
||||
if (lf->lf_entries) {
|
||||
entries2 += be16_to_cpu(lf->lf_entries);
|
||||
dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size,
|
||||
gfs2_dirent_gather, NULL, &g);
|
||||
error = PTR_ERR(dent);
|
||||
if (IS_ERR(dent)) {
|
||||
if (IS_ERR(dent))
|
||||
goto out_kfree;
|
||||
if (entries2 != g.offset) {
|
||||
fs_warn(sdp, "Number of entries corrupt in dir "
|
||||
"leaf %llu, entries2 (%u) != "
|
||||
"g.offset (%u)\n",
|
||||
(unsigned long long)bh->b_blocknr,
|
||||
entries2, g.offset);
|
||||
|
||||
error = -EIO;
|
||||
goto out_kfree;
|
||||
}
|
||||
error = 0;
|
||||
|
@ -1318,6 +1335,7 @@ static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque,
|
|||
}
|
||||
} while(lfn);
|
||||
|
||||
BUG_ON(entries2 != entries);
|
||||
error = do_filldir_main(ip, offset, opaque, filldir, darr,
|
||||
entries, copied);
|
||||
out_kfree:
|
||||
|
@ -1401,6 +1419,7 @@ int gfs2_dir_read(struct inode *inode, u64 *offset, void *opaque,
|
|||
filldir_t filldir)
|
||||
{
|
||||
struct gfs2_inode *dip = GFS2_I(inode);
|
||||
struct gfs2_sbd *sdp = GFS2_SB(inode);
|
||||
struct dirent_gather g;
|
||||
const struct gfs2_dirent **darr, *dent;
|
||||
struct buffer_head *dibh;
|
||||
|
@ -1423,8 +1442,8 @@ int gfs2_dir_read(struct inode *inode, u64 *offset, void *opaque,
|
|||
return error;
|
||||
|
||||
error = -ENOMEM;
|
||||
darr = kmalloc(dip->i_di.di_entries * sizeof(struct gfs2_dirent *),
|
||||
GFP_KERNEL);
|
||||
/* 96 is max number of dirents which can be stuffed into an inode */
|
||||
darr = kmalloc(96 * sizeof(struct gfs2_dirent *), GFP_KERNEL);
|
||||
if (darr) {
|
||||
g.pdent = darr;
|
||||
g.offset = 0;
|
||||
|
@ -1434,6 +1453,15 @@ int gfs2_dir_read(struct inode *inode, u64 *offset, void *opaque,
|
|||
error = PTR_ERR(dent);
|
||||
goto out;
|
||||
}
|
||||
if (dip->i_di.di_entries != g.offset) {
|
||||
fs_warn(sdp, "Number of entries corrupt in dir %llu, "
|
||||
"ip->i_di.di_entries (%u) != g.offset (%u)\n",
|
||||
(unsigned long long)dip->i_num.no_addr,
|
||||
dip->i_di.di_entries,
|
||||
g.offset);
|
||||
error = -EIO;
|
||||
goto out;
|
||||
}
|
||||
error = do_filldir_main(dip, offset, opaque, filldir, darr,
|
||||
dip->i_di.di_entries, &copied);
|
||||
out:
|
||||
|
|
619
fs/gfs2/glock.c
619
fs/gfs2/glock.c
|
@ -23,6 +23,10 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/rwsem.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kallsyms.h>
|
||||
|
||||
#include "gfs2.h"
|
||||
#include "incore.h"
|
||||
|
@ -40,20 +44,30 @@ struct gfs2_gl_hash_bucket {
|
|||
struct hlist_head hb_list;
|
||||
};
|
||||
|
||||
struct glock_iter {
|
||||
int hash; /* hash bucket index */
|
||||
struct gfs2_sbd *sdp; /* incore superblock */
|
||||
struct gfs2_glock *gl; /* current glock struct */
|
||||
struct hlist_head *hb_list; /* current hash bucket ptr */
|
||||
struct seq_file *seq; /* sequence file for debugfs */
|
||||
char string[512]; /* scratch space */
|
||||
};
|
||||
|
||||
typedef void (*glock_examiner) (struct gfs2_glock * gl);
|
||||
|
||||
static int gfs2_dump_lockstate(struct gfs2_sbd *sdp);
|
||||
static int dump_glock(struct gfs2_glock *gl);
|
||||
static int dump_inode(struct gfs2_inode *ip);
|
||||
static void gfs2_glock_xmote_th(struct gfs2_holder *gh);
|
||||
static int dump_glock(struct glock_iter *gi, struct gfs2_glock *gl);
|
||||
static void gfs2_glock_xmote_th(struct gfs2_glock *gl, struct gfs2_holder *gh);
|
||||
static void gfs2_glock_drop_th(struct gfs2_glock *gl);
|
||||
static DECLARE_RWSEM(gfs2_umount_flush_sem);
|
||||
static struct dentry *gfs2_root;
|
||||
|
||||
#define GFS2_GL_HASH_SHIFT 15
|
||||
#define GFS2_GL_HASH_SIZE (1 << GFS2_GL_HASH_SHIFT)
|
||||
#define GFS2_GL_HASH_MASK (GFS2_GL_HASH_SIZE - 1)
|
||||
|
||||
static struct gfs2_gl_hash_bucket gl_hash_table[GFS2_GL_HASH_SIZE];
|
||||
static struct dentry *gfs2_root;
|
||||
|
||||
/*
|
||||
* Despite what you might think, the numbers below are not arbitrary :-)
|
||||
|
@ -202,7 +216,6 @@ int gfs2_glock_put(struct gfs2_glock *gl)
|
|||
gfs2_assert(sdp, list_empty(&gl->gl_reclaim));
|
||||
gfs2_assert(sdp, list_empty(&gl->gl_holders));
|
||||
gfs2_assert(sdp, list_empty(&gl->gl_waiters1));
|
||||
gfs2_assert(sdp, list_empty(&gl->gl_waiters2));
|
||||
gfs2_assert(sdp, list_empty(&gl->gl_waiters3));
|
||||
glock_free(gl);
|
||||
rv = 1;
|
||||
|
@ -303,7 +316,7 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number,
|
|||
atomic_set(&gl->gl_ref, 1);
|
||||
gl->gl_state = LM_ST_UNLOCKED;
|
||||
gl->gl_hash = hash;
|
||||
gl->gl_owner = NULL;
|
||||
gl->gl_owner_pid = 0;
|
||||
gl->gl_ip = 0;
|
||||
gl->gl_ops = glops;
|
||||
gl->gl_req_gh = NULL;
|
||||
|
@ -367,7 +380,7 @@ void gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, unsigned flags,
|
|||
INIT_LIST_HEAD(&gh->gh_list);
|
||||
gh->gh_gl = gl;
|
||||
gh->gh_ip = (unsigned long)__builtin_return_address(0);
|
||||
gh->gh_owner = current;
|
||||
gh->gh_owner_pid = current->pid;
|
||||
gh->gh_state = state;
|
||||
gh->gh_flags = flags;
|
||||
gh->gh_error = 0;
|
||||
|
@ -389,7 +402,7 @@ void gfs2_holder_reinit(unsigned int state, unsigned flags, struct gfs2_holder *
|
|||
{
|
||||
gh->gh_state = state;
|
||||
gh->gh_flags = flags;
|
||||
gh->gh_iflags &= 1 << HIF_ALLOCED;
|
||||
gh->gh_iflags = 0;
|
||||
gh->gh_ip = (unsigned long)__builtin_return_address(0);
|
||||
}
|
||||
|
||||
|
@ -406,54 +419,8 @@ void gfs2_holder_uninit(struct gfs2_holder *gh)
|
|||
gh->gh_ip = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* gfs2_holder_get - get a struct gfs2_holder structure
|
||||
* @gl: the glock
|
||||
* @state: the state we're requesting
|
||||
* @flags: the modifier flags
|
||||
* @gfp_flags:
|
||||
*
|
||||
* Figure out how big an impact this function has. Either:
|
||||
* 1) Replace it with a cache of structures hanging off the struct gfs2_sbd
|
||||
* 2) Leave it like it is
|
||||
*
|
||||
* Returns: the holder structure, NULL on ENOMEM
|
||||
*/
|
||||
|
||||
static struct gfs2_holder *gfs2_holder_get(struct gfs2_glock *gl,
|
||||
unsigned int state,
|
||||
int flags, gfp_t gfp_flags)
|
||||
static void gfs2_holder_wake(struct gfs2_holder *gh)
|
||||
{
|
||||
struct gfs2_holder *gh;
|
||||
|
||||
gh = kmalloc(sizeof(struct gfs2_holder), gfp_flags);
|
||||
if (!gh)
|
||||
return NULL;
|
||||
|
||||
gfs2_holder_init(gl, state, flags, gh);
|
||||
set_bit(HIF_ALLOCED, &gh->gh_iflags);
|
||||
gh->gh_ip = (unsigned long)__builtin_return_address(0);
|
||||
return gh;
|
||||
}
|
||||
|
||||
/**
|
||||
* gfs2_holder_put - get rid of a struct gfs2_holder structure
|
||||
* @gh: the holder structure
|
||||
*
|
||||
*/
|
||||
|
||||
static void gfs2_holder_put(struct gfs2_holder *gh)
|
||||
{
|
||||
gfs2_holder_uninit(gh);
|
||||
kfree(gh);
|
||||
}
|
||||
|
||||
static void gfs2_holder_dispose_or_wake(struct gfs2_holder *gh)
|
||||
{
|
||||
if (test_bit(HIF_DEALLOC, &gh->gh_iflags)) {
|
||||
gfs2_holder_put(gh);
|
||||
return;
|
||||
}
|
||||
clear_bit(HIF_WAIT, &gh->gh_iflags);
|
||||
smp_mb();
|
||||
wake_up_bit(&gh->gh_iflags, HIF_WAIT);
|
||||
|
@ -519,7 +486,7 @@ static int rq_promote(struct gfs2_holder *gh)
|
|||
gfs2_reclaim_glock(sdp);
|
||||
}
|
||||
|
||||
gfs2_glock_xmote_th(gh);
|
||||
gfs2_glock_xmote_th(gh->gh_gl, gh);
|
||||
spin_lock(&gl->gl_spin);
|
||||
}
|
||||
return 1;
|
||||
|
@ -542,7 +509,7 @@ static int rq_promote(struct gfs2_holder *gh)
|
|||
gh->gh_error = 0;
|
||||
set_bit(HIF_HOLDER, &gh->gh_iflags);
|
||||
|
||||
gfs2_holder_dispose_or_wake(gh);
|
||||
gfs2_holder_wake(gh);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -554,32 +521,24 @@ static int rq_promote(struct gfs2_holder *gh)
|
|||
* Returns: 1 if the queue is blocked
|
||||
*/
|
||||
|
||||
static int rq_demote(struct gfs2_holder *gh)
|
||||
static int rq_demote(struct gfs2_glock *gl)
|
||||
{
|
||||
struct gfs2_glock *gl = gh->gh_gl;
|
||||
|
||||
if (!list_empty(&gl->gl_holders))
|
||||
return 1;
|
||||
|
||||
if (gl->gl_state == gh->gh_state || gl->gl_state == LM_ST_UNLOCKED) {
|
||||
list_del_init(&gh->gh_list);
|
||||
gh->gh_error = 0;
|
||||
spin_unlock(&gl->gl_spin);
|
||||
gfs2_holder_dispose_or_wake(gh);
|
||||
spin_lock(&gl->gl_spin);
|
||||
} else {
|
||||
gl->gl_req_gh = gh;
|
||||
set_bit(GLF_LOCK, &gl->gl_flags);
|
||||
spin_unlock(&gl->gl_spin);
|
||||
|
||||
if (gh->gh_state == LM_ST_UNLOCKED ||
|
||||
gl->gl_state != LM_ST_EXCLUSIVE)
|
||||
gfs2_glock_drop_th(gl);
|
||||
else
|
||||
gfs2_glock_xmote_th(gh);
|
||||
|
||||
spin_lock(&gl->gl_spin);
|
||||
if (gl->gl_state == gl->gl_demote_state ||
|
||||
gl->gl_state == LM_ST_UNLOCKED) {
|
||||
clear_bit(GLF_DEMOTE, &gl->gl_flags);
|
||||
return 0;
|
||||
}
|
||||
set_bit(GLF_LOCK, &gl->gl_flags);
|
||||
spin_unlock(&gl->gl_spin);
|
||||
if (gl->gl_demote_state == LM_ST_UNLOCKED ||
|
||||
gl->gl_state != LM_ST_EXCLUSIVE)
|
||||
gfs2_glock_drop_th(gl);
|
||||
else
|
||||
gfs2_glock_xmote_th(gl, NULL);
|
||||
spin_lock(&gl->gl_spin);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -607,16 +566,8 @@ static void run_queue(struct gfs2_glock *gl)
|
|||
else
|
||||
gfs2_assert_warn(gl->gl_sbd, 0);
|
||||
|
||||
} else if (!list_empty(&gl->gl_waiters2) &&
|
||||
!test_bit(GLF_SKIP_WAITERS2, &gl->gl_flags)) {
|
||||
gh = list_entry(gl->gl_waiters2.next,
|
||||
struct gfs2_holder, gh_list);
|
||||
|
||||
if (test_bit(HIF_DEMOTE, &gh->gh_iflags))
|
||||
blocked = rq_demote(gh);
|
||||
else
|
||||
gfs2_assert_warn(gl->gl_sbd, 0);
|
||||
|
||||
} else if (test_bit(GLF_DEMOTE, &gl->gl_flags)) {
|
||||
blocked = rq_demote(gl);
|
||||
} else if (!list_empty(&gl->gl_waiters3)) {
|
||||
gh = list_entry(gl->gl_waiters3.next,
|
||||
struct gfs2_holder, gh_list);
|
||||
|
@ -654,7 +605,7 @@ static void gfs2_glmutex_lock(struct gfs2_glock *gl)
|
|||
if (test_and_set_bit(GLF_LOCK, &gl->gl_flags)) {
|
||||
list_add_tail(&gh.gh_list, &gl->gl_waiters1);
|
||||
} else {
|
||||
gl->gl_owner = current;
|
||||
gl->gl_owner_pid = current->pid;
|
||||
gl->gl_ip = (unsigned long)__builtin_return_address(0);
|
||||
clear_bit(HIF_WAIT, &gh.gh_iflags);
|
||||
smp_mb();
|
||||
|
@ -681,7 +632,7 @@ static int gfs2_glmutex_trylock(struct gfs2_glock *gl)
|
|||
if (test_and_set_bit(GLF_LOCK, &gl->gl_flags)) {
|
||||
acquired = 0;
|
||||
} else {
|
||||
gl->gl_owner = current;
|
||||
gl->gl_owner_pid = current->pid;
|
||||
gl->gl_ip = (unsigned long)__builtin_return_address(0);
|
||||
}
|
||||
spin_unlock(&gl->gl_spin);
|
||||
|
@ -699,7 +650,7 @@ static void gfs2_glmutex_unlock(struct gfs2_glock *gl)
|
|||
{
|
||||
spin_lock(&gl->gl_spin);
|
||||
clear_bit(GLF_LOCK, &gl->gl_flags);
|
||||
gl->gl_owner = NULL;
|
||||
gl->gl_owner_pid = 0;
|
||||
gl->gl_ip = 0;
|
||||
run_queue(gl);
|
||||
BUG_ON(!spin_is_locked(&gl->gl_spin));
|
||||
|
@ -707,50 +658,24 @@ static void gfs2_glmutex_unlock(struct gfs2_glock *gl)
|
|||
}
|
||||
|
||||
/**
|
||||
* handle_callback - add a demote request to a lock's queue
|
||||
* handle_callback - process a demote request
|
||||
* @gl: the glock
|
||||
* @state: the state the caller wants us to change to
|
||||
*
|
||||
* Note: This may fail sliently if we are out of memory.
|
||||
* There are only two requests that we are going to see in actual
|
||||
* practise: LM_ST_SHARED and LM_ST_UNLOCKED
|
||||
*/
|
||||
|
||||
static void handle_callback(struct gfs2_glock *gl, unsigned int state)
|
||||
{
|
||||
struct gfs2_holder *gh, *new_gh = NULL;
|
||||
|
||||
restart:
|
||||
spin_lock(&gl->gl_spin);
|
||||
|
||||
list_for_each_entry(gh, &gl->gl_waiters2, gh_list) {
|
||||
if (test_bit(HIF_DEMOTE, &gh->gh_iflags) &&
|
||||
gl->gl_req_gh != gh) {
|
||||
if (gh->gh_state != state)
|
||||
gh->gh_state = LM_ST_UNLOCKED;
|
||||
goto out;
|
||||
}
|
||||
if (test_and_set_bit(GLF_DEMOTE, &gl->gl_flags) == 0) {
|
||||
gl->gl_demote_state = state;
|
||||
gl->gl_demote_time = jiffies;
|
||||
} else if (gl->gl_demote_state != LM_ST_UNLOCKED) {
|
||||
gl->gl_demote_state = state;
|
||||
}
|
||||
|
||||
if (new_gh) {
|
||||
list_add_tail(&new_gh->gh_list, &gl->gl_waiters2);
|
||||
new_gh = NULL;
|
||||
} else {
|
||||
spin_unlock(&gl->gl_spin);
|
||||
|
||||
new_gh = gfs2_holder_get(gl, state, LM_FLAG_TRY, GFP_NOFS);
|
||||
if (!new_gh)
|
||||
return;
|
||||
set_bit(HIF_DEMOTE, &new_gh->gh_iflags);
|
||||
set_bit(HIF_DEALLOC, &new_gh->gh_iflags);
|
||||
set_bit(HIF_WAIT, &new_gh->gh_iflags);
|
||||
|
||||
goto restart;
|
||||
}
|
||||
|
||||
out:
|
||||
spin_unlock(&gl->gl_spin);
|
||||
|
||||
if (new_gh)
|
||||
gfs2_holder_put(new_gh);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -810,56 +735,37 @@ static void xmote_bh(struct gfs2_glock *gl, unsigned int ret)
|
|||
|
||||
/* Deal with each possible exit condition */
|
||||
|
||||
if (!gh)
|
||||
if (!gh) {
|
||||
gl->gl_stamp = jiffies;
|
||||
else if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) {
|
||||
if (ret & LM_OUT_CANCELED)
|
||||
op_done = 0;
|
||||
else
|
||||
clear_bit(GLF_DEMOTE, &gl->gl_flags);
|
||||
} else {
|
||||
spin_lock(&gl->gl_spin);
|
||||
list_del_init(&gh->gh_list);
|
||||
gh->gh_error = -EIO;
|
||||
spin_unlock(&gl->gl_spin);
|
||||
} else if (test_bit(HIF_DEMOTE, &gh->gh_iflags)) {
|
||||
spin_lock(&gl->gl_spin);
|
||||
list_del_init(&gh->gh_list);
|
||||
if (gl->gl_state == gh->gh_state ||
|
||||
gl->gl_state == LM_ST_UNLOCKED) {
|
||||
gh->gh_error = 0;
|
||||
} else {
|
||||
if (gfs2_assert_warn(sdp, gh->gh_flags &
|
||||
(LM_FLAG_TRY | LM_FLAG_TRY_1CB)) == -1)
|
||||
fs_warn(sdp, "ret = 0x%.8X\n", ret);
|
||||
gh->gh_error = GLR_TRYFAILED;
|
||||
}
|
||||
spin_unlock(&gl->gl_spin);
|
||||
|
||||
if (ret & LM_OUT_CANCELED)
|
||||
handle_callback(gl, LM_ST_UNLOCKED);
|
||||
|
||||
} else if (ret & LM_OUT_CANCELED) {
|
||||
spin_lock(&gl->gl_spin);
|
||||
list_del_init(&gh->gh_list);
|
||||
if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
|
||||
goto out;
|
||||
gh->gh_error = GLR_CANCELED;
|
||||
spin_unlock(&gl->gl_spin);
|
||||
|
||||
} else if (relaxed_state_ok(gl->gl_state, gh->gh_state, gh->gh_flags)) {
|
||||
spin_lock(&gl->gl_spin);
|
||||
list_move_tail(&gh->gh_list, &gl->gl_holders);
|
||||
gh->gh_error = 0;
|
||||
set_bit(HIF_HOLDER, &gh->gh_iflags);
|
||||
spin_unlock(&gl->gl_spin);
|
||||
|
||||
set_bit(HIF_FIRST, &gh->gh_iflags);
|
||||
|
||||
op_done = 0;
|
||||
|
||||
} else if (gh->gh_flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB)) {
|
||||
spin_lock(&gl->gl_spin);
|
||||
list_del_init(&gh->gh_list);
|
||||
if (ret & LM_OUT_CANCELED)
|
||||
goto out;
|
||||
if (relaxed_state_ok(gl->gl_state, gh->gh_state, gh->gh_flags)) {
|
||||
list_add_tail(&gh->gh_list, &gl->gl_holders);
|
||||
gh->gh_error = 0;
|
||||
set_bit(HIF_HOLDER, &gh->gh_iflags);
|
||||
set_bit(HIF_FIRST, &gh->gh_iflags);
|
||||
op_done = 0;
|
||||
goto out;
|
||||
}
|
||||
gh->gh_error = GLR_TRYFAILED;
|
||||
spin_unlock(&gl->gl_spin);
|
||||
|
||||
} else {
|
||||
if (gh->gh_flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB))
|
||||
goto out;
|
||||
gh->gh_error = -EINVAL;
|
||||
if (gfs2_assert_withdraw(sdp, 0) == -1)
|
||||
fs_err(sdp, "ret = 0x%.8X\n", ret);
|
||||
out:
|
||||
spin_unlock(&gl->gl_spin);
|
||||
}
|
||||
|
||||
if (glops->go_xmote_bh)
|
||||
|
@ -877,7 +783,7 @@ static void xmote_bh(struct gfs2_glock *gl, unsigned int ret)
|
|||
gfs2_glock_put(gl);
|
||||
|
||||
if (gh)
|
||||
gfs2_holder_dispose_or_wake(gh);
|
||||
gfs2_holder_wake(gh);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -888,12 +794,11 @@ static void xmote_bh(struct gfs2_glock *gl, unsigned int ret)
|
|||
*
|
||||
*/
|
||||
|
||||
void gfs2_glock_xmote_th(struct gfs2_holder *gh)
|
||||
void gfs2_glock_xmote_th(struct gfs2_glock *gl, struct gfs2_holder *gh)
|
||||
{
|
||||
struct gfs2_glock *gl = gh->gh_gl;
|
||||
struct gfs2_sbd *sdp = gl->gl_sbd;
|
||||
int flags = gh->gh_flags;
|
||||
unsigned state = gh->gh_state;
|
||||
int flags = gh ? gh->gh_flags : 0;
|
||||
unsigned state = gh ? gh->gh_state : gl->gl_demote_state;
|
||||
const struct gfs2_glock_operations *glops = gl->gl_ops;
|
||||
int lck_flags = flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB |
|
||||
LM_FLAG_NOEXP | LM_FLAG_ANY |
|
||||
|
@ -943,6 +848,7 @@ static void drop_bh(struct gfs2_glock *gl, unsigned int ret)
|
|||
gfs2_assert_warn(sdp, !ret);
|
||||
|
||||
state_change(gl, LM_ST_UNLOCKED);
|
||||
clear_bit(GLF_DEMOTE, &gl->gl_flags);
|
||||
|
||||
if (glops->go_inval)
|
||||
glops->go_inval(gl, DIO_METADATA);
|
||||
|
@ -964,7 +870,7 @@ static void drop_bh(struct gfs2_glock *gl, unsigned int ret)
|
|||
gfs2_glock_put(gl);
|
||||
|
||||
if (gh)
|
||||
gfs2_holder_dispose_or_wake(gh);
|
||||
gfs2_holder_wake(gh);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1097,18 +1003,32 @@ static int glock_wait_internal(struct gfs2_holder *gh)
|
|||
}
|
||||
|
||||
static inline struct gfs2_holder *
|
||||
find_holder_by_owner(struct list_head *head, struct task_struct *owner)
|
||||
find_holder_by_owner(struct list_head *head, pid_t pid)
|
||||
{
|
||||
struct gfs2_holder *gh;
|
||||
|
||||
list_for_each_entry(gh, head, gh_list) {
|
||||
if (gh->gh_owner == owner)
|
||||
if (gh->gh_owner_pid == pid)
|
||||
return gh;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void print_dbg(struct glock_iter *gi, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
if (gi) {
|
||||
vsprintf(gi->string, fmt, args);
|
||||
seq_printf(gi->seq, gi->string);
|
||||
}
|
||||
else
|
||||
vprintk(fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/**
|
||||
* add_to_queue - Add a holder to the wait queue (but look for recursion)
|
||||
* @gh: the holder structure to add
|
||||
|
@ -1120,24 +1040,24 @@ static void add_to_queue(struct gfs2_holder *gh)
|
|||
struct gfs2_glock *gl = gh->gh_gl;
|
||||
struct gfs2_holder *existing;
|
||||
|
||||
BUG_ON(!gh->gh_owner);
|
||||
BUG_ON(!gh->gh_owner_pid);
|
||||
if (test_and_set_bit(HIF_WAIT, &gh->gh_iflags))
|
||||
BUG();
|
||||
|
||||
existing = find_holder_by_owner(&gl->gl_holders, gh->gh_owner);
|
||||
existing = find_holder_by_owner(&gl->gl_holders, gh->gh_owner_pid);
|
||||
if (existing) {
|
||||
print_symbol(KERN_WARNING "original: %s\n", existing->gh_ip);
|
||||
printk(KERN_INFO "pid : %d\n", existing->gh_owner->pid);
|
||||
printk(KERN_INFO "pid : %d\n", existing->gh_owner_pid);
|
||||
printk(KERN_INFO "lock type : %d lock state : %d\n",
|
||||
existing->gh_gl->gl_name.ln_type, existing->gh_gl->gl_state);
|
||||
print_symbol(KERN_WARNING "new: %s\n", gh->gh_ip);
|
||||
printk(KERN_INFO "pid : %d\n", gh->gh_owner->pid);
|
||||
printk(KERN_INFO "pid : %d\n", gh->gh_owner_pid);
|
||||
printk(KERN_INFO "lock type : %d lock state : %d\n",
|
||||
gl->gl_name.ln_type, gl->gl_state);
|
||||
BUG();
|
||||
}
|
||||
|
||||
existing = find_holder_by_owner(&gl->gl_waiters3, gh->gh_owner);
|
||||
existing = find_holder_by_owner(&gl->gl_waiters3, gh->gh_owner_pid);
|
||||
if (existing) {
|
||||
print_symbol(KERN_WARNING "original: %s\n", existing->gh_ip);
|
||||
print_symbol(KERN_WARNING "new: %s\n", gh->gh_ip);
|
||||
|
@ -1267,9 +1187,8 @@ void gfs2_glock_dq(struct gfs2_holder *gh)
|
|||
if (glops->go_unlock)
|
||||
glops->go_unlock(gh);
|
||||
|
||||
gl->gl_stamp = jiffies;
|
||||
|
||||
spin_lock(&gl->gl_spin);
|
||||
gl->gl_stamp = jiffies;
|
||||
}
|
||||
|
||||
clear_bit(GLF_LOCK, &gl->gl_flags);
|
||||
|
@ -1841,6 +1760,15 @@ void gfs2_gl_hash_clear(struct gfs2_sbd *sdp, int wait)
|
|||
* Diagnostic routines to help debug distributed deadlock
|
||||
*/
|
||||
|
||||
static void gfs2_print_symbol(struct glock_iter *gi, const char *fmt,
|
||||
unsigned long address)
|
||||
{
|
||||
char buffer[KSYM_SYMBOL_LEN];
|
||||
|
||||
sprint_symbol(buffer, address);
|
||||
print_dbg(gi, fmt, buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* dump_holder - print information about a glock holder
|
||||
* @str: a string naming the type of holder
|
||||
|
@ -1849,31 +1777,37 @@ void gfs2_gl_hash_clear(struct gfs2_sbd *sdp, int wait)
|
|||
* Returns: 0 on success, -ENOBUFS when we run out of space
|
||||
*/
|
||||
|
||||
static int dump_holder(char *str, struct gfs2_holder *gh)
|
||||
static int dump_holder(struct glock_iter *gi, char *str,
|
||||
struct gfs2_holder *gh)
|
||||
{
|
||||
unsigned int x;
|
||||
int error = -ENOBUFS;
|
||||
struct task_struct *gh_owner;
|
||||
|
||||
printk(KERN_INFO " %s\n", str);
|
||||
printk(KERN_INFO " owner = %ld\n",
|
||||
(gh->gh_owner) ? (long)gh->gh_owner->pid : -1);
|
||||
printk(KERN_INFO " gh_state = %u\n", gh->gh_state);
|
||||
printk(KERN_INFO " gh_flags =");
|
||||
print_dbg(gi, " %s\n", str);
|
||||
if (gh->gh_owner_pid) {
|
||||
print_dbg(gi, " owner = %ld ", (long)gh->gh_owner_pid);
|
||||
gh_owner = find_task_by_pid(gh->gh_owner_pid);
|
||||
if (gh_owner)
|
||||
print_dbg(gi, "(%s)\n", gh_owner->comm);
|
||||
else
|
||||
print_dbg(gi, "(ended)\n");
|
||||
} else
|
||||
print_dbg(gi, " owner = -1\n");
|
||||
print_dbg(gi, " gh_state = %u\n", gh->gh_state);
|
||||
print_dbg(gi, " gh_flags =");
|
||||
for (x = 0; x < 32; x++)
|
||||
if (gh->gh_flags & (1 << x))
|
||||
printk(" %u", x);
|
||||
printk(" \n");
|
||||
printk(KERN_INFO " error = %d\n", gh->gh_error);
|
||||
printk(KERN_INFO " gh_iflags =");
|
||||
print_dbg(gi, " %u", x);
|
||||
print_dbg(gi, " \n");
|
||||
print_dbg(gi, " error = %d\n", gh->gh_error);
|
||||
print_dbg(gi, " gh_iflags =");
|
||||
for (x = 0; x < 32; x++)
|
||||
if (test_bit(x, &gh->gh_iflags))
|
||||
printk(" %u", x);
|
||||
printk(" \n");
|
||||
print_symbol(KERN_INFO " initialized at: %s\n", gh->gh_ip);
|
||||
print_dbg(gi, " %u", x);
|
||||
print_dbg(gi, " \n");
|
||||
gfs2_print_symbol(gi, " initialized at: %s\n", gh->gh_ip);
|
||||
|
||||
error = 0;
|
||||
|
||||
return error;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1883,25 +1817,20 @@ static int dump_holder(char *str, struct gfs2_holder *gh)
|
|||
* Returns: 0 on success, -ENOBUFS when we run out of space
|
||||
*/
|
||||
|
||||
static int dump_inode(struct gfs2_inode *ip)
|
||||
static int dump_inode(struct glock_iter *gi, struct gfs2_inode *ip)
|
||||
{
|
||||
unsigned int x;
|
||||
int error = -ENOBUFS;
|
||||
|
||||
printk(KERN_INFO " Inode:\n");
|
||||
printk(KERN_INFO " num = %llu %llu\n",
|
||||
(unsigned long long)ip->i_num.no_formal_ino,
|
||||
(unsigned long long)ip->i_num.no_addr);
|
||||
printk(KERN_INFO " type = %u\n", IF2DT(ip->i_inode.i_mode));
|
||||
printk(KERN_INFO " i_flags =");
|
||||
print_dbg(gi, " Inode:\n");
|
||||
print_dbg(gi, " num = %llu/%llu\n",
|
||||
ip->i_num.no_formal_ino, ip->i_num.no_addr);
|
||||
print_dbg(gi, " type = %u\n", IF2DT(ip->i_inode.i_mode));
|
||||
print_dbg(gi, " i_flags =");
|
||||
for (x = 0; x < 32; x++)
|
||||
if (test_bit(x, &ip->i_flags))
|
||||
printk(" %u", x);
|
||||
printk(" \n");
|
||||
|
||||
error = 0;
|
||||
|
||||
return error;
|
||||
print_dbg(gi, " %u", x);
|
||||
print_dbg(gi, " \n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1912,74 +1841,86 @@ static int dump_inode(struct gfs2_inode *ip)
|
|||
* Returns: 0 on success, -ENOBUFS when we run out of space
|
||||
*/
|
||||
|
||||
static int dump_glock(struct gfs2_glock *gl)
|
||||
static int dump_glock(struct glock_iter *gi, struct gfs2_glock *gl)
|
||||
{
|
||||
struct gfs2_holder *gh;
|
||||
unsigned int x;
|
||||
int error = -ENOBUFS;
|
||||
struct task_struct *gl_owner;
|
||||
|
||||
spin_lock(&gl->gl_spin);
|
||||
|
||||
printk(KERN_INFO "Glock 0x%p (%u, %llu)\n", gl, gl->gl_name.ln_type,
|
||||
(unsigned long long)gl->gl_name.ln_number);
|
||||
printk(KERN_INFO " gl_flags =");
|
||||
print_dbg(gi, "Glock 0x%p (%u, %llu)\n", gl, gl->gl_name.ln_type,
|
||||
(unsigned long long)gl->gl_name.ln_number);
|
||||
print_dbg(gi, " gl_flags =");
|
||||
for (x = 0; x < 32; x++) {
|
||||
if (test_bit(x, &gl->gl_flags))
|
||||
printk(" %u", x);
|
||||
print_dbg(gi, " %u", x);
|
||||
}
|
||||
printk(" \n");
|
||||
printk(KERN_INFO " gl_ref = %d\n", atomic_read(&gl->gl_ref));
|
||||
printk(KERN_INFO " gl_state = %u\n", gl->gl_state);
|
||||
printk(KERN_INFO " gl_owner = %s\n", gl->gl_owner->comm);
|
||||
print_symbol(KERN_INFO " gl_ip = %s\n", gl->gl_ip);
|
||||
printk(KERN_INFO " req_gh = %s\n", (gl->gl_req_gh) ? "yes" : "no");
|
||||
printk(KERN_INFO " req_bh = %s\n", (gl->gl_req_bh) ? "yes" : "no");
|
||||
printk(KERN_INFO " lvb_count = %d\n", atomic_read(&gl->gl_lvb_count));
|
||||
printk(KERN_INFO " object = %s\n", (gl->gl_object) ? "yes" : "no");
|
||||
printk(KERN_INFO " le = %s\n",
|
||||
if (!test_bit(GLF_LOCK, &gl->gl_flags))
|
||||
print_dbg(gi, " (unlocked)");
|
||||
print_dbg(gi, " \n");
|
||||
print_dbg(gi, " gl_ref = %d\n", atomic_read(&gl->gl_ref));
|
||||
print_dbg(gi, " gl_state = %u\n", gl->gl_state);
|
||||
if (gl->gl_owner_pid) {
|
||||
gl_owner = find_task_by_pid(gl->gl_owner_pid);
|
||||
if (gl_owner)
|
||||
print_dbg(gi, " gl_owner = pid %d (%s)\n",
|
||||
gl->gl_owner_pid, gl_owner->comm);
|
||||
else
|
||||
print_dbg(gi, " gl_owner = %d (ended)\n",
|
||||
gl->gl_owner_pid);
|
||||
} else
|
||||
print_dbg(gi, " gl_owner = -1\n");
|
||||
print_dbg(gi, " gl_ip = %lu\n", gl->gl_ip);
|
||||
print_dbg(gi, " req_gh = %s\n", (gl->gl_req_gh) ? "yes" : "no");
|
||||
print_dbg(gi, " req_bh = %s\n", (gl->gl_req_bh) ? "yes" : "no");
|
||||
print_dbg(gi, " lvb_count = %d\n", atomic_read(&gl->gl_lvb_count));
|
||||
print_dbg(gi, " object = %s\n", (gl->gl_object) ? "yes" : "no");
|
||||
print_dbg(gi, " le = %s\n",
|
||||
(list_empty(&gl->gl_le.le_list)) ? "no" : "yes");
|
||||
printk(KERN_INFO " reclaim = %s\n",
|
||||
(list_empty(&gl->gl_reclaim)) ? "no" : "yes");
|
||||
print_dbg(gi, " reclaim = %s\n",
|
||||
(list_empty(&gl->gl_reclaim)) ? "no" : "yes");
|
||||
if (gl->gl_aspace)
|
||||
printk(KERN_INFO " aspace = 0x%p nrpages = %lu\n", gl->gl_aspace,
|
||||
gl->gl_aspace->i_mapping->nrpages);
|
||||
print_dbg(gi, " aspace = 0x%p nrpages = %lu\n", gl->gl_aspace,
|
||||
gl->gl_aspace->i_mapping->nrpages);
|
||||
else
|
||||
printk(KERN_INFO " aspace = no\n");
|
||||
printk(KERN_INFO " ail = %d\n", atomic_read(&gl->gl_ail_count));
|
||||
print_dbg(gi, " aspace = no\n");
|
||||
print_dbg(gi, " ail = %d\n", atomic_read(&gl->gl_ail_count));
|
||||
if (gl->gl_req_gh) {
|
||||
error = dump_holder("Request", gl->gl_req_gh);
|
||||
error = dump_holder(gi, "Request", gl->gl_req_gh);
|
||||
if (error)
|
||||
goto out;
|
||||
}
|
||||
list_for_each_entry(gh, &gl->gl_holders, gh_list) {
|
||||
error = dump_holder("Holder", gh);
|
||||
error = dump_holder(gi, "Holder", gh);
|
||||
if (error)
|
||||
goto out;
|
||||
}
|
||||
list_for_each_entry(gh, &gl->gl_waiters1, gh_list) {
|
||||
error = dump_holder("Waiter1", gh);
|
||||
if (error)
|
||||
goto out;
|
||||
}
|
||||
list_for_each_entry(gh, &gl->gl_waiters2, gh_list) {
|
||||
error = dump_holder("Waiter2", gh);
|
||||
error = dump_holder(gi, "Waiter1", gh);
|
||||
if (error)
|
||||
goto out;
|
||||
}
|
||||
list_for_each_entry(gh, &gl->gl_waiters3, gh_list) {
|
||||
error = dump_holder("Waiter3", gh);
|
||||
error = dump_holder(gi, "Waiter3", gh);
|
||||
if (error)
|
||||
goto out;
|
||||
}
|
||||
if (test_bit(GLF_DEMOTE, &gl->gl_flags)) {
|
||||
print_dbg(gi, " Demotion req to state %u (%llu uS ago)\n",
|
||||
gl->gl_demote_state,
|
||||
(u64)(jiffies - gl->gl_demote_time)*(1000000/HZ));
|
||||
}
|
||||
if (gl->gl_ops == &gfs2_inode_glops && gl->gl_object) {
|
||||
if (!test_bit(GLF_LOCK, &gl->gl_flags) &&
|
||||
list_empty(&gl->gl_holders)) {
|
||||
error = dump_inode(gl->gl_object);
|
||||
list_empty(&gl->gl_holders)) {
|
||||
error = dump_inode(gi, gl->gl_object);
|
||||
if (error)
|
||||
goto out;
|
||||
} else {
|
||||
error = -ENOBUFS;
|
||||
printk(KERN_INFO " Inode: busy\n");
|
||||
print_dbg(gi, " Inode: busy\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2014,7 +1955,7 @@ static int gfs2_dump_lockstate(struct gfs2_sbd *sdp)
|
|||
if (gl->gl_sbd != sdp)
|
||||
continue;
|
||||
|
||||
error = dump_glock(gl);
|
||||
error = dump_glock(NULL, gl);
|
||||
if (error)
|
||||
break;
|
||||
}
|
||||
|
@ -2043,3 +1984,189 @@ int __init gfs2_glock_init(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int gfs2_glock_iter_next(struct glock_iter *gi)
|
||||
{
|
||||
read_lock(gl_lock_addr(gi->hash));
|
||||
while (1) {
|
||||
if (!gi->hb_list) { /* If we don't have a hash bucket yet */
|
||||
gi->hb_list = &gl_hash_table[gi->hash].hb_list;
|
||||
if (hlist_empty(gi->hb_list)) {
|
||||
read_unlock(gl_lock_addr(gi->hash));
|
||||
gi->hash++;
|
||||
read_lock(gl_lock_addr(gi->hash));
|
||||
gi->hb_list = NULL;
|
||||
if (gi->hash >= GFS2_GL_HASH_SIZE) {
|
||||
read_unlock(gl_lock_addr(gi->hash));
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
continue;
|
||||
}
|
||||
if (!hlist_empty(gi->hb_list)) {
|
||||
gi->gl = list_entry(gi->hb_list->first,
|
||||
struct gfs2_glock,
|
||||
gl_list);
|
||||
}
|
||||
} else {
|
||||
if (gi->gl->gl_list.next == NULL) {
|
||||
read_unlock(gl_lock_addr(gi->hash));
|
||||
gi->hash++;
|
||||
read_lock(gl_lock_addr(gi->hash));
|
||||
gi->hb_list = NULL;
|
||||
continue;
|
||||
}
|
||||
gi->gl = list_entry(gi->gl->gl_list.next,
|
||||
struct gfs2_glock, gl_list);
|
||||
}
|
||||
if (gi->gl)
|
||||
break;
|
||||
}
|
||||
read_unlock(gl_lock_addr(gi->hash));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gfs2_glock_iter_free(struct glock_iter *gi)
|
||||
{
|
||||
kfree(gi);
|
||||
}
|
||||
|
||||
static struct glock_iter *gfs2_glock_iter_init(struct gfs2_sbd *sdp)
|
||||
{
|
||||
struct glock_iter *gi;
|
||||
|
||||
gi = kmalloc(sizeof (*gi), GFP_KERNEL);
|
||||
if (!gi)
|
||||
return NULL;
|
||||
|
||||
gi->sdp = sdp;
|
||||
gi->hash = 0;
|
||||
gi->gl = NULL;
|
||||
gi->hb_list = NULL;
|
||||
gi->seq = NULL;
|
||||
memset(gi->string, 0, sizeof(gi->string));
|
||||
|
||||
if (gfs2_glock_iter_next(gi)) {
|
||||
gfs2_glock_iter_free(gi);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return gi;
|
||||
}
|
||||
|
||||
static void *gfs2_glock_seq_start(struct seq_file *file, loff_t *pos)
|
||||
{
|
||||
struct glock_iter *gi;
|
||||
loff_t n = *pos;
|
||||
|
||||
gi = gfs2_glock_iter_init(file->private);
|
||||
if (!gi)
|
||||
return NULL;
|
||||
|
||||
while (n--) {
|
||||
if (gfs2_glock_iter_next(gi)) {
|
||||
gfs2_glock_iter_free(gi);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return gi;
|
||||
}
|
||||
|
||||
static void *gfs2_glock_seq_next(struct seq_file *file, void *iter_ptr,
|
||||
loff_t *pos)
|
||||
{
|
||||
struct glock_iter *gi = iter_ptr;
|
||||
|
||||
(*pos)++;
|
||||
|
||||
if (gfs2_glock_iter_next(gi)) {
|
||||
gfs2_glock_iter_free(gi);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return gi;
|
||||
}
|
||||
|
||||
static void gfs2_glock_seq_stop(struct seq_file *file, void *iter_ptr)
|
||||
{
|
||||
/* nothing for now */
|
||||
}
|
||||
|
||||
static int gfs2_glock_seq_show(struct seq_file *file, void *iter_ptr)
|
||||
{
|
||||
struct glock_iter *gi = iter_ptr;
|
||||
|
||||
gi->seq = file;
|
||||
dump_glock(gi, gi->gl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct seq_operations gfs2_glock_seq_ops = {
|
||||
.start = gfs2_glock_seq_start,
|
||||
.next = gfs2_glock_seq_next,
|
||||
.stop = gfs2_glock_seq_stop,
|
||||
.show = gfs2_glock_seq_show,
|
||||
};
|
||||
|
||||
static int gfs2_debugfs_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct seq_file *seq;
|
||||
int ret;
|
||||
|
||||
ret = seq_open(file, &gfs2_glock_seq_ops);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
seq = file->private_data;
|
||||
seq->private = inode->i_private;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct file_operations gfs2_debug_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = gfs2_debugfs_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = seq_release
|
||||
};
|
||||
|
||||
int gfs2_create_debugfs_file(struct gfs2_sbd *sdp)
|
||||
{
|
||||
sdp->debugfs_dir = debugfs_create_dir(sdp->sd_table_name, gfs2_root);
|
||||
if (!sdp->debugfs_dir)
|
||||
return -ENOMEM;
|
||||
sdp->debugfs_dentry_glocks = debugfs_create_file("glocks",
|
||||
S_IFREG | S_IRUGO,
|
||||
sdp->debugfs_dir, sdp,
|
||||
&gfs2_debug_fops);
|
||||
if (!sdp->debugfs_dentry_glocks)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void gfs2_delete_debugfs_file(struct gfs2_sbd *sdp)
|
||||
{
|
||||
if (sdp && sdp->debugfs_dir) {
|
||||
if (sdp->debugfs_dentry_glocks) {
|
||||
debugfs_remove(sdp->debugfs_dentry_glocks);
|
||||
sdp->debugfs_dentry_glocks = NULL;
|
||||
}
|
||||
debugfs_remove(sdp->debugfs_dir);
|
||||
sdp->debugfs_dir = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int gfs2_register_debugfs(void)
|
||||
{
|
||||
gfs2_root = debugfs_create_dir("gfs2", NULL);
|
||||
return gfs2_root ? 0 : -ENOMEM;
|
||||
}
|
||||
|
||||
void gfs2_unregister_debugfs(void)
|
||||
{
|
||||
debugfs_remove(gfs2_root);
|
||||
gfs2_root = NULL;
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ static inline int gfs2_glock_is_locked_by_me(struct gfs2_glock *gl)
|
|||
/* Look in glock's list of holders for one with current task as owner */
|
||||
spin_lock(&gl->gl_spin);
|
||||
list_for_each_entry(gh, &gl->gl_holders, gh_list) {
|
||||
if (gh->gh_owner == current) {
|
||||
if (gh->gh_owner_pid == current->pid) {
|
||||
locked = 1;
|
||||
break;
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ static inline int gfs2_glock_is_blocking(struct gfs2_glock *gl)
|
|||
{
|
||||
int ret;
|
||||
spin_lock(&gl->gl_spin);
|
||||
ret = !list_empty(&gl->gl_waiters2) || !list_empty(&gl->gl_waiters3);
|
||||
ret = test_bit(GLF_DEMOTE, &gl->gl_flags) || !list_empty(&gl->gl_waiters3);
|
||||
spin_unlock(&gl->gl_spin);
|
||||
return ret;
|
||||
}
|
||||
|
@ -135,5 +135,9 @@ void gfs2_scand_internal(struct gfs2_sbd *sdp);
|
|||
void gfs2_gl_hash_clear(struct gfs2_sbd *sdp, int wait);
|
||||
|
||||
int __init gfs2_glock_init(void);
|
||||
int gfs2_create_debugfs_file(struct gfs2_sbd *sdp);
|
||||
void gfs2_delete_debugfs_file(struct gfs2_sbd *sdp);
|
||||
int gfs2_register_debugfs(void);
|
||||
void gfs2_unregister_debugfs(void);
|
||||
|
||||
#endif /* __GLOCK_DOT_H__ */
|
||||
|
|
|
@ -115,11 +115,8 @@ enum {
|
|||
/* Actions */
|
||||
HIF_MUTEX = 0,
|
||||
HIF_PROMOTE = 1,
|
||||
HIF_DEMOTE = 2,
|
||||
|
||||
/* States */
|
||||
HIF_ALLOCED = 4,
|
||||
HIF_DEALLOC = 5,
|
||||
HIF_HOLDER = 6,
|
||||
HIF_FIRST = 7,
|
||||
HIF_ABORTED = 9,
|
||||
|
@ -130,7 +127,7 @@ struct gfs2_holder {
|
|||
struct list_head gh_list;
|
||||
|
||||
struct gfs2_glock *gh_gl;
|
||||
struct task_struct *gh_owner;
|
||||
pid_t gh_owner_pid;
|
||||
unsigned int gh_state;
|
||||
unsigned gh_flags;
|
||||
|
||||
|
@ -142,8 +139,8 @@ struct gfs2_holder {
|
|||
enum {
|
||||
GLF_LOCK = 1,
|
||||
GLF_STICKY = 2,
|
||||
GLF_DEMOTE = 3,
|
||||
GLF_DIRTY = 5,
|
||||
GLF_SKIP_WAITERS2 = 6,
|
||||
};
|
||||
|
||||
struct gfs2_glock {
|
||||
|
@ -156,11 +153,12 @@ struct gfs2_glock {
|
|||
|
||||
unsigned int gl_state;
|
||||
unsigned int gl_hash;
|
||||
struct task_struct *gl_owner;
|
||||
unsigned int gl_demote_state; /* state requested by remote node */
|
||||
unsigned long gl_demote_time; /* time of first demote request */
|
||||
pid_t gl_owner_pid;
|
||||
unsigned long gl_ip;
|
||||
struct list_head gl_holders;
|
||||
struct list_head gl_waiters1; /* HIF_MUTEX */
|
||||
struct list_head gl_waiters2; /* HIF_DEMOTE */
|
||||
struct list_head gl_waiters3; /* HIF_PROMOTE */
|
||||
|
||||
const struct gfs2_glock_operations *gl_ops;
|
||||
|
@ -611,6 +609,8 @@ struct gfs2_sbd {
|
|||
|
||||
unsigned long sd_last_warning;
|
||||
struct vfsmount *sd_gfs2mnt;
|
||||
struct dentry *debugfs_dir; /* debugfs directory */
|
||||
struct dentry *debugfs_dentry_glocks; /* for debugfs */
|
||||
};
|
||||
|
||||
#endif /* __INCORE_DOT_H__ */
|
||||
|
|
|
@ -151,7 +151,7 @@ static inline unsigned int make_flags(struct gdlm_lock *lp,
|
|||
|
||||
/* make_strname - convert GFS lock numbers to a string */
|
||||
|
||||
static inline void make_strname(struct lm_lockname *lockname,
|
||||
static inline void make_strname(const struct lm_lockname *lockname,
|
||||
struct gdlm_strname *str)
|
||||
{
|
||||
sprintf(str->name, "%8x%16llx", lockname->ln_type,
|
||||
|
@ -169,6 +169,7 @@ static int gdlm_create_lp(struct gdlm_ls *ls, struct lm_lockname *name,
|
|||
return -ENOMEM;
|
||||
|
||||
lp->lockname = *name;
|
||||
make_strname(name, &lp->strname);
|
||||
lp->ls = ls;
|
||||
lp->cur = DLM_LOCK_IV;
|
||||
lp->lvb = NULL;
|
||||
|
@ -227,7 +228,6 @@ void gdlm_put_lock(void *lock)
|
|||
unsigned int gdlm_do_lock(struct gdlm_lock *lp)
|
||||
{
|
||||
struct gdlm_ls *ls = lp->ls;
|
||||
struct gdlm_strname str;
|
||||
int error, bast = 1;
|
||||
|
||||
/*
|
||||
|
@ -249,8 +249,6 @@ unsigned int gdlm_do_lock(struct gdlm_lock *lp)
|
|||
if (test_bit(LFL_NOBAST, &lp->flags))
|
||||
bast = 0;
|
||||
|
||||
make_strname(&lp->lockname, &str);
|
||||
|
||||
set_bit(LFL_ACTIVE, &lp->flags);
|
||||
|
||||
log_debug("lk %x,%llx id %x %d,%d %x", lp->lockname.ln_type,
|
||||
|
@ -258,8 +256,8 @@ unsigned int gdlm_do_lock(struct gdlm_lock *lp)
|
|||
lp->cur, lp->req, lp->lkf);
|
||||
|
||||
error = dlm_lock(ls->dlm_lockspace, lp->req, &lp->lksb, lp->lkf,
|
||||
str.name, str.namelen, 0, gdlm_ast, lp,
|
||||
bast ? gdlm_bast : NULL);
|
||||
lp->strname.name, lp->strname.namelen, 0, gdlm_ast,
|
||||
lp, bast ? gdlm_bast : NULL);
|
||||
|
||||
if ((error == -EAGAIN) && (lp->lkf & DLM_LKF_NOQUEUE)) {
|
||||
lp->lksb.sb_status = -EAGAIN;
|
||||
|
@ -268,7 +266,7 @@ unsigned int gdlm_do_lock(struct gdlm_lock *lp)
|
|||
}
|
||||
|
||||
if (error) {
|
||||
log_debug("%s: gdlm_lock %x,%llx err=%d cur=%d req=%d lkf=%x "
|
||||
log_error("%s: gdlm_lock %x,%llx err=%d cur=%d req=%d lkf=%x "
|
||||
"flags=%lx", ls->fsname, lp->lockname.ln_type,
|
||||
(unsigned long long)lp->lockname.ln_number, error,
|
||||
lp->cur, lp->req, lp->lkf, lp->flags);
|
||||
|
@ -296,7 +294,7 @@ static unsigned int gdlm_do_unlock(struct gdlm_lock *lp)
|
|||
error = dlm_unlock(ls->dlm_lockspace, lp->lksb.sb_lkid, lkf, NULL, lp);
|
||||
|
||||
if (error) {
|
||||
log_debug("%s: gdlm_unlock %x,%llx err=%d cur=%d req=%d lkf=%x "
|
||||
log_error("%s: gdlm_unlock %x,%llx err=%d cur=%d req=%d lkf=%x "
|
||||
"flags=%lx", ls->fsname, lp->lockname.ln_type,
|
||||
(unsigned long long)lp->lockname.ln_number, error,
|
||||
lp->cur, lp->req, lp->lkf, lp->flags);
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
|
||||
#define GDLM_STRNAME_BYTES 24
|
||||
#define GDLM_LVB_SIZE 32
|
||||
#define GDLM_DROP_COUNT 200000
|
||||
#define GDLM_DROP_COUNT 0
|
||||
#define GDLM_DROP_PERIOD 60
|
||||
#define GDLM_NAME_LEN 128
|
||||
|
||||
|
@ -106,6 +106,7 @@ enum {
|
|||
struct gdlm_lock {
|
||||
struct gdlm_ls *ls;
|
||||
struct lm_lockname lockname;
|
||||
struct gdlm_strname strname;
|
||||
char *lvb;
|
||||
struct dlm_lksb lksb;
|
||||
|
||||
|
|
|
@ -33,16 +33,17 @@ static void glock_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
|
|||
|
||||
tr->tr_touched = 1;
|
||||
|
||||
if (!list_empty(&le->le_list))
|
||||
return;
|
||||
|
||||
gl = container_of(le, struct gfs2_glock, gl_le);
|
||||
if (gfs2_assert_withdraw(sdp, gfs2_glock_is_held_excl(gl)))
|
||||
return;
|
||||
gfs2_glock_hold(gl);
|
||||
set_bit(GLF_DIRTY, &gl->gl_flags);
|
||||
|
||||
gfs2_log_lock(sdp);
|
||||
if (!list_empty(&le->le_list)){
|
||||
gfs2_log_unlock(sdp);
|
||||
return;
|
||||
}
|
||||
gfs2_glock_hold(gl);
|
||||
set_bit(GLF_DIRTY, &gl->gl_flags);
|
||||
sdp->sd_log_num_gl++;
|
||||
list_add(&le->le_list, &sdp->sd_log_le_gl);
|
||||
gfs2_log_unlock(sdp);
|
||||
|
@ -415,13 +416,14 @@ static void rg_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
|
|||
|
||||
tr->tr_touched = 1;
|
||||
|
||||
if (!list_empty(&le->le_list))
|
||||
return;
|
||||
|
||||
rgd = container_of(le, struct gfs2_rgrpd, rd_le);
|
||||
gfs2_rgrp_bh_hold(rgd);
|
||||
|
||||
gfs2_log_lock(sdp);
|
||||
if (!list_empty(&le->le_list)){
|
||||
gfs2_log_unlock(sdp);
|
||||
return;
|
||||
}
|
||||
gfs2_rgrp_bh_hold(rgd);
|
||||
sdp->sd_log_num_rg++;
|
||||
list_add(&le->le_list, &sdp->sd_log_le_rg);
|
||||
gfs2_log_unlock(sdp);
|
||||
|
|
|
@ -43,7 +43,6 @@ static void gfs2_init_glock_once(void *foo, struct kmem_cache *cachep, unsigned
|
|||
spin_lock_init(&gl->gl_spin);
|
||||
INIT_LIST_HEAD(&gl->gl_holders);
|
||||
INIT_LIST_HEAD(&gl->gl_waiters1);
|
||||
INIT_LIST_HEAD(&gl->gl_waiters2);
|
||||
INIT_LIST_HEAD(&gl->gl_waiters3);
|
||||
gl->gl_lvb = NULL;
|
||||
atomic_set(&gl->gl_lvb_count, 0);
|
||||
|
@ -101,6 +100,8 @@ static int __init init_gfs2_fs(void)
|
|||
if (error)
|
||||
goto fail_unregister;
|
||||
|
||||
gfs2_register_debugfs();
|
||||
|
||||
printk("GFS2 (built %s %s) installed\n", __DATE__, __TIME__);
|
||||
|
||||
return 0;
|
||||
|
@ -128,6 +129,7 @@ fail:
|
|||
|
||||
static void __exit exit_gfs2_fs(void)
|
||||
{
|
||||
gfs2_unregister_debugfs();
|
||||
unregister_filesystem(&gfs2_fs_type);
|
||||
unregister_filesystem(&gfs2meta_fs_type);
|
||||
|
||||
|
|
245
fs/gfs2/mount.c
245
fs/gfs2/mount.c
|
@ -13,6 +13,7 @@
|
|||
#include <linux/buffer_head.h>
|
||||
#include <linux/gfs2_ondisk.h>
|
||||
#include <linux/lm_interface.h>
|
||||
#include <linux/parser.h>
|
||||
|
||||
#include "gfs2.h"
|
||||
#include "incore.h"
|
||||
|
@ -20,6 +21,52 @@
|
|||
#include "sys.h"
|
||||
#include "util.h"
|
||||
|
||||
enum {
|
||||
Opt_lockproto,
|
||||
Opt_locktable,
|
||||
Opt_hostdata,
|
||||
Opt_spectator,
|
||||
Opt_ignore_local_fs,
|
||||
Opt_localflocks,
|
||||
Opt_localcaching,
|
||||
Opt_debug,
|
||||
Opt_nodebug,
|
||||
Opt_upgrade,
|
||||
Opt_num_glockd,
|
||||
Opt_acl,
|
||||
Opt_noacl,
|
||||
Opt_quota_off,
|
||||
Opt_quota_account,
|
||||
Opt_quota_on,
|
||||
Opt_suiddir,
|
||||
Opt_nosuiddir,
|
||||
Opt_data_writeback,
|
||||
Opt_data_ordered,
|
||||
};
|
||||
|
||||
static match_table_t tokens = {
|
||||
{Opt_lockproto, "lockproto=%s"},
|
||||
{Opt_locktable, "locktable=%s"},
|
||||
{Opt_hostdata, "hostdata=%s"},
|
||||
{Opt_spectator, "spectator"},
|
||||
{Opt_ignore_local_fs, "ignore_local_fs"},
|
||||
{Opt_localflocks, "localflocks"},
|
||||
{Opt_localcaching, "localcaching"},
|
||||
{Opt_debug, "debug"},
|
||||
{Opt_nodebug, "nodebug"},
|
||||
{Opt_upgrade, "upgrade"},
|
||||
{Opt_num_glockd, "num_glockd=%d"},
|
||||
{Opt_acl, "acl"},
|
||||
{Opt_noacl, "noacl"},
|
||||
{Opt_quota_off, "quota=off"},
|
||||
{Opt_quota_account, "quota=account"},
|
||||
{Opt_quota_on, "quota=on"},
|
||||
{Opt_suiddir, "suiddir"},
|
||||
{Opt_nosuiddir, "nosuiddir"},
|
||||
{Opt_data_writeback, "data=writeback"},
|
||||
{Opt_data_ordered, "data=ordered"}
|
||||
};
|
||||
|
||||
/**
|
||||
* gfs2_mount_args - Parse mount options
|
||||
* @sdp:
|
||||
|
@ -54,146 +101,150 @@ int gfs2_mount_args(struct gfs2_sbd *sdp, char *data_arg, int remount)
|
|||
process them */
|
||||
|
||||
for (options = data; (o = strsep(&options, ",")); ) {
|
||||
int token, option;
|
||||
substring_t tmp[MAX_OPT_ARGS];
|
||||
|
||||
if (!*o)
|
||||
continue;
|
||||
|
||||
v = strchr(o, '=');
|
||||
if (v)
|
||||
*v++ = 0;
|
||||
token = match_token(o, tokens, tmp);
|
||||
switch (token) {
|
||||
case Opt_lockproto:
|
||||
v = match_strdup(&tmp[0]);
|
||||
if (!v) {
|
||||
fs_info(sdp, "no memory for lockproto\n");
|
||||
error = -ENOMEM;
|
||||
goto out_error;
|
||||
}
|
||||
|
||||
if (!strcmp(o, "lockproto")) {
|
||||
if (!v)
|
||||
goto need_value;
|
||||
if (remount && strcmp(v, args->ar_lockproto))
|
||||
if (remount && strcmp(v, args->ar_lockproto)) {
|
||||
kfree(v);
|
||||
goto cant_remount;
|
||||
}
|
||||
|
||||
strncpy(args->ar_lockproto, v, GFS2_LOCKNAME_LEN);
|
||||
args->ar_lockproto[GFS2_LOCKNAME_LEN - 1] = 0;
|
||||
}
|
||||
kfree(v);
|
||||
break;
|
||||
case Opt_locktable:
|
||||
v = match_strdup(&tmp[0]);
|
||||
if (!v) {
|
||||
fs_info(sdp, "no memory for locktable\n");
|
||||
error = -ENOMEM;
|
||||
goto out_error;
|
||||
}
|
||||
|
||||
else if (!strcmp(o, "locktable")) {
|
||||
if (!v)
|
||||
goto need_value;
|
||||
if (remount && strcmp(v, args->ar_locktable))
|
||||
if (remount && strcmp(v, args->ar_locktable)) {
|
||||
kfree(v);
|
||||
goto cant_remount;
|
||||
}
|
||||
|
||||
strncpy(args->ar_locktable, v, GFS2_LOCKNAME_LEN);
|
||||
args->ar_locktable[GFS2_LOCKNAME_LEN - 1] = 0;
|
||||
}
|
||||
args->ar_locktable[GFS2_LOCKNAME_LEN - 1] = 0;
|
||||
kfree(v);
|
||||
break;
|
||||
case Opt_hostdata:
|
||||
v = match_strdup(&tmp[0]);
|
||||
if (!v) {
|
||||
fs_info(sdp, "no memory for hostdata\n");
|
||||
error = -ENOMEM;
|
||||
goto out_error;
|
||||
}
|
||||
|
||||
else if (!strcmp(o, "hostdata")) {
|
||||
if (!v)
|
||||
goto need_value;
|
||||
if (remount && strcmp(v, args->ar_hostdata))
|
||||
if (remount && strcmp(v, args->ar_hostdata)) {
|
||||
kfree(v);
|
||||
goto cant_remount;
|
||||
}
|
||||
|
||||
strncpy(args->ar_hostdata, v, GFS2_LOCKNAME_LEN);
|
||||
args->ar_hostdata[GFS2_LOCKNAME_LEN - 1] = 0;
|
||||
}
|
||||
|
||||
else if (!strcmp(o, "spectator")) {
|
||||
kfree(v);
|
||||
break;
|
||||
case Opt_spectator:
|
||||
if (remount && !args->ar_spectator)
|
||||
goto cant_remount;
|
||||
args->ar_spectator = 1;
|
||||
sdp->sd_vfs->s_flags |= MS_RDONLY;
|
||||
}
|
||||
|
||||
else if (!strcmp(o, "ignore_local_fs")) {
|
||||
break;
|
||||
case Opt_ignore_local_fs:
|
||||
if (remount && !args->ar_ignore_local_fs)
|
||||
goto cant_remount;
|
||||
args->ar_ignore_local_fs = 1;
|
||||
}
|
||||
|
||||
else if (!strcmp(o, "localflocks")) {
|
||||
break;
|
||||
case Opt_localflocks:
|
||||
if (remount && !args->ar_localflocks)
|
||||
goto cant_remount;
|
||||
args->ar_localflocks = 1;
|
||||
}
|
||||
|
||||
else if (!strcmp(o, "localcaching")) {
|
||||
break;
|
||||
case Opt_localcaching:
|
||||
if (remount && !args->ar_localcaching)
|
||||
goto cant_remount;
|
||||
args->ar_localcaching = 1;
|
||||
}
|
||||
|
||||
else if (!strcmp(o, "debug"))
|
||||
break;
|
||||
case Opt_debug:
|
||||
args->ar_debug = 1;
|
||||
|
||||
else if (!strcmp(o, "nodebug"))
|
||||
break;
|
||||
case Opt_nodebug:
|
||||
args->ar_debug = 0;
|
||||
|
||||
else if (!strcmp(o, "upgrade")) {
|
||||
break;
|
||||
case Opt_upgrade:
|
||||
if (remount && !args->ar_upgrade)
|
||||
goto cant_remount;
|
||||
args->ar_upgrade = 1;
|
||||
}
|
||||
|
||||
else if (!strcmp(o, "num_glockd")) {
|
||||
unsigned int x;
|
||||
if (!v)
|
||||
goto need_value;
|
||||
sscanf(v, "%u", &x);
|
||||
if (remount && x != args->ar_num_glockd)
|
||||
goto cant_remount;
|
||||
if (!x || x > GFS2_GLOCKD_MAX) {
|
||||
fs_info(sdp, "0 < num_glockd <= %u (not %u)\n",
|
||||
GFS2_GLOCKD_MAX, x);
|
||||
error = -EINVAL;
|
||||
break;
|
||||
break;
|
||||
case Opt_num_glockd:
|
||||
if ((error = match_int(&tmp[0], &option))) {
|
||||
fs_info(sdp, "problem getting num_glockd\n");
|
||||
goto out_error;
|
||||
}
|
||||
args->ar_num_glockd = x;
|
||||
}
|
||||
|
||||
else if (!strcmp(o, "acl")) {
|
||||
if (remount && option != args->ar_num_glockd)
|
||||
goto cant_remount;
|
||||
if (!option || option > GFS2_GLOCKD_MAX) {
|
||||
fs_info(sdp, "0 < num_glockd <= %u (not %u)\n",
|
||||
GFS2_GLOCKD_MAX, option);
|
||||
error = -EINVAL;
|
||||
goto out_error;
|
||||
}
|
||||
args->ar_num_glockd = option;
|
||||
break;
|
||||
case Opt_acl:
|
||||
args->ar_posix_acl = 1;
|
||||
sdp->sd_vfs->s_flags |= MS_POSIXACL;
|
||||
}
|
||||
|
||||
else if (!strcmp(o, "noacl")) {
|
||||
break;
|
||||
case Opt_noacl:
|
||||
args->ar_posix_acl = 0;
|
||||
sdp->sd_vfs->s_flags &= ~MS_POSIXACL;
|
||||
}
|
||||
|
||||
else if (!strcmp(o, "quota")) {
|
||||
if (!v)
|
||||
goto need_value;
|
||||
if (!strcmp(v, "off"))
|
||||
args->ar_quota = GFS2_QUOTA_OFF;
|
||||
else if (!strcmp(v, "account"))
|
||||
args->ar_quota = GFS2_QUOTA_ACCOUNT;
|
||||
else if (!strcmp(v, "on"))
|
||||
args->ar_quota = GFS2_QUOTA_ON;
|
||||
else {
|
||||
fs_info(sdp, "invalid value for quota\n");
|
||||
error = -EINVAL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
else if (!strcmp(o, "suiddir"))
|
||||
break;
|
||||
case Opt_quota_off:
|
||||
args->ar_quota = GFS2_QUOTA_OFF;
|
||||
break;
|
||||
case Opt_quota_account:
|
||||
args->ar_quota = GFS2_QUOTA_ACCOUNT;
|
||||
break;
|
||||
case Opt_quota_on:
|
||||
args->ar_quota = GFS2_QUOTA_ON;
|
||||
break;
|
||||
case Opt_suiddir:
|
||||
args->ar_suiddir = 1;
|
||||
|
||||
else if (!strcmp(o, "nosuiddir"))
|
||||
break;
|
||||
case Opt_nosuiddir:
|
||||
args->ar_suiddir = 0;
|
||||
|
||||
else if (!strcmp(o, "data")) {
|
||||
if (!v)
|
||||
goto need_value;
|
||||
if (!strcmp(v, "writeback"))
|
||||
args->ar_data = GFS2_DATA_WRITEBACK;
|
||||
else if (!strcmp(v, "ordered"))
|
||||
args->ar_data = GFS2_DATA_ORDERED;
|
||||
else {
|
||||
fs_info(sdp, "invalid value for data\n");
|
||||
error = -EINVAL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
break;
|
||||
case Opt_data_writeback:
|
||||
args->ar_data = GFS2_DATA_WRITEBACK;
|
||||
break;
|
||||
case Opt_data_ordered:
|
||||
args->ar_data = GFS2_DATA_ORDERED;
|
||||
break;
|
||||
default:
|
||||
fs_info(sdp, "unknown option: %s\n", o);
|
||||
error = -EINVAL;
|
||||
break;
|
||||
goto out_error;
|
||||
}
|
||||
}
|
||||
|
||||
out_error:
|
||||
if (error)
|
||||
fs_info(sdp, "invalid mount option(s)\n");
|
||||
|
||||
|
@ -202,10 +253,6 @@ int gfs2_mount_args(struct gfs2_sbd *sdp, char *data_arg, int remount)
|
|||
|
||||
return error;
|
||||
|
||||
need_value:
|
||||
fs_info(sdp, "need value for option %s\n", o);
|
||||
return -EINVAL;
|
||||
|
||||
cant_remount:
|
||||
fs_info(sdp, "can't remount with option %s\n", o);
|
||||
return -EINVAL;
|
||||
|
|
|
@ -197,7 +197,19 @@ static int stuffed_readpage(struct gfs2_inode *ip, struct page *page)
|
|||
void *kaddr;
|
||||
int error;
|
||||
|
||||
BUG_ON(page->index);
|
||||
/*
|
||||
* Due to the order of unstuffing files and ->nopage(), we can be
|
||||
* asked for a zero page in the case of a stuffed file being extended,
|
||||
* so we need to supply one here. It doesn't happen often.
|
||||
*/
|
||||
if (unlikely(page->index)) {
|
||||
kaddr = kmap_atomic(page, KM_USER0);
|
||||
memset(kaddr, 0, PAGE_CACHE_SIZE);
|
||||
kunmap_atomic(kaddr, KM_USER0);
|
||||
flush_dcache_page(page);
|
||||
SetPageUptodate(page);
|
||||
return 0;
|
||||
}
|
||||
|
||||
error = gfs2_meta_inode_buffer(ip, &dibh);
|
||||
if (error)
|
||||
|
@ -208,9 +220,8 @@ static int stuffed_readpage(struct gfs2_inode *ip, struct page *page)
|
|||
ip->i_di.di_size);
|
||||
memset(kaddr + ip->i_di.di_size, 0, PAGE_CACHE_SIZE - ip->i_di.di_size);
|
||||
kunmap_atomic(kaddr, KM_USER0);
|
||||
|
||||
flush_dcache_page(page);
|
||||
brelse(dibh);
|
||||
|
||||
SetPageUptodate(page);
|
||||
|
||||
return 0;
|
||||
|
@ -507,7 +518,9 @@ static int gfs2_commit_write(struct file *file, struct page *page,
|
|||
gfs2_quota_unlock(ip);
|
||||
gfs2_alloc_put(ip);
|
||||
}
|
||||
unlock_page(page);
|
||||
gfs2_glock_dq_m(1, &ip->i_gh);
|
||||
lock_page(page);
|
||||
gfs2_holder_uninit(&ip->i_gh);
|
||||
return 0;
|
||||
|
||||
|
@ -520,7 +533,9 @@ fail_endtrans:
|
|||
gfs2_quota_unlock(ip);
|
||||
gfs2_alloc_put(ip);
|
||||
}
|
||||
unlock_page(page);
|
||||
gfs2_glock_dq_m(1, &ip->i_gh);
|
||||
lock_page(page);
|
||||
gfs2_holder_uninit(&ip->i_gh);
|
||||
fail_nounlock:
|
||||
ClearPageUptodate(page);
|
||||
|
|
|
@ -690,6 +690,8 @@ static int fill_super(struct super_block *sb, void *data, int silent)
|
|||
if (error)
|
||||
goto fail;
|
||||
|
||||
gfs2_create_debugfs_file(sdp);
|
||||
|
||||
error = gfs2_sys_fs_add(sdp);
|
||||
if (error)
|
||||
goto fail;
|
||||
|
@ -754,6 +756,7 @@ fail_lm:
|
|||
fail_sys:
|
||||
gfs2_sys_fs_del(sdp);
|
||||
fail:
|
||||
gfs2_delete_debugfs_file(sdp);
|
||||
kfree(sdp);
|
||||
sb->s_fs_info = NULL;
|
||||
return error;
|
||||
|
@ -896,6 +899,7 @@ error:
|
|||
|
||||
static void gfs2_kill_sb(struct super_block *sb)
|
||||
{
|
||||
gfs2_delete_debugfs_file(sb->s_fs_info);
|
||||
kill_block_super(sb);
|
||||
}
|
||||
|
||||
|
|
|
@ -283,6 +283,31 @@ static int gfs2_remount_fs(struct super_block *sb, int *flags, char *data)
|
|||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* gfs2_drop_inode - Drop an inode (test for remote unlink)
|
||||
* @inode: The inode to drop
|
||||
*
|
||||
* If we've received a callback on an iopen lock then its because a
|
||||
* remote node tried to deallocate the inode but failed due to this node
|
||||
* still having the inode open. Here we mark the link count zero
|
||||
* since we know that it must have reached zero if the GLF_DEMOTE flag
|
||||
* is set on the iopen glock. If we didn't do a disk read since the
|
||||
* remote node removed the final link then we might otherwise miss
|
||||
* this event. This check ensures that this node will deallocate the
|
||||
* inode's blocks, or alternatively pass the baton on to another
|
||||
* node for later deallocation.
|
||||
*/
|
||||
static void gfs2_drop_inode(struct inode *inode)
|
||||
{
|
||||
if (inode->i_private && inode->i_nlink) {
|
||||
struct gfs2_inode *ip = GFS2_I(inode);
|
||||
struct gfs2_glock *gl = ip->i_iopen_gh.gh_gl;
|
||||
if (gl && test_bit(GLF_DEMOTE, &gl->gl_flags))
|
||||
clear_nlink(inode);
|
||||
}
|
||||
generic_drop_inode(inode);
|
||||
}
|
||||
|
||||
/**
|
||||
* gfs2_clear_inode - Deallocate an inode when VFS is done with it
|
||||
* @inode: The VFS inode
|
||||
|
@ -441,7 +466,7 @@ out_unlock:
|
|||
out_uninit:
|
||||
gfs2_holder_uninit(&ip->i_iopen_gh);
|
||||
gfs2_glock_dq_uninit(&gh);
|
||||
if (error)
|
||||
if (error && error != GLR_TRYFAILED)
|
||||
fs_warn(sdp, "gfs2_delete_inode: %d\n", error);
|
||||
out:
|
||||
truncate_inode_pages(&inode->i_data, 0);
|
||||
|
@ -481,6 +506,7 @@ const struct super_operations gfs2_super_ops = {
|
|||
.statfs = gfs2_statfs,
|
||||
.remount_fs = gfs2_remount_fs,
|
||||
.clear_inode = gfs2_clear_inode,
|
||||
.drop_inode = gfs2_drop_inode,
|
||||
.show_options = gfs2_show_options,
|
||||
};
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "trans.h"
|
||||
#include "ops_file.h"
|
||||
#include "util.h"
|
||||
#include "log.h"
|
||||
|
||||
#define BFITNOENT ((u32)~0)
|
||||
|
||||
|
@ -697,8 +698,6 @@ struct gfs2_alloc *gfs2_alloc_get(struct gfs2_inode *ip)
|
|||
* @al: the struct gfs2_alloc structure describing the reservation
|
||||
*
|
||||
* If there's room for the requested blocks to be allocated from the RG:
|
||||
* Sets the $al_reserved_data field in @al.
|
||||
* Sets the $al_reserved_meta field in @al.
|
||||
* Sets the $al_rgd field in @al.
|
||||
*
|
||||
* Returns: 1 on success (it fits), 0 on failure (it doesn't fit)
|
||||
|
@ -709,6 +708,9 @@ static int try_rgrp_fit(struct gfs2_rgrpd *rgd, struct gfs2_alloc *al)
|
|||
struct gfs2_sbd *sdp = rgd->rd_sbd;
|
||||
int ret = 0;
|
||||
|
||||
if (rgd->rd_rg.rg_flags & GFS2_RGF_NOALLOC)
|
||||
return 0;
|
||||
|
||||
spin_lock(&sdp->sd_rindex_spin);
|
||||
if (rgd->rd_free_clone >= al->al_requested) {
|
||||
al->al_rgd = rgd;
|
||||
|
@ -941,9 +943,13 @@ static int get_local_rgrp(struct gfs2_inode *ip)
|
|||
rgd = gfs2_rgrpd_get_first(sdp);
|
||||
|
||||
if (rgd == begin) {
|
||||
if (++loops >= 2 || !skipped)
|
||||
if (++loops >= 3)
|
||||
return -ENOSPC;
|
||||
if (!skipped)
|
||||
loops++;
|
||||
flags = 0;
|
||||
if (loops == 2)
|
||||
gfs2_log_flush(sdp, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
/* Version of the device interface */
|
||||
#define DLM_DEVICE_VERSION_MAJOR 5
|
||||
#define DLM_DEVICE_VERSION_MINOR 0
|
||||
#define DLM_DEVICE_VERSION_MINOR 1
|
||||
#define DLM_DEVICE_VERSION_PATCH 0
|
||||
|
||||
/* struct passed to the lock write */
|
||||
|
@ -44,6 +44,11 @@ struct dlm_lspace_params {
|
|||
char name[0];
|
||||
};
|
||||
|
||||
struct dlm_purge_params {
|
||||
__u32 nodeid;
|
||||
__u32 pid;
|
||||
};
|
||||
|
||||
struct dlm_write_request {
|
||||
__u32 version[3];
|
||||
__u8 cmd;
|
||||
|
@ -53,6 +58,7 @@ struct dlm_write_request {
|
|||
union {
|
||||
struct dlm_lock_params lock;
|
||||
struct dlm_lspace_params lspace;
|
||||
struct dlm_purge_params purge;
|
||||
} i;
|
||||
};
|
||||
|
||||
|
@ -76,6 +82,7 @@ struct dlm_lock_result {
|
|||
#define DLM_USER_QUERY 3
|
||||
#define DLM_USER_CREATE_LOCKSPACE 4
|
||||
#define DLM_USER_REMOVE_LOCKSPACE 5
|
||||
#define DLM_USER_PURGE 6
|
||||
|
||||
/* Arbitrary length restriction */
|
||||
#define MAX_LS_NAME_LEN 64
|
||||
|
|
Loading…
Reference in New Issue