| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 1 | /* | 
 | 2 |  * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved. | 
| Steven Whitehouse | 3a8a9a1 | 2006-05-18 15:09:15 -0400 | [diff] [blame] | 3 |  * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved. | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 4 |  * | 
 | 5 |  * This copyrighted material is made available to anyone wishing to use, | 
 | 6 |  * modify, copy, or redistribute it subject to the terms and conditions | 
| Steven Whitehouse | e9fc2aa | 2006-09-01 11:05:15 -0400 | [diff] [blame] | 7 |  * of the GNU General Public License version 2. | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 8 |  */ | 
 | 9 |  | 
 | 10 | #include <linux/module.h> | 
 | 11 | #include <linux/init.h> | 
 | 12 | #include <linux/string.h> | 
 | 13 | #include <linux/slab.h> | 
 | 14 | #include <linux/wait.h> | 
 | 15 | #include <linux/sched.h> | 
 | 16 | #include <linux/kmod.h> | 
 | 17 | #include <linux/fs.h> | 
 | 18 | #include <linux/delay.h> | 
| Fabio Massimo Di Nitto | 7d30859 | 2006-09-19 07:56:29 +0200 | [diff] [blame] | 19 | #include <linux/lm_interface.h> | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 20 |  | 
 | 21 | struct lmh_wrapper { | 
 | 22 | 	struct list_head lw_list; | 
| Steven Whitehouse | 9b47c11 | 2006-09-08 10:17:58 -0400 | [diff] [blame] | 23 | 	const struct lm_lockops *lw_ops; | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 24 | }; | 
 | 25 |  | 
 | 26 | /* List of registered low-level locking protocols.  A file system selects one | 
 | 27 |    of them by name at mount time, e.g. lock_nolock, lock_dlm. */ | 
 | 28 |  | 
| Steven Whitehouse | 5029996 | 2006-09-04 09:49:55 -0400 | [diff] [blame] | 29 | static LIST_HEAD(lmh_list); | 
 | 30 | static DEFINE_MUTEX(lmh_lock); | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 31 |  | 
 | 32 | /** | 
| Steven Whitehouse | 2b557f6 | 2006-08-07 11:12:30 -0400 | [diff] [blame] | 33 |  * gfs2_register_lockproto - Register a low-level locking protocol | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 34 |  * @proto: the protocol definition | 
 | 35 |  * | 
 | 36 |  * Returns: 0 on success, -EXXX on failure | 
 | 37 |  */ | 
 | 38 |  | 
| Steven Whitehouse | 9b47c11 | 2006-09-08 10:17:58 -0400 | [diff] [blame] | 39 | int gfs2_register_lockproto(const struct lm_lockops *proto) | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 40 | { | 
 | 41 | 	struct lmh_wrapper *lw; | 
 | 42 |  | 
| Steven Whitehouse | a74604b | 2006-04-21 15:10:46 -0400 | [diff] [blame] | 43 | 	mutex_lock(&lmh_lock); | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 44 |  | 
 | 45 | 	list_for_each_entry(lw, &lmh_list, lw_list) { | 
 | 46 | 		if (!strcmp(lw->lw_ops->lm_proto_name, proto->lm_proto_name)) { | 
| Steven Whitehouse | a74604b | 2006-04-21 15:10:46 -0400 | [diff] [blame] | 47 | 			mutex_unlock(&lmh_lock); | 
| Steven Whitehouse | d92a8d4 | 2006-02-27 10:57:14 -0500 | [diff] [blame] | 48 | 			printk(KERN_INFO "GFS2: protocol %s already exists\n", | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 49 | 			       proto->lm_proto_name); | 
 | 50 | 			return -EEXIST; | 
 | 51 | 		} | 
 | 52 | 	} | 
 | 53 |  | 
| Steven Whitehouse | d92a8d4 | 2006-02-27 10:57:14 -0500 | [diff] [blame] | 54 | 	lw = kzalloc(sizeof(struct lmh_wrapper), GFP_KERNEL); | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 55 | 	if (!lw) { | 
| Steven Whitehouse | a74604b | 2006-04-21 15:10:46 -0400 | [diff] [blame] | 56 | 		mutex_unlock(&lmh_lock); | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 57 | 		return -ENOMEM; | 
 | 58 | 	} | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 59 |  | 
 | 60 | 	lw->lw_ops = proto; | 
 | 61 | 	list_add(&lw->lw_list, &lmh_list); | 
 | 62 |  | 
| Steven Whitehouse | a74604b | 2006-04-21 15:10:46 -0400 | [diff] [blame] | 63 | 	mutex_unlock(&lmh_lock); | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 64 |  | 
 | 65 | 	return 0; | 
 | 66 | } | 
 | 67 |  | 
 | 68 | /** | 
| Steven Whitehouse | 2b557f6 | 2006-08-07 11:12:30 -0400 | [diff] [blame] | 69 |  * gfs2_unregister_lockproto - Unregister a low-level locking protocol | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 70 |  * @proto: the protocol definition | 
 | 71 |  * | 
 | 72 |  */ | 
 | 73 |  | 
| Steven Whitehouse | 9b47c11 | 2006-09-08 10:17:58 -0400 | [diff] [blame] | 74 | void gfs2_unregister_lockproto(const struct lm_lockops *proto) | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 75 | { | 
 | 76 | 	struct lmh_wrapper *lw; | 
 | 77 |  | 
| Steven Whitehouse | a74604b | 2006-04-21 15:10:46 -0400 | [diff] [blame] | 78 | 	mutex_lock(&lmh_lock); | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 79 |  | 
 | 80 | 	list_for_each_entry(lw, &lmh_list, lw_list) { | 
 | 81 | 		if (!strcmp(lw->lw_ops->lm_proto_name, proto->lm_proto_name)) { | 
 | 82 | 			list_del(&lw->lw_list); | 
| Steven Whitehouse | a74604b | 2006-04-21 15:10:46 -0400 | [diff] [blame] | 83 | 			mutex_unlock(&lmh_lock); | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 84 | 			kfree(lw); | 
 | 85 | 			return; | 
 | 86 | 		} | 
 | 87 | 	} | 
 | 88 |  | 
| Steven Whitehouse | a74604b | 2006-04-21 15:10:46 -0400 | [diff] [blame] | 89 | 	mutex_unlock(&lmh_lock); | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 90 |  | 
| Steven Whitehouse | d92a8d4 | 2006-02-27 10:57:14 -0500 | [diff] [blame] | 91 | 	printk(KERN_WARNING "GFS2: can't unregister lock protocol %s\n", | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 92 | 	       proto->lm_proto_name); | 
 | 93 | } | 
 | 94 |  | 
 | 95 | /** | 
 | 96 |  * gfs2_mount_lockproto - Mount a lock protocol | 
 | 97 |  * @proto_name - the name of the protocol | 
 | 98 |  * @table_name - the name of the lock space | 
 | 99 |  * @host_data - data specific to this host | 
 | 100 |  * @cb - the callback to the code using the lock module | 
| Steven Whitehouse | 1c089c3 | 2006-09-07 15:50:20 -0400 | [diff] [blame] | 101 |  * @sdp - The GFS2 superblock | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 102 |  * @min_lvb_size - the mininum LVB size that the caller can deal with | 
 | 103 |  * @flags - LM_MFLAG_* | 
 | 104 |  * @lockstruct - a structure returned describing the mount | 
 | 105 |  * | 
 | 106 |  * Returns: 0 on success, -EXXX on failure | 
 | 107 |  */ | 
 | 108 |  | 
 | 109 | int gfs2_mount_lockproto(char *proto_name, char *table_name, char *host_data, | 
| Steven Whitehouse | 9b47c11 | 2006-09-08 10:17:58 -0400 | [diff] [blame] | 110 | 			 lm_callback_t cb, void *cb_data, | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 111 | 			 unsigned int min_lvb_size, int flags, | 
 | 112 | 			 struct lm_lockstruct *lockstruct, | 
 | 113 | 			 struct kobject *fskobj) | 
 | 114 | { | 
 | 115 | 	struct lmh_wrapper *lw = NULL; | 
 | 116 | 	int try = 0; | 
 | 117 | 	int error, found; | 
 | 118 |  | 
| Steven Whitehouse | 2b557f6 | 2006-08-07 11:12:30 -0400 | [diff] [blame] | 119 | retry: | 
| Steven Whitehouse | a74604b | 2006-04-21 15:10:46 -0400 | [diff] [blame] | 120 | 	mutex_lock(&lmh_lock); | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 121 |  | 
 | 122 | 	found = 0; | 
 | 123 | 	list_for_each_entry(lw, &lmh_list, lw_list) { | 
 | 124 | 		if (!strcmp(lw->lw_ops->lm_proto_name, proto_name)) { | 
 | 125 | 			found = 1; | 
 | 126 | 			break; | 
 | 127 | 		} | 
 | 128 | 	} | 
 | 129 |  | 
 | 130 | 	if (!found) { | 
 | 131 | 		if (!try && capable(CAP_SYS_MODULE)) { | 
 | 132 | 			try = 1; | 
| Steven Whitehouse | a74604b | 2006-04-21 15:10:46 -0400 | [diff] [blame] | 133 | 			mutex_unlock(&lmh_lock); | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 134 | 			request_module(proto_name); | 
 | 135 | 			goto retry; | 
 | 136 | 		} | 
| Steven Whitehouse | d92a8d4 | 2006-02-27 10:57:14 -0500 | [diff] [blame] | 137 | 		printk(KERN_INFO "GFS2: can't find protocol %s\n", proto_name); | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 138 | 		error = -ENOENT; | 
 | 139 | 		goto out; | 
 | 140 | 	} | 
 | 141 |  | 
 | 142 | 	if (!try_module_get(lw->lw_ops->lm_owner)) { | 
 | 143 | 		try = 0; | 
| Steven Whitehouse | a74604b | 2006-04-21 15:10:46 -0400 | [diff] [blame] | 144 | 		mutex_unlock(&lmh_lock); | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 145 | 		msleep(1000); | 
 | 146 | 		goto retry; | 
 | 147 | 	} | 
 | 148 |  | 
| Steven Whitehouse | 9b47c11 | 2006-09-08 10:17:58 -0400 | [diff] [blame] | 149 | 	error = lw->lw_ops->lm_mount(table_name, host_data, cb, cb_data, | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 150 | 				     min_lvb_size, flags, lockstruct, fskobj); | 
 | 151 | 	if (error) | 
 | 152 | 		module_put(lw->lw_ops->lm_owner); | 
| Steven Whitehouse | 2b557f6 | 2006-08-07 11:12:30 -0400 | [diff] [blame] | 153 | out: | 
| Steven Whitehouse | a74604b | 2006-04-21 15:10:46 -0400 | [diff] [blame] | 154 | 	mutex_unlock(&lmh_lock); | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 155 | 	return error; | 
 | 156 | } | 
 | 157 |  | 
 | 158 | void gfs2_unmount_lockproto(struct lm_lockstruct *lockstruct) | 
 | 159 | { | 
| Steven Whitehouse | a74604b | 2006-04-21 15:10:46 -0400 | [diff] [blame] | 160 | 	mutex_lock(&lmh_lock); | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 161 | 	lockstruct->ls_ops->lm_unmount(lockstruct->ls_lockspace); | 
 | 162 | 	if (lockstruct->ls_ops->lm_owner) | 
 | 163 | 		module_put(lockstruct->ls_ops->lm_owner); | 
| Steven Whitehouse | a74604b | 2006-04-21 15:10:46 -0400 | [diff] [blame] | 164 | 	mutex_unlock(&lmh_lock); | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 165 | } | 
 | 166 |  | 
 | 167 | /** | 
 | 168 |  * gfs2_withdraw_lockproto - abnormally unmount a lock module | 
 | 169 |  * @lockstruct: the lockstruct passed into mount | 
 | 170 |  * | 
 | 171 |  */ | 
 | 172 |  | 
 | 173 | void gfs2_withdraw_lockproto(struct lm_lockstruct *lockstruct) | 
 | 174 | { | 
| Steven Whitehouse | a74604b | 2006-04-21 15:10:46 -0400 | [diff] [blame] | 175 | 	mutex_lock(&lmh_lock); | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 176 | 	lockstruct->ls_ops->lm_withdraw(lockstruct->ls_lockspace); | 
 | 177 | 	if (lockstruct->ls_ops->lm_owner) | 
 | 178 | 		module_put(lockstruct->ls_ops->lm_owner); | 
| Steven Whitehouse | a74604b | 2006-04-21 15:10:46 -0400 | [diff] [blame] | 179 | 	mutex_unlock(&lmh_lock); | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 180 | } | 
 | 181 |  | 
| Steven Whitehouse | 2b557f6 | 2006-08-07 11:12:30 -0400 | [diff] [blame] | 182 | EXPORT_SYMBOL_GPL(gfs2_register_lockproto); | 
 | 183 | EXPORT_SYMBOL_GPL(gfs2_unregister_lockproto); | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 184 |  |