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