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