Whamcloud - gitweb
1e40b3e3690c1e9e668f7513ba8d565219b7d7be
[fs/lustre-release.git] / lustre / mds / handler.c
1 /*
2  *  linux/mds/handler.c
3  *  
4  *  Lustre Metadata Server (mds) request handler
5  * 
6  *  Copyright (C) 2001  Cluster File Systems, Inc.
7  *
8  *  This code is issued under the GNU General Public License.
9  *  See the file COPYING in this distribution
10  *
11  *  by Peter Braam <braam@clusterfs.com>
12  * 
13  *  This server is single threaded at present (but can easily be multi threaded). 
14  * 
15  */
16
17
18 #define EXPORT_SYMTAB
19
20 #include <linux/version.h>
21 #include <linux/module.h>
22 #include <linux/fs.h>
23 #include <linux/stat.h>
24 #include <linux/locks.h>
25 #include <linux/ext2_fs.h>
26 #include <linux/quotaops.h>
27 #include <asm/unistd.h>
28 #include <linux/obd_support.h>
29 #include <linux/obd.h>
30 #include <linux/lustre_lib.h>
31 #include <linux/lustre_idl.h>
32 #include <linux/lustre_mds.h>
33 #include <linux/obd_class.h>
34
35 // for testing
36 static struct mds_obd *MDS;
37
38 // XXX make this networked!  
39 static int mds_queue_req(struct mds_request *req)
40 {
41         struct mds_request *srv_req;
42         
43         if (!MDS) { 
44                 EXIT;
45                 return -1;
46         }
47
48         srv_req = kmalloc(sizeof(*srv_req), GFP_KERNEL);
49         if (!srv_req) { 
50                 EXIT;
51                 return -ENOMEM;
52         }
53
54         printk("---> MDS at %d %p, incoming req %p, srv_req %p\n", 
55                __LINE__, MDS, req, srv_req);
56
57         memset(srv_req, 0, sizeof(*req)); 
58
59         /* move the request buffer */
60         srv_req->rq_reqbuf = req->rq_reqbuf;
61         srv_req->rq_reqlen    = req->rq_reqlen;
62         srv_req->rq_obd = MDS;
63
64         /* remember where it came from */
65         srv_req->rq_reply_handle = req;
66
67         list_add(&srv_req->rq_list, &MDS->mds_reqs); 
68         wake_up(&MDS->mds_waitq);
69         return 0;
70 }
71
72 /* XXX replace with networking code */
73 int mds_reply(struct mds_request *req)
74 {
75         struct mds_request *clnt_req = req->rq_reply_handle;
76
77         ENTRY;
78
79         /* free the request buffer */
80         kfree(req->rq_reqbuf);
81         req->rq_reqbuf = NULL; 
82         
83         /* move the reply to the client */ 
84         clnt_req->rq_replen = req->rq_replen;
85         clnt_req->rq_repbuf = req->rq_repbuf;
86         req->rq_repbuf = NULL;
87         req->rq_replen = 0;
88
89         /* wake up the client */ 
90         wake_up_interruptible(&clnt_req->rq_wait_for_rep); 
91         EXIT;
92         return 0;
93 }
94
95 int mds_error(struct mds_request *req)
96 {
97         struct mds_rep_hdr *hdr;
98
99         ENTRY;
100         hdr = kmalloc(sizeof(*hdr), GFP_KERNEL);
101         if (!hdr) { 
102                 EXIT;
103                 return -ENOMEM;
104         }
105
106         memset(hdr, 0, sizeof(*hdr));
107         
108         hdr->seqno = req->rq_reqhdr->seqno;
109         hdr->status = req->rq_status; 
110         hdr->type = MDS_TYPE_ERR;
111
112         req->rq_repbuf = (char *)hdr;
113         req->rq_replen = sizeof(*hdr); 
114
115         EXIT;
116         return mds_reply(req);
117 }
118
119
120
121 static struct dentry *mds_fid2dentry(struct mds_obd *mds, struct lustre_fid *fid)
122 {
123         struct dentry *de;
124         struct inode *inode;
125
126         inode = iget(mds->mds_sb, fid->id);
127         if (!inode) { 
128                 EXIT;
129         }
130
131         de = d_alloc_root(inode);
132         if (!de) { 
133                 iput(inode);
134                 EXIT;
135                 return NULL;
136         }
137
138         de->d_inode = inode;
139         return de;
140 }
141
142 int mds_getattr(struct mds_request *req)
143 {
144         struct dentry *de = mds_fid2dentry(req->rq_obd, &req->rq_req->fid1);
145         struct inode *inode;
146         struct mds_rep *rep;
147         int rc;
148         
149         rc = mds_pack_rep(NULL, 0, NULL, 0, &req->rq_rephdr, &req->rq_rep, 
150                           &req->rq_replen, &req->rq_repbuf);
151         if (rc) { 
152                 EXIT;
153                 printk("mds: out of memory\n");
154                 req->rq_status = -ENOMEM;
155                 return -ENOMEM;
156         }
157
158         req->rq_rephdr->seqno = req->rq_reqhdr->seqno;
159         rep = req->rq_rep;
160
161         if (!de) { 
162                 EXIT;
163                 req->rq_rephdr->status = -ENOENT;
164                 return 0;
165         }
166
167         inode = de->d_inode;
168         rep->atime = inode->i_atime;
169         rep->ctime = inode->i_ctime;
170         rep->mtime = inode->i_mtime;
171         rep->uid = inode->i_uid;
172         rep->gid = inode->i_gid;
173         rep->size = inode->i_size;
174         rep->mode = inode->i_mode;
175
176         dput(de); 
177         return 0;
178 }
179
180
181 //int mds_handle(struct mds_conn *conn, int len, char *buf)
182 int mds_handle(struct mds_request *req)
183 {
184         int rc;
185         struct mds_req_hdr *hdr;
186
187         ENTRY;
188
189         hdr = (struct mds_req_hdr *)req->rq_reqbuf;
190
191         if (NTOH__u32(hdr->type) != MDS_TYPE_REQ) {
192                 printk("lustre_mds: wrong packet type sent %d\n",
193                        NTOH__u32(hdr->type));
194                 rc = -EINVAL;
195                 goto out;
196         }
197
198         rc = mds_unpack_req(req->rq_reqbuf, req->rq_reqlen, 
199                             &req->rq_reqhdr, &req->rq_req);
200         if (rc) { 
201                 printk("lustre_mds: Invalid request\n");
202                 EXIT; 
203                 goto out;
204         }
205
206         switch (req->rq_reqhdr->opc) { 
207
208         case MDS_GETATTR:
209                 CDEBUG(D_INODE, "getattr\n");
210                 rc = mds_getattr(req);
211                 break;
212
213         case MDS_OPEN:
214                 return mds_getattr(req);
215
216         case MDS_SETATTR:
217                 return mds_getattr(req);
218
219         case MDS_CREATE:
220                 return mds_getattr(req);
221
222         case MDS_MKDIR:
223                 return mds_getattr(req);
224
225         case MDS_RMDIR:
226                 return mds_getattr(req);
227
228         case MDS_SYMLINK:
229                 return mds_getattr(req);
230  
231         case MDS_LINK:
232                 return mds_getattr(req);
233   
234         case MDS_MKNOD:
235                 return mds_getattr(req);
236
237         case MDS_UNLINK:
238                 return mds_getattr(req);
239
240         case MDS_RENAME:
241                 return mds_getattr(req);
242
243         default:
244                 return mds_error(req);
245         }
246
247 out:
248         if (rc) { 
249                 printk("mds: processing error %d\n", rc);
250                 mds_error(req);
251         } else { 
252                 CDEBUG(D_INODE, "sending reply\n"); 
253                 mds_reply(req); 
254         }
255
256         return 0;
257 }
258
259
260 static void mds_timer_run(unsigned long __data)
261 {
262         struct task_struct * p = (struct task_struct *) __data;
263
264         wake_up_process(p);
265 }
266
267 int mds_main(void *arg)
268 {
269         struct mds_obd *mds = (struct mds_obd *) arg;
270         struct timer_list timer;
271
272         lock_kernel();
273         daemonize();
274         spin_lock_irq(&current->sigmask_lock);
275         sigfillset(&current->blocked);
276         recalc_sigpending(current);
277         spin_unlock_irq(&current->sigmask_lock);
278
279         sprintf(current->comm, "lustre_mds");
280
281         /* Set up an interval timer which can be used to trigger a
282            wakeup after the interval expires */
283         init_timer(&timer);
284         timer.data = (unsigned long) current;
285         timer.function = mds_timer_run;
286         mds->mds_timer = &timer;
287
288         /* Record that the  thread is running */
289         mds->mds_thread = current;
290         wake_up(&mds->mds_done_waitq); 
291
292         printk(KERN_INFO "lustre_mds starting.  Commit interval %d seconds\n",
293                         mds->mds_interval / HZ);
294
295         /* XXX maintain a list of all managed devices: insert here */
296
297         /* And now, wait forever for commit wakeup events. */
298         while (1) {
299                 struct mds_request *request;
300                 int rc; 
301
302                 if (mds->mds_flags & MDS_UNMOUNT)
303                         break;
304
305
306                 wake_up(&mds->mds_done_waitq);
307                 interruptible_sleep_on(&mds->mds_waitq);
308
309                 CDEBUG(D_INODE, "lustre_mds wakes\n");
310                 CDEBUG(D_INODE, "pick up req here and continue\n"); 
311
312                 if (list_empty(&mds->mds_reqs)) { 
313                         CDEBUG(D_INODE, "woke because of timer\n"); 
314                 } else { 
315                         request = list_entry(mds->mds_reqs.next, 
316                                              struct mds_request, rq_list);
317                         list_del(&request->rq_list);
318                         rc = mds_handle(request); 
319                 }
320         }
321
322         del_timer_sync(mds->mds_timer);
323
324         /* XXX maintain a list of all managed devices: cleanup here */
325
326         mds->mds_thread = NULL;
327         wake_up(&mds->mds_done_waitq);
328         printk("lustre_mds: exiting\n");
329         return 0;
330 }
331
332 static void mds_stop_srv_thread(struct mds_obd *mds)
333 {
334         mds->mds_flags |= MDS_UNMOUNT;
335
336         while (mds->mds_thread) {
337                 wake_up(&mds->mds_waitq);
338                 sleep_on(&mds->mds_done_waitq);
339         }
340 }
341
342 static void mds_start_srv_thread(struct mds_obd *mds)
343 {
344         init_waitqueue_head(&mds->mds_waitq);
345         init_waitqueue_head(&mds->mds_done_waitq);
346         kernel_thread(mds_main, (void *)mds, 
347                       CLONE_VM | CLONE_FS | CLONE_FILES);
348         while (!mds->mds_thread) 
349                 sleep_on(&mds->mds_done_waitq);
350 }
351
352 /* mount the file system (secretly) */
353 static int mds_setup(struct obd_device *obddev, obd_count len,
354                         void *buf)
355                         
356 {
357         struct obd_ioctl_data* data = buf;
358         struct mds_obd *mds = &obddev->u.mds;
359         struct vfsmount *mnt;
360         int err; 
361         ENTRY;
362         
363         mnt = do_kern_mount(data->ioc_inlbuf2, 0, 
364                             data->ioc_inlbuf1, NULL); 
365         err = PTR_ERR(mnt);
366         if (IS_ERR(mnt)) { 
367                 EXIT;
368                 return err;
369         }
370
371         mds->mds_sb = mnt->mnt_root->d_inode->i_sb;
372         if (!obddev->u.mds.mds_sb) {
373                 EXIT;
374                 return -ENODEV;
375         }
376
377         INIT_LIST_HEAD(&mds->mds_reqs);
378         mds->mds_thread = NULL;
379         mds->mds_flags = 0;
380         mds->mds_interval = 3 * HZ;
381         mds->mds_vfsmnt = mnt;
382         obddev->u.mds.mds_fstype = strdup(data->ioc_inlbuf2);
383
384         mds->mds_ctxt.pwdmnt = mnt;
385         mds->mds_ctxt.pwd = mnt->mnt_root;
386         mds->mds_ctxt.fs = KERNEL_DS;
387         MDS = mds;
388
389         spin_lock_init(&obddev->u.mds.fo_lock);
390
391         mds_start_srv_thread(mds);
392
393         MOD_INC_USE_COUNT;
394         EXIT; 
395         return 0;
396
397
398 static int mds_cleanup(struct obd_device * obddev)
399 {
400         struct super_block *sb;
401         struct mds_obd *mds = &obddev->u.mds;
402
403         ENTRY;
404
405         if ( !(obddev->obd_flags & OBD_SET_UP) ) {
406                 EXIT;
407                 return 0;
408         }
409
410         if ( !list_empty(&obddev->obd_gen_clients) ) {
411                 printk(KERN_WARNING __FUNCTION__ ": still has clients!\n");
412                 EXIT;
413                 return -EBUSY;
414         }
415
416         MDS = NULL;
417         mds_stop_srv_thread(mds);
418         sb = mds->mds_sb;
419         if (!mds->mds_sb){
420                 EXIT;
421                 return 0;
422         }
423
424         if (!list_empty(&mds->mds_reqs)) {
425                 // XXX reply with errors and clean up
426                 CDEBUG(D_INODE, "Request list not empty!\n");
427         }
428
429         unlock_kernel();
430         mntput(mds->mds_vfsmnt); 
431         mds->mds_sb = 0;
432         kfree(mds->mds_fstype);
433         lock_kernel();
434         
435
436         MOD_DEC_USE_COUNT;
437         EXIT;
438         return 0;
439 }
440
441 /* use obd ops to offer management infrastructure */
442 static struct obd_ops mds_obd_ops = {
443         o_setup:       mds_setup,
444         o_cleanup:     mds_cleanup,
445 };
446
447 static int __init mds_init(void)
448 {
449         obd_register_type(&mds_obd_ops, LUSTRE_MDS_NAME);
450         return 0;
451 }
452
453 static void __exit mds_exit(void)
454 {
455         obd_unregister_type(LUSTRE_MDS_NAME);
456 }
457
458 MODULE_AUTHOR("Peter J. Braam <braam@clusterfs.com>");
459 MODULE_DESCRIPTION("Lustre Metadata Server (MDS) v0.01");
460 MODULE_LICENSE("GPL");
461
462
463 // for testing (maybe this stays)
464 EXPORT_SYMBOL(mds_queue_req);
465
466 module_init(mds_init);
467 module_exit(mds_exit);