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