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