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
	
	Block a user