Whamcloud - gitweb
demos/test.c: removed duplicate files (also exist in test/test.c)
[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 = &obdfs_symlink_inode_operations;
308                 EXIT;
309         } else {
310                 init_special_inode(inode, inode->i_mode,
311                                    ((int *)obdfs_i2info(inode)->oi_inline)[0]);
312         }
313
314         return;
315 } /* obdfs_read_inode */
316
317 static void obdfs_write_inode(struct inode *inode) 
318 {
319         struct obdo *oa;
320         int err;
321         
322         ENTRY;
323         if (IOPS(inode, setattr) == NULL) {
324                 printk(KERN_ERR __FUNCTION__ ": no setattr method!\n");
325                 EXIT;
326                 return;
327         }
328         oa = obdo_alloc();
329         if ( !oa ) {
330                 printk(__FUNCTION__ ": obdo_alloc failed\n");
331                 return;
332         }
333
334         oa->o_valid = OBD_MD_FLNOTOBD;
335         obdfs_from_inode(oa, inode);
336         err = IOPS(inode, setattr)(IID(inode), oa);
337
338         if ( err ) {
339                 printk(__FUNCTION__ ": obd_setattr fails (%d)\n", err);
340                 EXIT;
341         } else {
342                 /* Copy back attributes from oa, as there may have been
343                  * changes at the target (e.g. obdo becomes a redirector
344                  * in the snapshot layer).
345                  */
346                 obdfs_to_inode(inode, oa);
347                 EXIT;
348         }
349
350         obdo_free(oa);
351 } /* obdfs_write_inode */
352
353
354 /* This routine is called from iput() (for each unlink on the inode).
355  * We can't put this call into delete_inode() since that is called only
356  * when i_count == 0, and we need to keep a reference on the inode while
357  * it is in the page cache, which means i_count > 0.  Catch 22.
358  */
359 static void obdfs_put_inode(struct inode *inode)
360 {
361         ENTRY;
362         if (inode->i_nlink) {
363                 EXIT;
364                 return;
365         }
366
367         obdfs_dequeue_pages(inode);
368         EXIT;
369 } /* obdfs_put_inode */
370
371
372 static void obdfs_delete_inode(struct inode *inode)
373 {
374         struct obdo *oa;
375         int err;
376
377         ENTRY;
378         if (IOPS(inode, destroy) == NULL) {
379                 printk(KERN_ERR __FUNCTION__ ": no destroy method!\n");
380                 EXIT;
381                 return;
382         }
383
384         oa = obdo_alloc();
385         if ( !oa ) {
386                 printk(__FUNCTION__ ": obdo_alloc failed\n");
387                 EXIT;
388                 return;
389         }
390         oa->o_valid = OBD_MD_FLNOTOBD;
391         obdfs_from_inode(oa, inode);
392
393         ODEBUG(oa);
394         err = IOPS(inode, destroy)(IID(inode), oa);
395         obdo_free(oa);
396
397         if (err) {
398                 printk(__FUNCTION__ ": obd_destroy fails (%d)\n", err);
399                 EXIT;
400                 return;
401         }
402
403         EXIT;
404 } /* obdfs_delete_inode */
405
406
407 static int obdfs_notify_change(struct dentry *de, struct iattr *attr)
408 {
409         struct inode *inode = de->d_inode;
410         struct obdo *oa;
411         int err;
412
413         ENTRY;
414         if (IOPS(inode, setattr) == NULL) {
415                 printk(KERN_ERR __FUNCTION__ ": no setattr method!\n");
416                 EXIT;
417                 return -EIO;
418         }
419         oa = obdo_alloc();
420         if ( !oa ) {
421                 printk(__FUNCTION__ ": obdo_alloc failed\n");
422                 return -ENOMEM;
423         }
424
425         oa->o_id = inode->i_ino;
426         obdo_from_iattr(oa, attr);
427         err = IOPS(inode, setattr)(IID(inode), oa);
428
429         if ( err ) {
430                 printk(__FUNCTION__ ": obd_setattr fails (%d)\n", err);
431                 EXIT;
432         } else {
433                 /* Copy back attributes from oa, as there may have been
434                  * changes at the target (e.g. obdo becomes a redirector
435                  * in the snapshot layer).
436                  */
437                 obdfs_to_inode(inode, oa);
438                 EXIT;
439         }
440
441         obdo_free(oa);
442         return err;
443 } /* obdfs_notify_change */
444
445
446 static int obdfs_statfs(struct super_block *sb, struct statfs *buf, 
447                        int bufsize)
448 {
449         struct statfs tmp;
450         int err;
451
452         ENTRY;
453
454         err = OPS(sb,statfs)(ID(sb), &tmp);
455         if ( err ) { 
456                 printk(__FUNCTION__ ": obd_statfs fails (%d)\n", err);
457                 return err;
458         }
459         copy_to_user(buf, &tmp, (bufsize<sizeof(tmp)) ? bufsize : sizeof(tmp));
460
461         EXIT;
462
463         return err; 
464 }
465
466 /* exported operations */
467 struct super_operations obdfs_super_operations =
468 {
469         obdfs_read_inode,       /* read_inode */
470         obdfs_write_inode,      /* write_inode */
471         obdfs_put_inode,        /* put_inode */
472         obdfs_delete_inode,     /* delete_inode */
473         obdfs_notify_change,    /* notify_change */
474         obdfs_put_super,        /* put_super */
475         NULL,                   /* write_super */
476         obdfs_statfs,           /* statfs */
477         NULL                    /* remount_fs */
478 };
479
480 struct file_system_type obdfs_fs_type = {
481    "obdfs", 0, obdfs_read_super, NULL
482 };
483
484 int init_obdfs(void)
485 {
486         int err;
487
488         printk(KERN_INFO "OBDFS v0.1, braam@stelias.com\n");
489
490         obdfs_sysctl_init();
491
492         INIT_LIST_HEAD(&obdfs_super_list);
493         err = obdfs_init_pgrqcache();
494         if (err)
495                 return err;
496
497         obdfs_flushd_init();
498         return register_filesystem(&obdfs_fs_type);
499 }
500
501
502 #ifdef MODULE
503 int init_module(void)
504 {
505         return init_obdfs();
506 }
507
508 void cleanup_module(void)
509 {
510         ENTRY;
511
512         obdfs_flushd_cleanup();
513         obdfs_sysctl_clean();
514         obdfs_cleanup_pgrqcache();
515         unregister_filesystem(&obdfs_fs_type);
516         CDEBUG(D_MALLOC, "OBDFS mem used %ld\n", obd_memory);
517         EXIT;
518 }
519
520 #endif