]> git.karo-electronics.de Git - karo-tx-linux.git/blob - fs/gfs2/locking.c
Merge branch 'master'
[karo-tx-linux.git] / fs / gfs2 / locking.c
1 /*
2  * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
3  * Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
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
7  * of the GNU General Public License v.2.
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>
19
20 #include "lm_interface.h"
21
22 struct lmh_wrapper {
23         struct list_head lw_list;
24         struct lm_lockops *lw_ops;
25 };
26
27 /* List of registered low-level locking protocols.  A file system selects one
28    of them by name at mount time, e.g. lock_nolock, lock_dlm. */
29
30 static struct list_head lmh_list;
31 static struct semaphore lmh_lock;
32
33 /**
34  * gfs_register_lockproto - Register a low-level locking protocol
35  * @proto: the protocol definition
36  *
37  * Returns: 0 on success, -EXXX on failure
38  */
39
40 int gfs_register_lockproto(struct lm_lockops *proto)
41 {
42         struct lmh_wrapper *lw;
43
44         down(&lmh_lock);
45
46         list_for_each_entry(lw, &lmh_list, lw_list) {
47                 if (!strcmp(lw->lw_ops->lm_proto_name, proto->lm_proto_name)) {
48                         up(&lmh_lock);
49                         printk("GFS2: protocol %s already exists\n",
50                                proto->lm_proto_name);
51                         return -EEXIST;
52                 }
53         }
54
55         lw = kmalloc(sizeof(struct lmh_wrapper), GFP_KERNEL);
56         if (!lw) {
57                 up(&lmh_lock);
58                 return -ENOMEM;
59         }
60         memset(lw, 0, sizeof(struct lmh_wrapper));
61
62         lw->lw_ops = proto;
63         list_add(&lw->lw_list, &lmh_list);
64
65         up(&lmh_lock);
66
67         return 0;
68 }
69
70 /**
71  * gfs_unregister_lockproto - Unregister a low-level locking protocol
72  * @proto: the protocol definition
73  *
74  */
75
76 void gfs_unregister_lockproto(struct lm_lockops *proto)
77 {
78         struct lmh_wrapper *lw;
79
80         down(&lmh_lock);
81
82         list_for_each_entry(lw, &lmh_list, lw_list) {
83                 if (!strcmp(lw->lw_ops->lm_proto_name, proto->lm_proto_name)) {
84                         list_del(&lw->lw_list);
85                         up(&lmh_lock);
86                         kfree(lw);
87                         return;
88                 }
89         }
90
91         up(&lmh_lock);
92
93         printk("GFS2: can't unregister lock protocol %s\n",
94                proto->lm_proto_name);
95 }
96
97 /**
98  * gfs2_mount_lockproto - Mount a lock protocol
99  * @proto_name - the name of the protocol
100  * @table_name - the name of the lock space
101  * @host_data - data specific to this host
102  * @cb - the callback to the code using the lock module
103  * @fsdata - data to pass back with the callback
104  * @min_lvb_size - the mininum LVB size that the caller can deal with
105  * @flags - LM_MFLAG_*
106  * @lockstruct - a structure returned describing the mount
107  *
108  * Returns: 0 on success, -EXXX on failure
109  */
110
111 int gfs2_mount_lockproto(char *proto_name, char *table_name, char *host_data,
112                          lm_callback_t cb, lm_fsdata_t *fsdata,
113                          unsigned int min_lvb_size, int flags,
114                          struct lm_lockstruct *lockstruct,
115                          struct kobject *fskobj)
116 {
117         struct lmh_wrapper *lw = NULL;
118         int try = 0;
119         int error, found;
120
121  retry:
122         down(&lmh_lock);
123
124         found = 0;
125         list_for_each_entry(lw, &lmh_list, lw_list) {
126                 if (!strcmp(lw->lw_ops->lm_proto_name, proto_name)) {
127                         found = 1;
128                         break;
129                 }
130         }
131
132         if (!found) {
133                 if (!try && capable(CAP_SYS_MODULE)) {
134                         try = 1;
135                         up(&lmh_lock);
136                         request_module(proto_name);
137                         goto retry;
138                 }
139                 printk("GFS2: can't find protocol %s\n", proto_name);
140                 error = -ENOENT;
141                 goto out;
142         }
143
144         if (!try_module_get(lw->lw_ops->lm_owner)) {
145                 try = 0;
146                 up(&lmh_lock);
147                 msleep(1000);
148                 goto retry;
149         }
150
151         error = lw->lw_ops->lm_mount(table_name, host_data, cb, fsdata,
152                                      min_lvb_size, flags, lockstruct, fskobj);
153         if (error)
154                 module_put(lw->lw_ops->lm_owner);
155  out:
156         up(&lmh_lock);
157         return error;
158 }
159
160 void gfs2_unmount_lockproto(struct lm_lockstruct *lockstruct)
161 {
162         down(&lmh_lock);
163         lockstruct->ls_ops->lm_unmount(lockstruct->ls_lockspace);
164         if (lockstruct->ls_ops->lm_owner)
165                 module_put(lockstruct->ls_ops->lm_owner);
166         up(&lmh_lock);
167 }
168
169 /**
170  * gfs2_withdraw_lockproto - abnormally unmount a lock module
171  * @lockstruct: the lockstruct passed into mount
172  *
173  */
174
175 void gfs2_withdraw_lockproto(struct lm_lockstruct *lockstruct)
176 {
177         down(&lmh_lock);
178         lockstruct->ls_ops->lm_withdraw(lockstruct->ls_lockspace);
179         if (lockstruct->ls_ops->lm_owner)
180                 module_put(lockstruct->ls_ops->lm_owner);
181         up(&lmh_lock);
182 }
183
184 void __init gfs2_init_lmh(void)
185 {
186         init_MUTEX(&lmh_lock);
187         INIT_LIST_HEAD(&lmh_list);
188 }
189
190 EXPORT_SYMBOL_GPL(gfs_register_lockproto);
191 EXPORT_SYMBOL_GPL(gfs_unregister_lockproto);
192