Orangefs: kernel client part 3
[linux-block.git] / fs / orangefs / pvfs2-mod.c
CommitLineData
274dcf55
MM
1/*
2 * (C) 2001 Clemson University and The University of Chicago
3 *
4 * Changes by Acxiom Corporation to add proc file handler for pvfs2 client
5 * parameters, Copyright Acxiom Corporation, 2005.
6 *
7 * See COPYING in top-level directory.
8 */
9
10#include "protocol.h"
11#include "pvfs2-kernel.h"
12#include "pvfs2-debugfs.h"
13#include "pvfs2-sysfs.h"
14
15/* PVFS2_VERSION is a ./configure define */
16#ifndef PVFS2_VERSION
17#define PVFS2_VERSION "Unknown"
18#endif
19
20/*
21 * global variables declared here
22 */
23
24/* array of client debug keyword/mask values */
25struct client_debug_mask *cdm_array;
26int cdm_element_count;
27
28char kernel_debug_string[PVFS2_MAX_DEBUG_STRING_LEN] = "none";
29char client_debug_string[PVFS2_MAX_DEBUG_STRING_LEN];
30char client_debug_array_string[PVFS2_MAX_DEBUG_STRING_LEN];
31
32char *debug_help_string;
33int help_string_initialized;
34struct dentry *help_file_dentry;
35struct dentry *client_debug_dentry;
36struct dentry *debug_dir;
37int client_verbose_index;
38int client_all_index;
39struct pvfs2_stats g_pvfs2_stats;
40
41/* the size of the hash tables for ops in progress */
42int hash_table_size = 509;
43
44static ulong module_parm_debug_mask;
45__u64 gossip_debug_mask;
46struct client_debug_mask client_debug_mask = { NULL, 0, 0 };
47unsigned int kernel_mask_set_mod_init; /* implicitly false */
48int op_timeout_secs = PVFS2_DEFAULT_OP_TIMEOUT_SECS;
49int slot_timeout_secs = PVFS2_DEFAULT_SLOT_TIMEOUT_SECS;
50__u32 DEBUG_LINE = 50;
51
52MODULE_LICENSE("GPL");
53MODULE_AUTHOR("PVFS2 Development Team");
54MODULE_DESCRIPTION("The Linux Kernel VFS interface to PVFS2");
55MODULE_PARM_DESC(module_parm_debug_mask, "debugging level (see pvfs2-debug.h for values)");
56MODULE_PARM_DESC(op_timeout_secs, "Operation timeout in seconds");
57MODULE_PARM_DESC(slot_timeout_secs, "Slot timeout in seconds");
58MODULE_PARM_DESC(hash_table_size,
59 "size of hash table for operations in progress");
60
61static struct file_system_type pvfs2_fs_type = {
62 .name = "pvfs2",
63 .mount = pvfs2_mount,
64 .kill_sb = pvfs2_kill_sb,
65 .owner = THIS_MODULE,
66};
67
68module_param(hash_table_size, int, 0);
69module_param(module_parm_debug_mask, ulong, 0755);
70module_param(op_timeout_secs, int, 0);
71module_param(slot_timeout_secs, int, 0);
72
73/* synchronizes the request device file */
74struct mutex devreq_mutex;
75
76/*
77 blocks non-priority requests from being queued for servicing. this
78 could be used for protecting the request list data structure, but
79 for now it's only being used to stall the op addition to the request
80 list
81*/
82struct mutex request_mutex;
83
84/* hash table for storing operations waiting for matching downcall */
85struct list_head *htable_ops_in_progress;
86DEFINE_SPINLOCK(htable_ops_in_progress_lock);
87
88/* list for queueing upcall operations */
89LIST_HEAD(pvfs2_request_list);
90
91/* used to protect the above pvfs2_request_list */
92DEFINE_SPINLOCK(pvfs2_request_list_lock);
93
94/* used for incoming request notification */
95DECLARE_WAIT_QUEUE_HEAD(pvfs2_request_list_waitq);
96
97static int __init pvfs2_init(void)
98{
99 int ret = -1;
100 __u32 i = 0;
101
102 /* convert input debug mask to a 64-bit unsigned integer */
103 gossip_debug_mask = (unsigned long long) module_parm_debug_mask;
104
105 /*
106 * set the kernel's gossip debug string; invalid mask values will
107 * be ignored.
108 */
109 debug_mask_to_string(&gossip_debug_mask, 0);
110
111 /* remove any invalid values from the mask */
112 debug_string_to_mask(kernel_debug_string, &gossip_debug_mask, 0);
113
114 /*
115 * if the mask has a non-zero value, then indicate that the mask
116 * was set when the kernel module was loaded. The pvfs2 dev ioctl
117 * command will look at this boolean to determine if the kernel's
118 * debug mask should be overwritten when the client-core is started.
119 */
120 if (gossip_debug_mask != 0)
121 kernel_mask_set_mod_init = true;
122
123 /* print information message to the system log */
124 pr_info("pvfs2: pvfs2_init called with debug mask: :%s: :%llx:\n",
125 kernel_debug_string,
126 (unsigned long long)gossip_debug_mask);
127
128 ret = bdi_init(&pvfs2_backing_dev_info);
129
130 if (ret)
131 return ret;
132
133 if (op_timeout_secs < 0)
134 op_timeout_secs = 0;
135
136 if (slot_timeout_secs < 0)
137 slot_timeout_secs = 0;
138
139 /* initialize global book keeping data structures */
140 ret = op_cache_initialize();
141 if (ret < 0)
142 goto err;
143
144 ret = dev_req_cache_initialize();
145 if (ret < 0)
146 goto cleanup_op;
147
148 ret = pvfs2_inode_cache_initialize();
149 if (ret < 0)
150 goto cleanup_req;
151
152 ret = kiocb_cache_initialize();
153 if (ret < 0)
154 goto cleanup_inode;
155
156 /* Initialize the pvfsdev subsystem. */
157 ret = pvfs2_dev_init();
158 if (ret < 0) {
159 gossip_err("pvfs2: could not initialize device subsystem %d!\n",
160 ret);
161 goto cleanup_kiocb;
162 }
163
164 mutex_init(&devreq_mutex);
165 mutex_init(&request_mutex);
166
167 htable_ops_in_progress =
168 kcalloc(hash_table_size, sizeof(struct list_head), GFP_KERNEL);
169 if (!htable_ops_in_progress) {
170 gossip_err("Failed to initialize op hashtable");
171 ret = -ENOMEM;
172 goto cleanup_device;
173 }
174
175 /* initialize a doubly linked at each hash table index */
176 for (i = 0; i < hash_table_size; i++)
177 INIT_LIST_HEAD(&htable_ops_in_progress[i]);
178
179 ret = fsid_key_table_initialize();
180 if (ret < 0)
181 goto cleanup_progress_table;
182
183 /*
184 * Build the contents of /sys/kernel/debug/orangefs/debug-help
185 * from the keywords in the kernel keyword/mask array.
186 *
187 * The keywords in the client keyword/mask array are
188 * unknown at boot time.
189 *
190 * orangefs_prepare_debugfs_help_string will be used again
191 * later to rebuild the debug-help file after the client starts
192 * and passes along the needed info. The argument signifies
193 * which time orangefs_prepare_debugfs_help_string is being
194 * called.
195 *
196 */
197 ret = orangefs_prepare_debugfs_help_string(1);
198 if (ret)
199 goto out;
200
201 pvfs2_debugfs_init();
202 pvfs2_kernel_debug_init();
203 orangefs_sysfs_init();
204
205 ret = register_filesystem(&pvfs2_fs_type);
206 if (ret == 0) {
207 pr_info("pvfs2: module version %s loaded\n", PVFS2_VERSION);
208 return 0;
209 }
210
211 pvfs2_debugfs_cleanup();
212 orangefs_sysfs_exit();
213 fsid_key_table_finalize();
214
215cleanup_progress_table:
216 kfree(htable_ops_in_progress);
217
218cleanup_device:
219 pvfs2_dev_cleanup();
220
221cleanup_kiocb:
222 kiocb_cache_finalize();
223
224cleanup_inode:
225 pvfs2_inode_cache_finalize();
226
227cleanup_req:
228 dev_req_cache_finalize();
229
230cleanup_op:
231 op_cache_finalize();
232
233err:
234 bdi_destroy(&pvfs2_backing_dev_info);
235
236out:
237 return ret;
238}
239
240static void __exit pvfs2_exit(void)
241{
242 int i = 0;
243 struct pvfs2_kernel_op_s *cur_op = NULL;
244
245 gossip_debug(GOSSIP_INIT_DEBUG, "pvfs2: pvfs2_exit called\n");
246
247 unregister_filesystem(&pvfs2_fs_type);
248 pvfs2_debugfs_cleanup();
249 orangefs_sysfs_exit();
250 fsid_key_table_finalize();
251 pvfs2_dev_cleanup();
252 /* clear out all pending upcall op requests */
253 spin_lock(&pvfs2_request_list_lock);
254 while (!list_empty(&pvfs2_request_list)) {
255 cur_op = list_entry(pvfs2_request_list.next,
256 struct pvfs2_kernel_op_s,
257 list);
258 list_del(&cur_op->list);
259 gossip_debug(GOSSIP_INIT_DEBUG,
260 "Freeing unhandled upcall request type %d\n",
261 cur_op->upcall.type);
262 op_release(cur_op);
263 }
264 spin_unlock(&pvfs2_request_list_lock);
265
266 for (i = 0; i < hash_table_size; i++)
267 while (!list_empty(&htable_ops_in_progress[i])) {
268 cur_op = list_entry(htable_ops_in_progress[i].next,
269 struct pvfs2_kernel_op_s,
270 list);
271 op_release(cur_op);
272 }
273
274 kiocb_cache_finalize();
275 pvfs2_inode_cache_finalize();
276 dev_req_cache_finalize();
277 op_cache_finalize();
278
279 kfree(htable_ops_in_progress);
280
281 bdi_destroy(&pvfs2_backing_dev_info);
282
283 pr_info("pvfs2: module version %s unloaded\n", PVFS2_VERSION);
284}
285
286/*
287 * What we do in this function is to walk the list of operations
288 * that are in progress in the hash table and mark them as purged as well.
289 */
290void purge_inprogress_ops(void)
291{
292 int i;
293
294 for (i = 0; i < hash_table_size; i++) {
295 struct pvfs2_kernel_op_s *op;
296 struct pvfs2_kernel_op_s *next;
297
298 list_for_each_entry_safe(op,
299 next,
300 &htable_ops_in_progress[i],
301 list) {
302 spin_lock(&op->lock);
303 gossip_debug(GOSSIP_INIT_DEBUG,
304 "pvfs2-client-core: purging in-progress op tag "
305 "%llu %s\n",
306 llu(op->tag),
307 get_opname_string(op));
308 set_op_state_purged(op);
309 spin_unlock(&op->lock);
310 wake_up_interruptible(&op->waitq);
311 }
312 }
313}
314
315module_init(pvfs2_init);
316module_exit(pvfs2_exit);