Whamcloud - gitweb
current branches now use lnet from HEAD
[fs/lustre-release.git] / lustre / snapfs / super.c
1 /*
2  *  snap_current
3  *
4  *  Copyright (C) 1998 Peter J. Braam
5  *  Copyright (C) 2000 Stelias Computing, Inc.
6  *  Copyright (C) 2000 Red Hat, Inc.
7  *  Copyright (C) 2000 Mountain View Data, Inc.
8  *
9  *  Author: Peter J. Braam <braam@mountainviewdata.com>
10  */
11 #define DEBUG_SUBSYSTEM S_SNAP
12
13 #include <linux/module.h>
14 #include <linux/kmod.h>
15 #include <linux/init.h>
16 #include <linux/fs.h>
17 #include <linux/slab.h>
18 #include <linux/string.h>
19 #include <linux/loop.h>
20 #include <linux/jbd.h>
21 #include <linux/ext3_fs.h>
22 #include <linux/snap.h>
23 #include <linux/errno.h>
24 #include "snapfs_internal.h" 
25
26
27 #ifdef SNAP_DEBUG
28 unsigned int snap_debug_failcode = 0;
29 #endif
30
31 extern struct snap_cache *snap_init_cache(void);
32 extern inline void snap_cache_add(struct snap_cache *, kdev_t);
33 extern inline void snap_init_cache_hash(void);
34
35 extern int snap_get_index_from_name (int tableno, char *name);
36
37
38 extern struct snapshot_operations ext3_snap_operations;
39 extern struct journal_ops snap_ext3_journal_ops;
40                                                                                                                                                                                                      
41 static void put_filesystem(struct file_system_type *fs)
42 {
43         if (fs->owner)
44                 __MOD_DEC_USE_COUNT(fs->owner);
45 }
46
47 static struct vfsmount* get_vfsmount(struct super_block *sb)
48 {
49         struct vfsmount *rootmnt, *mnt, *ret = NULL;
50         struct list_head *end, *list;
51
52         rootmnt = mntget(current->fs->rootmnt);
53         end = list = &rootmnt->mnt_list;
54         do {
55                 mnt = list_entry(list, struct vfsmount, mnt_list);
56                 if (mnt->mnt_sb == sb) {
57                         ret = mnt;
58                         break;
59                 }
60                 list = list->next;
61         } while (end != list);
62         mntput(current->fs->rootmnt);
63         return ret;
64 }
65
66 void get_snap_current_mnt(struct super_block *sb)
67 {
68         struct vfsmount *mnt;
69
70         mnt = get_vfsmount(sb);
71         if (mnt) 
72                 mntget(mnt);
73 }
74 void put_snap_current_mnt(struct super_block *sb)
75 {
76         struct vfsmount *mnt;
77
78         mnt = get_vfsmount(sb);
79         if (mnt) 
80                 mntput(mnt);
81 }
82
83 /* In get_opt we get options in opt, value in opt_value
84  * we must remember to free opt and opt_value*/
85 static char * snapfs_options(char *options, char **cache_type, 
86                              char **cow_type, char **snaptable)
87 {
88         struct option *opt_value;
89         char *pos;
90         
91         while (!(get_opt(&opt_value, &pos))) {                  
92                 if (!strcmp(opt_value->opt, "cache_type")) {
93                         if (cache_type != NULL)
94                                 *cache_type = opt_value->value;
95                 } else if (!strcmp(opt_value->opt, "cow_type")) {
96                         if (cow_type != NULL)
97                                 *cow_type = opt_value->value;
98                 } else if (!strcmp(opt_value->opt, "snap_table")) {
99                         if (snaptable != NULL)
100                                 *snaptable = opt_value->value;
101                 } else {
102                         break;
103                 }
104         }
105         if (!*cache_type && cache_type) 
106                 *cache_type = "ext3"; 
107         if (!*cow_type && cow_type) 
108                 *cow_type = "block";
109         if (!*snaptable && snaptable)
110                 *snaptable = "0";
111         return pos;
112 }
113 int snapfs_remount(struct super_block * sb, int *flags, char *data)
114 {
115         struct super_operations *sops;
116         struct snap_cache *cache = NULL;
117         char *snapno = NULL, *pos = NULL;
118         char *cache_data = NULL;
119         int err = 0;
120
121         ENTRY;
122         CDEBUG(D_SUPER, "remount opts: %s\n", data ? (char *)data : "(none)");
123
124         if ((err = init_option(data))) {
125                 GOTO(out_err, 0);       
126         }
127         cache = snap_find_cache(sb->s_dev);
128         if (!cache) {
129                 CERROR("cannot find cache on remount\n");
130                 GOTO(out_err, err = -ENODEV);
131         }
132
133         /* If an option has not yet been set, we allow it to be set on
134          * remount.  If an option already has a value, we pass NULL for
135          * the option pointer, which means that the snapfs option
136          * will be parsed but discarded.
137          */
138         cache_data = snapfs_options(data, NULL, NULL, &snapno);
139
140         CDEBUG(D_SUPER, "cache_data at %p is: %s\n", cache_data, cache_data); 
141         sops = filter_c2csops(cache->cache_filter);
142         if (sops->remount_fs) 
143                 err = sops->remount_fs(sb, flags, pos);
144 out_err:
145         cleanup_option();
146         RETURN(err);
147 }
148 /*
149  * snapfs super block read.
150  *
151  * Allocate a struct snap_cache, determine the underlying fs type,
152  * read the underlying fs superblock, save the underlying fs ops,
153  * and then replace them with snapfs ops.
154  *
155  * Remove the snapfs options before passing to underlying fs.
156  */
157 struct super_block *
158 snapfs_read_super (
159         struct super_block *sb,
160         void *data,
161         int silent)
162 {
163         struct file_system_type *fstype;
164         struct snap_cache *cache = NULL;
165         char *cache_type = NULL, *cow_type = NULL;
166         char *snapno = NULL, *cache_data = NULL;
167         int tableno, rc = 0;
168
169         ENTRY;
170
171         init_option(data);
172         cache_data = snapfs_options(data, &cache_type, &cow_type, &snapno);
173         /* set up the cache */
174         cache = snap_init_cache();
175         if ( !cache ) {
176                 CERROR("snapfs_read_super: failure allocating cache.\n");
177                 GOTO(out_err, rc = -EINVAL);
178         }
179         /*get cache and cache filter type */    
180         fstype = get_fs_type((const char *)cache_type);
181
182         if ( !fstype || !fstype->read_super) {
183                 CERROR("Unrecognized cache type %s \n", cache_type);
184                 GOTO(out_err, rc = -EINVAL);
185         }
186         cache->cache_filter = filter_get_filter_fs((const char *)cache_type); 
187         if (!cache->cache_filter) {
188                 CERROR("Unrecognized cache type %s \n", cache_type);
189                 GOTO(out_err, rc = -EINVAL);
190         }
191
192         /*
193          * Read the underlying file system superblock - ext2, ext3, reiser.
194          * This performs the underlying mount operation. The snapfs options
195          * have been removed from 'cache_data'.
196          *
197          * Note: It's assumed that sb is always returned.
198          */
199         if (fstype->read_super(sb, cache_data, silent) != sb) {
200                 CERROR("snapfs: cache mount failure.\n");
201                 GOTO(out_err, rc = -EINVAL);
202         }
203         /*
204          * We now know the dev of the cache: hash the cache.
205          *
206          * 'cache' is the struct snap_cache allocated for this
207          * snapfs mount.
208          */
209         snap_cache_add(cache, sb->s_dev);
210
211         tableno = simple_strtoul(snapno, NULL, 0);
212         cache->cache_snap_tableno = tableno;
213         CDEBUG(D_SUPER, "get tableno %d\n", cache->cache_snap_tableno);
214         
215         /*
216          * make sure we have our own super operations
217          *
218          * Initialize or re-initialize the cache->cache_ops shared
219          * struct snap_ops structure set based on the underlying
220          * file system type.
221          */
222         filter_setup_super_ops(cache->cache_filter, sb->s_op,
223                                &currentfs_super_ops);
224         sb->s_op = filter_c2usops(cache->cache_filter); 
225         /*
226          * Save pointers in the snap_cache structure to the
227          * snapfs and underlying file system superblocks.
228          */
229         cache->cache_sb = sb; /* Underlying file system superblock. */
230
231         /* set up snapshot ops, handle COMPAT_FEATUREs */
232         if( 0 ){
233         }
234         else if (strcmp (cache_type,"ext3") == 0 || !cache_type){
235                 cache->cache_type = FILTER_FS_EXT3;
236                 filter_setup_snapshot_ops(cache->cache_filter,
237                                         &ext3_snap_operations);
238                 filter_setup_journal_ops(cache->cache_filter,
239                                         &snap_ext3_journal_ops);
240                 if( !EXT3_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_SNAPFS) ){
241                         if( strcmp(cow_type, "block")==0 ){
242                                 sb->u.ext3_sb.s_es->s_feature_compat |=
243                                         cpu_to_le32(EXT3_FEATURE_COMPAT_BLOCKCOW);
244                         }
245                 }
246                 sb->u.ext3_sb.s_last_cowed_pri_ino = 0;
247                 sb->u.ext3_sb.s_first_cowed_pri_ino = 0;
248         }
249         /* now get our own directory operations */
250         if ( sb->s_root && sb->s_root->d_inode ) {
251                 filter_setup_dir_ops(cache->cache_filter, 
252                                      sb->s_root->d_inode,
253                                      &currentfs_dir_iops, &currentfs_dir_fops);
254                 sb->s_root->d_inode->i_op =filter_c2udiops(cache->cache_filter);
255
256                 CDEBUG(D_SUPER, "lookup at %p\n", 
257                        sb->s_root->d_inode->i_op->lookup);
258                 /* XXX is this needed ?? ext3 do not have dentry operations*/
259                 filter_setup_dentry_ops(cache->cache_filter, 
260                                         sb->s_root->d_op, 
261                                         &currentfs_dentry_ops);
262                 sb->s_root->d_op = filter_c2udops(cache->cache_filter);
263                 init_filter_data(sb->s_root->d_inode, 0); 
264         }
265         /*
266          * Save a pointer to the snap_cache structure in the
267          * "snap_current" superblock.
268          */
269         (struct snap_cache *) sb->u.generic_sbp = cache;
270
271         snapfs_read_snaptable(cache, tableno);
272         
273         CDEBUG(D_SUPER, "sb %lx, sb->u.generic_sbp: %lx\n",
274                 (ulong) sb, (ulong) sb->u.generic_sbp);
275 out_err:
276         cleanup_option();
277         /* Inc in get_fs_type, Dec in put_fs_type*/
278         if (fstype)
279                 put_filesystem(fstype);
280         if (rc) 
281                 return NULL;
282         return sb; 
283 }
284
285 static DECLARE_FSTYPE_DEV(snapfs_current_type, 
286                           "snap_current", snapfs_read_super);
287
288 /* Find the options for the clone. These consist of a cache device
289    and an index in the snaptable associated with that device. 
290 */
291 static char *clonefs_options(char *options, char **devstr, char **namestr)
292 {
293         struct option *opt_value = NULL;
294         char *pos;
295         
296         while (!(get_opt(&opt_value, &pos))) {                  
297                 if (!strcmp(opt_value->opt, "dev")) {
298                         if (devstr != NULL)
299                                 *devstr = opt_value->value;
300                 } else if (!strcmp(opt_value->opt, "name")) {
301                         if (namestr != NULL)
302                                 *namestr = opt_value->value;
303                 } else {
304                         break;
305                 }
306         }
307         return pos;
308 }
309 static int snap_cache_lookup_ino_cb(struct snap_cache *cache, void *in, unsigned long *out)
310 {
311         ino_t ino = *((unsigned long*)in);
312
313         if (cache) {
314                 struct super_block *sb = cache->cache_sb;
315                 kdev_t dev = sb->s_dev;
316
317                 if (MAJOR(dev) != LOOP_MAJOR) 
318                         return 0;
319                 if (sb->s_bdev->bd_op && sb->s_bdev->bd_op->ioctl) {
320                         struct inode *inode = sb->s_bdev->bd_inode;
321                         struct loop_info loop_info;
322
323                         sb->s_bdev->bd_op->ioctl(inode, NULL, LOOP_GET_INFO, 
324                                                  (unsigned long)&loop_info);
325                         
326                         if(loop_info.lo_inode == ino) {
327                                 *out = sb->s_dev; 
328                                 return 1;
329                         }
330                 }
331         }
332         return 0;       
333 }
334 static int snapfs_path2dev(char *dev_path, kdev_t *dev)
335 {
336         struct dentry *dentry;
337         struct nameidata nd;
338         int error = 0;
339         
340         if (path_init(dev_path, LOOKUP_FOLLOW, &nd)) {
341                 error = path_walk(dev_path, &nd);
342                 if (error)
343                         return error;
344         } else
345                 return -EINVAL;
346
347         dentry = nd.dentry;
348
349         if (!dentry->d_inode || is_bad_inode(dentry->d_inode) || 
350             (!S_ISBLK(dentry->d_inode->i_mode) && 
351              !S_ISREG(dentry->d_inode->i_mode))){
352                 path_release(&nd);
353                 return -ENODEV;
354         }
355         if (S_ISBLK(dentry->d_inode->i_mode)) {
356                 *dev = kdev_t_to_nr(dentry->d_inode->i_rdev);
357         } else {
358                 /*here we must walk through all the snap cache to 
359                  *find the loop device */
360                 kdev_t tmp;
361
362                 if (snap_cache_process(snap_cache_lookup_ino_cb,
363                                        &dentry->d_inode->i_ino, 
364                                        (unsigned long*)&tmp))
365                         return -EINVAL;
366                 *dev = tmp;
367         }
368         path_release(&nd);
369         return 0;
370 }
371
372 extern struct super_operations clone_super_ops;
373 /*
374  * We always need to remove the snapfs options before passing
375  * to bottom FS.
376  */
377 struct super_block *
378 clone_read_super(
379         struct super_block *sb,
380         void *data,
381         int silent)
382 {
383         struct snap_clone_info *clone_sb;
384         struct snap_cache *snap_cache = NULL;
385         struct inode *root_inode = NULL;
386         char *devstr = NULL, *namestr = NULL;
387         char *cache_data;
388         kdev_t dev;
389         int index;
390         ino_t root_ino;
391         int err = 0;
392
393         ENTRY;
394
395         CDEBUG(D_SUPER, "mount opts: %s\n", data ? (char *)data : "(none)");
396         
397         init_option(data);
398         /* read and validate options */
399         cache_data = clonefs_options(data, &devstr, &namestr);
400         if (*cache_data) {
401                 CERROR("clonefs: invalid mount option %s\n", (char*)data);
402                 GOTO(out_err, err=-EINVAL);
403         }
404         if (!namestr || !devstr) {
405                 CERROR("snapfs: mount options name and dev mandatory\n");
406                 GOTO(out_err, err=-EINVAL);
407         }
408
409         err = snapfs_path2dev(devstr, &dev);
410         if ( err ) {
411                 CERROR("snap: incorrect device option %s\n", devstr);
412                 GOTO(out_err, err=-EINVAL);
413         }
414         
415         snap_cache = snap_find_cache(dev);
416         if ( !snap_cache ) {
417                 CERROR("snap: incorrect device option %s\n", devstr);
418                 GOTO(out_err, err=-EINVAL);
419         }
420
421         index = snap_get_index_from_name (snap_cache->cache_snap_tableno, 
422                                         namestr);
423         CDEBUG(D_SUPER, "tableno %d, name %s, get index %d\n", 
424                         snap_cache->cache_snap_tableno, namestr, index);
425
426         if(index < 0 ) {
427                 CERROR("No valid index for name %s passed to mount\n",namestr); 
428                 GOTO(out_err, err=-EINVAL);
429         }
430
431         /*
432          * Force clone fs to be read-only.
433          *
434          * XXX - Is there a way to change the mount options too so
435          * the fs is listed as RO by mount?
436          */
437         sb->s_flags |= MS_RDONLY;
438
439         /* set up the super block */
440         clone_sb = (struct snap_clone_info *)&sb->u.generic_sbp;
441         list_add(&clone_sb->clone_list_entry, &snap_cache->cache_clone_list);
442         clone_sb->clone_cache = snap_cache;
443         clone_sb->clone_index = index;
444         sb->s_op = &clone_super_ops;
445
446         root_ino = snap_cache->cache_sb->s_root->d_inode->i_ino;
447         root_inode = iget(sb, root_ino);
448
449         CDEBUG(D_SUPER, "readinode %p, root ino %ld, root inode at %p\n",
450                sb->s_op->read_inode, root_ino, root_inode);
451
452         sb->s_root = d_alloc_root(root_inode);
453         
454         if (!sb->s_root) {
455                 list_del(&clone_sb->clone_list_entry);
456                 GOTO(out_err, err=-EINVAL);
457         }
458         dget(snap_cache->cache_sb->s_root);
459
460         CDEBUG(D_SUPER, "sb %lx, &sb->u.generic_sbp: %lx\n",
461                 (ulong) sb, (ulong) &sb->u.generic_sbp);
462         
463         get_snap_current_mnt(snap_cache->cache_sb);
464  out_err:
465         cleanup_option();
466         if (err)
467                 return NULL;
468         return sb;
469 }
470
471 static DECLARE_FSTYPE(snapfs_clone_type, "snap_clone", clone_read_super, 0);
472
473 int init_snapfs(void)
474 {
475         int status;
476
477         snap_init_cache_hash();
478         init_filter_info_cache();
479
480         status = register_filesystem(&snapfs_current_type);
481         if (status) {
482                 CERROR("snapfs: failed in register current filesystem!\n");
483         }
484
485         status = register_filesystem(&snapfs_clone_type);
486         if (status) {
487                 unregister_filesystem(&snapfs_current_type);
488                 CERROR("snapfs: failed in register clone filesystem!\n");
489         }
490
491         return status;
492 }
493
494
495
496 int cleanup_snapfs(void)
497 {
498         int err;
499
500         ENTRY;
501
502         cleanup_filter_info_cache();
503         err = unregister_filesystem(&snapfs_clone_type);
504         if ( err ) {
505                 CERROR("snapfs: failed to unregister clone filesystem\n");
506         }
507         err = unregister_filesystem(&snapfs_current_type);
508         if ( err ) {
509                 CERROR("snapfs: failed to unregister filesystem\n");
510         }
511         return 0;
512 }