Whamcloud - gitweb
a working file system!
[fs/lustre-release.git] / lustre / obdfs / super.c
1 /*
2  * OBDFS Super operations
3  *
4  * Copryright (C) 1996 Peter J. Braam <braam@stelias.com>
5  * Copryright (C) 1999 Stelias Computing Inc. <braam@stelias.com>
6  * Copryright (C) 1999 Seagate Technology Inc.
7  * Copryright (C) 2001 Mountain View Data, Inc.
8  *
9  */
10
11 #define EXPORT_SYMTAB
12
13 #include <linux/config.h>
14 #include <linux/module.h>
15 #include <linux/kernel.h>
16 #include <linux/mm.h>
17 #include <linux/string.h>
18 #include <linux/stat.h>
19 #include <linux/errno.h>
20 #include <linux/locks.h>
21 #include <linux/unistd.h>
22
23 #include <asm/system.h>
24 #include <asm/uaccess.h>
25
26 #include <linux/fs.h>
27 #include <linux/stat.h>
28 #include <asm/uaccess.h>
29 #include <linux/vmalloc.h>
30 #include <asm/segment.h>
31
32 #include <linux/obd_support.h>
33 #include <linux/obd_class.h>
34 #include <linux/obdfs.h>
35
36 struct list_head obdfs_super_list;
37 struct address_space_operations obdfs_aops;
38 struct super_operations obdfs_super_operations;
39 long obdfs_cache_count = 0;
40 long obdfs_mutex_start = 0;
41 long obd_memory = 0;
42
43 static char *obdfs_read_opt(const char *opt, char *data)
44 {
45         char *value;
46         char *retval;
47
48         CDEBUG(D_INFO, "option: %s, data %s\n", opt, data);
49         if ( strncmp(opt, data, strlen(opt)) )
50                 return NULL;
51
52         if ( (value = strchr(data, '=')) == NULL )
53                 return NULL;
54
55         value++;
56         OBD_ALLOC(retval, char *, strlen(value) + 1);
57         if ( !retval ) {
58                 printk(KERN_ALERT __FUNCTION__ ": out of memory!\n");
59                 return NULL;
60         }
61         
62         memcpy(retval, value, strlen(value)+1);
63         CDEBUG(D_PSDEV, "Assigned option: %s, value %s\n", opt, retval);
64         return retval;
65 }
66
67 static void obdfs_options(char *options, char **dev, char **vers)
68 {
69         char *this_char;
70
71         if (!options)
72                 return;
73
74         for (this_char = strtok (options, ",");
75              this_char != NULL;
76              this_char = strtok (NULL, ",")) {
77                 CDEBUG(D_INFO, "this_char %s\n", this_char);
78                 if ( (!*dev && (*dev = obdfs_read_opt("device", this_char)))||
79                      (!*vers && (*vers = obdfs_read_opt("version", this_char))) )
80                         continue;
81                 
82         }
83 }
84
85 static int obdfs_getdev(char *devpath, int *dev)
86 {
87         struct dentry *dentry;
88         kdev_t devno;
89         struct nameidata nd;
90         int error = 0; 
91
92         ENTRY;
93         if (path_init(devpath, LOOKUP_POSITIVE, &nd))
94                 error = path_walk(devpath, &nd);
95         if (error)
96                 return error;
97
98         dentry = nd.dentry;
99         if (!S_ISCHR(dentry->d_inode->i_mode))
100                 return -ENODEV;
101
102         devno = dentry->d_inode->i_rdev;
103         if ( MAJOR(devno) != OBD_PSDEV_MAJOR ) 
104                 return -ENODEV;
105         
106         if ( MINOR(devno) >= MAX_OBD_DEVICES ) 
107                 return -ENODEV;
108
109         *dev = devno;
110         return 0;
111 }
112
113
114 static struct super_block * obdfs_read_super(struct super_block *sb, 
115                                             void *data, int silent)
116 {
117         struct inode *root = 0; 
118         struct obdfs_sb_info *sbi = (struct obdfs_sb_info *)(&sb->u.generic_sbp);
119         struct obd_device *obddev;
120         char *device = NULL;
121         char *version = NULL;
122         int devno;
123         int err;
124         unsigned long blocksize;
125         unsigned long blocksize_bits;
126         unsigned long root_ino;
127         int scratch;
128         
129
130         ENTRY;
131         MOD_INC_USE_COUNT; 
132         
133         memset(sbi, 0, sizeof(*sbi));
134         
135         CDEBUG(D_INFO, "\n"); 
136         obdfs_options(data, &device, &version);
137         if ( !device ) {
138                 printk(__FUNCTION__ ": no device\n");
139                 EXIT;
140                 goto ERR;
141         }
142
143         CDEBUG(D_INFO, "\n"); 
144         if ( (err = obdfs_getdev(device, &devno)) ) {
145                 printk("Cannot get devno of %s, error %d\n", device, err);
146                 EXIT;
147                 goto ERR;;
148         }
149
150         CDEBUG(D_INFO, "\n"); 
151         if ( MAJOR(devno) != OBD_PSDEV_MAJOR ) {
152                 printk(__FUNCTION__ ": wrong major number %d!\n", MAJOR(devno));
153                 EXIT;
154                 goto ERR;
155         }
156                 
157         CDEBUG(D_INFO, "\n"); 
158         if ( MINOR(devno) >= MAX_OBD_DEVICES ) {
159                 printk(__FUNCTION__ ": minor of %s too high (%d)\n",
160                        device, MINOR(devno));
161                 EXIT;
162                 goto ERR;
163         } 
164
165         CDEBUG(D_INFO, "\n"); 
166         obddev = &obd_dev[MINOR(devno)];
167
168         CDEBUG(D_INFO, "\n"); 
169         if ( ! (obddev->obd_flags & OBD_ATTACHED) || 
170              ! (obddev->obd_flags & OBD_SET_UP) ){
171                 printk("device %s not attached or not set up (%d)\n", 
172                        device, MINOR(devno));
173                 EXIT;
174                 goto ERR;;
175         } 
176
177         CDEBUG(D_INFO, "\n"); 
178         sbi->osi_obd = obddev;
179         sbi->osi_ops = sbi->osi_obd->obd_type->typ_ops;
180         
181         sbi->osi_conn.oc_dev = obddev;
182         err = sbi->osi_ops->o_connect(&sbi->osi_conn);
183         if ( err ) {
184                 printk("OBDFS: cannot connect to %s\n", device);
185                 EXIT;
186                 goto ERR;
187         }
188
189         CDEBUG(D_INFO, "\n"); 
190         /* list of dirty inodes, and a mutex to hold while modifying it */
191         INIT_LIST_HEAD(&sbi->osi_inodes);
192         sema_init(&sbi->osi_list_mutex, 1);
193
194         CDEBUG(D_INFO, "\n"); 
195         sbi->osi_super = sb;
196
197         CDEBUG(D_INFO, "\n"); 
198         err = sbi->osi_ops->o_get_info(&sbi->osi_conn, strlen("blocksize"),
199                                        "blocksize", &scratch,
200                                        (void *)&blocksize);
201         if ( err ) {
202                 printk("getinfo call to drive failed (blocksize)\n");
203                 EXIT;
204                 goto ERR;
205         }
206
207         CDEBUG(D_INFO, "\n"); 
208         err = sbi->osi_ops->o_get_info(&sbi->osi_conn, strlen("blocksize_bits"),
209                                        "blocksize_bits", &scratch,
210                                        (void *)&blocksize_bits);
211         if ( err ) {
212                 printk("getinfo call to drive failed (blocksize_bits)\n");
213                 EXIT;
214                 goto ERR;
215         }
216
217         CDEBUG(D_INFO, "\n"); 
218         err = sbi->osi_ops->o_get_info(&sbi->osi_conn, strlen("root_ino"), 
219                                        "root_ino", &scratch, (void *)&root_ino);
220         if ( err ) {
221                 printk("getinfo call to drive failed (root_ino)\n");
222                 EXIT;
223                 goto ERR;
224         }
225         
226         CDEBUG(D_INFO, "\n"); 
227         sb->s_blocksize = blocksize;
228         sb->s_blocksize_bits = (unsigned char)blocksize_bits;
229         sb->s_magic = OBDFS_SUPER_MAGIC;
230         sb->s_op = &obdfs_super_operations;
231
232         /* XXX how to get "sb->s_flags |= MS_RDONLY" here for snapshots? */
233
234         /* make root inode */
235         CDEBUG(D_INFO, "\n"); 
236         root = iget(sb, root_ino);
237         if (!root || is_bad_inode(root)) {
238             printk("OBDFS: bad iget for root\n");
239             sb->s_dev = 0;
240             err = -ENOENT;
241             EXIT;
242             goto ERR;
243         } 
244         
245         CDEBUG(D_INFO, "obdfs_read_super: sbdev %d, rootino: %ld, dev %s, "
246                "minor: %d, blocksize: %ld, blocksize bits %ld\n", 
247                sb->s_dev, root->i_ino, device, MINOR(devno), 
248                blocksize, blocksize_bits);
249         sb->s_root = d_alloc_root(root);
250         list_add(&sbi->osi_list, &obdfs_super_list);
251         OBD_FREE(device, strlen(device) + 1);
252         if (version)
253                 OBD_FREE(version, strlen(version) + 1);
254         EXIT;  
255         return sb;
256
257 ERR:
258         MOD_DEC_USE_COUNT;
259         if (device)
260                 OBD_FREE(device, strlen(device) + 1);
261         if (version)
262                 OBD_FREE(version, strlen(version) + 1);
263         if (sbi) {
264                 sbi->osi_super = NULL;
265         }
266         if (root) {
267                 iput(root);
268         }
269         sb->s_dev = 0;
270         return NULL;
271 } /* obdfs_read_super */
272
273
274 static void obdfs_put_super(struct super_block *sb)
275 {
276         struct obdfs_sb_info *sbi;
277
278         ENTRY;
279         sb->s_dev = 0;
280         
281         sbi = (struct obdfs_sb_info *) &sb->u.generic_sbp;
282         obdfs_flush_reqs(&sbi->osi_inodes, ~0UL);
283
284         OPS(sb,disconnect)(ID(sb));
285         list_del(&sbi->osi_list);
286         memset(sbi, 0, sizeof(*sbi));
287         
288         printk(KERN_INFO "OBDFS: Bye bye.\n");
289
290         MOD_DEC_USE_COUNT;
291         EXIT;
292 } /* obdfs_put_super */
293
294
295 /* all filling in of inodes postponed until lookup */
296 static void obdfs_read_inode(struct inode *inode)
297 {
298         struct obdo *oa;
299
300         ENTRY;
301         oa = obdo_fromid(IID(inode), inode->i_ino,
302                          OBD_MD_FLNOTOBD | OBD_MD_FLBLOCKS);
303         if ( IS_ERR(oa) ) {
304                 printk(__FUNCTION__ ": obdo_fromid failed\n");
305                 EXIT;
306                 return /* PTR_ERR(oa) */;
307         }
308
309         ODEBUG(oa);
310         obdfs_to_inode(inode, oa);
311         INIT_LIST_HEAD(obdfs_iplist(inode)); /* list of dirty pages on inode */
312         INIT_LIST_HEAD(obdfs_islist(inode)); /* list of inodes in superblock */
313
314         obdo_free(oa);
315         /* OIDEBUG(inode); */
316
317         if (S_ISREG(inode->i_mode)) {
318                 inode->i_op = &obdfs_file_inode_operations;
319                 inode->i_fop = &obdfs_file_operations;
320                 inode->i_mapping->a_ops = &obdfs_aops;
321                 EXIT;
322         } else if (S_ISDIR(inode->i_mode)) {
323                 inode->i_op = &obdfs_dir_inode_operations;
324                 inode->i_fop = &obdfs_dir_operations; 
325                 EXIT;
326         } else if (S_ISLNK(inode->i_mode)) {
327                 if (inode->i_blocks) { 
328                         inode->i_op = &obdfs_symlink_inode_operations;
329                         inode->i_mapping->a_ops = &obdfs_aops;
330                 }else {
331                         inode->i_op = &obdfs_fast_symlink_inode_operations;
332                 }
333                 EXIT;
334         } else {
335                 init_special_inode(inode, inode->i_mode,
336                                    ((int *)obdfs_i2info(inode)->oi_inline)[0]);
337         }
338
339         return;
340 } /* obdfs_read_inode */
341
342 static void obdfs_write_inode(struct inode *inode, int wait) 
343 {
344         struct obdo *oa;
345         int err;
346         
347         ENTRY;
348         if (IOPS(inode, setattr) == NULL) {
349                 printk(KERN_ERR __FUNCTION__ ": no setattr method!\n");
350                 EXIT;
351                 return;
352         }
353         oa = obdo_alloc();
354         if ( !oa ) {
355                 printk(__FUNCTION__ ": obdo_alloc failed\n");
356                 EXIT;
357                 return;
358         }
359
360         oa->o_valid = OBD_MD_FLNOTOBD;
361         obdfs_from_inode(oa, inode);
362         err = IOPS(inode, setattr)(IID(inode), oa);
363
364         if ( err )
365                 printk(__FUNCTION__ ": obd_setattr fails (%d)\n", err);
366
367         EXIT;
368         obdo_free(oa);
369 } /* obdfs_write_inode */
370
371
372 /* This routine is called from iput() (for each unlink on the inode).
373  * We can't put this call into delete_inode() since that is called only
374  * when i_count == 0, and we need to keep a reference on the inode while
375  * it is in the page cache, which means i_count > 0.  Catch 22.
376  */
377 static void obdfs_put_inode(struct inode *inode)
378 {
379         ENTRY;
380         if (inode->i_nlink) {
381                 EXIT;
382                 return;
383         }
384
385         obdfs_dequeue_pages(inode);
386         EXIT;
387 } /* obdfs_put_inode */
388
389
390 static void obdfs_delete_inode(struct inode *inode)
391 {
392         struct obdo *oa;
393         int err;
394
395         ENTRY;
396         if (IOPS(inode, destroy) == NULL) {
397                 printk(KERN_ERR __FUNCTION__ ": no destroy method!\n");
398                 EXIT;
399                 return;
400         }
401
402         oa = obdo_alloc();
403         if ( !oa ) {
404                 printk(__FUNCTION__ ": obdo_alloc failed\n");
405                 EXIT;
406                 return;
407         }
408         oa->o_valid = OBD_MD_FLNOTOBD;
409         obdfs_from_inode(oa, inode);
410
411         ODEBUG(oa);
412         err = IOPS(inode, destroy)(IID(inode), oa);
413         obdo_free(oa);
414
415         if (err) {
416                 printk(__FUNCTION__ ": obd_destroy fails (%d)\n", err);
417                 EXIT;
418                 return;
419         }
420
421         EXIT;
422 } /* obdfs_delete_inode */
423
424
425 int obdfs_notify_change(struct dentry *de, struct iattr *attr)
426 {
427         struct inode *inode = de->d_inode;
428         struct obdo *oa;
429         int err;
430
431         ENTRY;
432         if (IOPS(inode, setattr) == NULL) {
433                 printk(KERN_ERR __FUNCTION__ ": no setattr method!\n");
434                 EXIT;
435                 return -EIO;
436         }
437         oa = obdo_alloc();
438         if ( !oa ) {
439                 printk(__FUNCTION__ ": obdo_alloc failed\n");
440                 return -ENOMEM;
441         }
442
443         oa->o_id = inode->i_ino;
444         obdo_from_iattr(oa, attr);
445         err = IOPS(inode, setattr)(IID(inode), oa);
446
447         if ( err )
448                 printk(__FUNCTION__ ": obd_setattr fails (%d)\n", err);
449
450         EXIT;
451         obdo_free(oa);
452         return err;
453 } /* obdfs_notify_change */
454
455
456 static int obdfs_statfs(struct super_block *sb, struct statfs *buf)
457 {
458         struct statfs tmp;
459         int bufsize = sizeof(*buf);
460         int err;
461
462         ENTRY;
463
464         err = OPS(sb,statfs)(ID(sb), &tmp);
465         if ( err ) { 
466                 printk(__FUNCTION__ ": obd_statfs fails (%d)\n", err);
467                 return err;
468         }
469         copy_to_user(buf, &tmp, (bufsize<sizeof(tmp)) ? bufsize : sizeof(tmp));
470
471         EXIT;
472
473         return err; 
474 }
475
476 /* exported operations */
477 struct super_operations obdfs_super_operations =
478 {
479         read_inode: obdfs_read_inode,
480         write_inode: obdfs_write_inode,
481         put_inode: obdfs_put_inode,
482         delete_inode: obdfs_delete_inode,
483         put_super: obdfs_put_super,
484         statfs: obdfs_statfs
485 };
486
487 struct file_system_type obdfs_fs_type = {
488    "obdfs", 0, obdfs_read_super, NULL
489 };
490
491 int init_obdfs(void)
492 {
493         int err;
494
495         printk(KERN_INFO "OBDFS v0.1, braam@stelias.com\n");
496
497         obdfs_sysctl_init();
498
499         INIT_LIST_HEAD(&obdfs_super_list);
500         err = obdfs_init_pgrqcache();
501         if (err)
502                 return err;
503
504         obdfs_flushd_init();
505         return register_filesystem(&obdfs_fs_type);
506 }
507
508 struct address_space_operations obdfs_aops = {
509         readpage: obdfs_readpage,
510         writepage: obdfs_writepage,
511         sync_page: block_sync_page,
512         prepare_write: NULL, 
513         commit_write: generic_commit_write,
514         bmap: NULL
515 };
516
517
518 #ifdef MODULE
519 int init_module(void)
520 {
521         return init_obdfs();
522 }
523
524 void cleanup_module(void)
525 {
526         ENTRY;
527
528         obdfs_flushd_cleanup();
529         obdfs_sysctl_clean();
530         obdfs_cleanup_pgrqcache();
531         unregister_filesystem(&obdfs_fs_type);
532         CDEBUG(D_MALLOC, "OBDFS mem used %ld\n", obd_memory);
533         EXIT;
534 }
535
536 #endif