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