Whamcloud - gitweb
add snapfs to cvs
[fs/lustre-release.git] / lustre / snapfs / filter.c
1 /*
2  *
3  *
4  *  Copyright (C) 2000 Stelias Computing, Inc.
5  *  Copyright (C) 2000 Red Hat, Inc.
6  *  Copyright (C) 2000 Mountain View Data, Inc.
7  *
8  *
9  */
10
11 #include <stdarg.h>
12
13 #include <asm/bitops.h>
14 #include <asm/uaccess.h>
15 #include <asm/system.h>
16
17 #include <linux/errno.h>
18 #include <linux/fs.h>
19 #include <linux/ext2_fs.h>
20 #include <linux/malloc.h>
21 #include <linux/vmalloc.h>
22 #include <linux/sched.h>
23 #include <linux/stat.h>
24 #include <linux/string.h>
25 #include <linux/locks.h>
26 #include <linux/blkdev.h>
27 #include <linux/init.h>
28 #define __NO_VERSION__
29 #include <linux/module.h>
30
31 #include <linux/filter.h>
32
33 int filter_print_entry = 1;
34 int filter_debug = 0xfffffff;
35 /*
36  * The function in this file are responsible for setting up the 
37  * correct methods layered file systems like InterMezzo and SnapFS
38  */
39
40
41 static struct filter_fs filter_oppar[FILTER_FS_TYPES];
42
43 /* get to the upper methods (intermezzo, snapfs) */
44 inline struct super_operations *filter_c2usops(struct filter_fs *cache)
45 {
46         return &cache->o_fops.filter_sops;
47 }
48
49 inline struct inode_operations *filter_c2udiops(struct filter_fs *cache)
50 {
51         return &cache->o_fops.filter_dir_iops;
52 }
53
54 inline struct inode_operations *filter_c2ufiops(struct filter_fs *cache)
55 {
56         return &cache->o_fops.filter_file_iops;
57 }
58
59 inline struct inode_operations *filter_c2usiops(struct filter_fs *cache)
60 {
61         return &cache->o_fops.filter_sym_iops;
62 }
63
64 inline struct file_operations *filter_c2udfops(struct filter_fs *cache)
65 {
66         return &cache->o_fops.filter_dir_fops;
67 }
68
69 inline struct file_operations *filter_c2uffops(struct filter_fs *cache)
70 {
71         return &cache->o_fops.filter_file_fops;
72 }
73
74 inline struct file_operations *filter_c2usfops(struct filter_fs *cache)
75 {
76         return &cache->o_fops.filter_sym_fops;
77 }
78
79 inline struct dentry_operations *filter_c2udops(struct filter_fs *cache)
80 {
81         return &cache->o_fops.filter_dentry_ops;
82 }
83
84 /* get to the cache (lower) methods */
85 inline struct super_operations *filter_c2csops(struct filter_fs *cache)
86 {
87         return cache->o_caops.cache_sops;
88 }
89
90 inline struct inode_operations *filter_c2cdiops(struct filter_fs *cache)
91 {
92         return cache->o_caops.cache_dir_iops;
93 }
94
95 inline struct inode_operations *filter_c2cfiops(struct filter_fs *cache)
96 {
97         return cache->o_caops.cache_file_iops;
98 }
99
100 inline struct inode_operations *filter_c2csiops(struct filter_fs *cache)
101 {
102         return cache->o_caops.cache_sym_iops;
103 }
104
105 inline struct file_operations *filter_c2cdfops(struct filter_fs *cache)
106 {
107         return cache->o_caops.cache_dir_fops;
108 }
109
110 inline struct file_operations *filter_c2cffops(struct filter_fs *cache)
111 {
112         return cache->o_caops.cache_file_fops;
113 }
114
115 inline struct file_operations *filter_c2csfops(struct filter_fs *cache)
116 {
117         return cache->o_caops.cache_sym_fops;
118 }
119
120 inline struct dentry_operations *filter_c2cdops(struct filter_fs *cache)
121 {
122         return cache->o_caops.cache_dentry_ops;
123 }
124 /* snapfs: for snapshot operations */
125 inline struct snapshot_operations *filter_c2csnapops(struct filter_fs *cache)
126 {
127         return cache->o_snapops;
128 }
129
130 /* find the cache for this FS */
131 struct filter_fs *filter_get_filter_fs(const char *cache_type)
132 {
133         struct filter_fs *ops = NULL;
134         FENTRY;
135
136         if ( strlen(cache_type) == strlen("ext2") &&
137              memcmp(cache_type, "ext2", strlen("ext2")) == 0 ) {
138                 ops = &filter_oppar[FILTER_FS_EXT2];
139                 FDEBUG(D_SUPER, "ops at %p\n", ops);
140         }
141
142         if ( strlen(cache_type) == strlen("ext3") &&
143              memcmp(cache_type, "ext3", strlen("ext3")) == 0 ) {
144                 ops = &filter_oppar[FILTER_FS_EXT3];
145                 FDEBUG(D_SUPER, "ops at %p\n", ops);
146         }
147         if ( strlen(cache_type) == strlen("reiser") &&
148              memcmp(cache_type, "reiser", strlen("reiser")) == 0 ) {
149                 ops = &filter_oppar[FILTER_FS_REISER];
150                 FDEBUG(D_SUPER, "ops at %p\n", ops);
151         }
152
153         if (ops == NULL) {
154                 printk("prepare to die: unrecognized cache type for Filter\n");
155         }
156         FEXIT;
157         return ops;
158 }
159
160
161 /*
162  *  Frobnicate the InterMezzo/SnapFS operations
163  *    this establishes the link between the InterMezzo/SnapFS file system
164  *    and the underlying file system used for the cache.
165  */
166
167 void filter_setup_super_ops(struct filter_fs *cache, struct super_operations *cache_sops, struct super_operations *filter_sops)
168 {
169         /* Get ptr to the shared struct snapfs_ops structure. */
170         struct filter_ops *uops = &cache->o_fops;
171         /* Get ptr to the shared struct cache_ops structure. */
172         struct cache_ops *caops = &cache->o_caops;
173
174         FENTRY;
175
176         if ( cache->o_flags & FILTER_DID_SUPER_OPS ) {
177                 FEXIT;
178                 return;
179         }
180         cache->o_flags |= FILTER_DID_SUPER_OPS;
181
182         /* Set the cache superblock operations to point to the
183            superblock operations of the underlying file system.  */
184         caops->cache_sops = cache_sops;
185
186         /*
187          * Copy the cache (real fs) superblock ops to the "filter"
188          * superblock ops as defaults. Some will be changed below
189          */
190         memcpy(&uops->filter_sops, cache_sops, sizeof(*cache_sops));
191
192         /*  now overwrite with filtering ops */
193         if (cache_sops->put_super && uops->filter_sops.put_super) { 
194                 uops->filter_sops.put_super = filter_sops->put_super;
195         }
196         if (cache_sops->read_inode && uops->filter_sops.read_inode) {
197                 uops->filter_sops.read_inode = filter_sops->read_inode;
198                 FDEBUG(D_INODE, "setting filter_read_inode, cache_ops %p, cache %p, ri at %p\n",
199                       cache, cache, uops->filter_sops.read_inode);
200         }
201         if (cache_sops->notify_change && uops->filter_sops.notify_change) 
202                 uops->filter_sops.notify_change = filter_sops->notify_change;
203         if (cache_sops->remount_fs && uops->filter_sops.remount_fs)
204                 uops->filter_sops.remount_fs = filter_sops->remount_fs;
205         FEXIT;
206 }
207
208
209 void filter_setup_dir_ops(struct filter_fs *cache, struct inode_operations *cache_iops, struct inode_operations *filter_iops)
210 {
211         struct inode_operations *u_iops;
212         struct file_operations *u_fops, *c_fops, *f_fops;
213         FENTRY;
214
215         if ( cache->o_flags & FILTER_DID_DIR_OPS ) {
216                 FEXIT;
217                 return;
218         }
219         FDEBUG(D_SUPER, "\n");
220         cache->o_flags |= FILTER_DID_DIR_OPS;
221
222         /* steal the old ops */
223         cache->o_caops.cache_dir_iops = cache_iops;
224         cache->o_caops.cache_dir_fops = 
225                 cache_iops->default_file_ops;
226
227         FDEBUG(D_SUPER, "\n");
228         /* abbreviate */
229         u_iops = &cache->o_fops.filter_dir_iops;
230
231         /* setup our dir iops: copy and modify */
232         memcpy(u_iops, cache_iops, sizeof(*cache_iops));
233         FDEBUG(D_SUPER, "\n");
234
235         /* methods that filter if cache filesystem has these ops */
236         if ( cache_iops->lookup && filter_iops->lookup ) {
237         FDEBUG(D_SUPER, "\n");
238                 u_iops->lookup = filter_iops->lookup;
239                 FDEBUG(D_SUPER, "lookup at %p\n", &filter_iops->lookup);
240         }
241         if (cache_iops->create && filter_iops->create)
242                 u_iops->create = filter_iops->create;
243         FDEBUG(D_SUPER, "\n");
244         if (cache_iops->link && filter_iops->link)
245                 u_iops->link = filter_iops->link;
246         FDEBUG(D_SUPER, "\n");
247         if (cache_iops->unlink && filter_iops->unlink)
248                 u_iops->unlink = filter_iops->unlink;
249         FDEBUG(D_SUPER, "\n");
250         if (cache_iops->mkdir && filter_iops->mkdir)
251                 u_iops->mkdir = filter_iops->mkdir;
252         FDEBUG(D_SUPER, "\n");
253         if (cache_iops->rmdir && filter_iops->rmdir)
254                 u_iops->rmdir = filter_iops->rmdir;
255         FDEBUG(D_SUPER, "\n");
256         if (cache_iops->symlink && filter_iops->symlink)
257                 u_iops->symlink = filter_iops->symlink;
258         FDEBUG(D_SUPER, "\n");
259         if (cache_iops->rename && filter_iops->rename)
260                 u_iops->rename = filter_iops->rename;
261         FDEBUG(D_SUPER, "\n");
262         if (cache_iops->mknod && filter_iops->mknod)
263                 u_iops->mknod = filter_iops->mknod;
264         FDEBUG(D_SUPER, "\n");
265         if (cache_iops->permission && filter_iops->permission)
266                 u_iops->permission = filter_iops->permission;
267
268         /* copy dir fops */
269         FDEBUG(D_SUPER, "\n");
270         u_fops = &cache->o_fops.filter_dir_fops;
271         c_fops = cache_iops->default_file_ops;
272         f_fops = filter_iops->default_file_ops;
273
274         memcpy(u_fops, c_fops, sizeof(*c_fops));
275
276         if( c_fops->readdir && f_fops->readdir )
277                 u_fops->readdir = f_fops->readdir;
278
279         /* assign */
280         FDEBUG(D_SUPER, "\n");
281         filter_c2udiops(cache)->default_file_ops = filter_c2udfops(cache);
282         FDEBUG(D_SUPER, "\n");
283
284         /* unconditional filtering operations */
285         if ( filter_iops->default_file_ops && 
286              filter_iops->default_file_ops->open ) 
287                 filter_c2udfops(cache)->open = 
288                         filter_iops->default_file_ops->open;
289
290         FEXIT;
291 }
292
293
294 void filter_setup_file_ops(struct filter_fs *cache, struct inode_operations *cache_iops, struct inode_operations *filter_iops)
295 {
296         struct inode_operations *u_iops;
297         FENTRY;
298
299         if ( cache->o_flags & FILTER_DID_FILE_OPS ) {
300                 FEXIT;
301                 return;
302         }
303         cache->o_flags |= FILTER_DID_FILE_OPS;
304
305         /* steal the old ops */
306         cache->o_caops.cache_file_iops = cache_iops;
307         cache->o_caops.cache_file_fops = 
308                 cache_iops->default_file_ops;
309
310         /* abbreviate */
311         u_iops = filter_c2ufiops(cache); 
312
313         /* setup our dir iops: copy and modify */
314         memcpy(u_iops, cache_iops, sizeof(*cache_iops));
315
316         /* copy dir fops */
317         memcpy(filter_c2uffops(cache), cache_iops->default_file_ops, 
318                sizeof(*cache_iops->default_file_ops));
319         /* assign */
320         filter_c2ufiops(cache)->default_file_ops = filter_c2uffops(cache);
321
322         /* unconditional filtering operations */
323         if (filter_iops->default_file_ops &&
324             filter_iops->default_file_ops->open ) 
325                 filter_c2uffops(cache)->open = 
326                         filter_iops->default_file_ops->open;
327         if (filter_iops->default_file_ops &&
328             filter_iops->default_file_ops->release ) 
329                 filter_c2uffops(cache)->release = 
330                         filter_iops->default_file_ops->release;
331         if (filter_iops->default_file_ops &&
332             filter_iops->default_file_ops->write ) 
333                 filter_c2uffops(cache)->write = 
334                         filter_iops->default_file_ops->write;
335
336         /* set up readpage */
337         if (filter_iops->readpage) 
338                 filter_c2ufiops(cache)->readpage = filter_iops->readpage;
339
340         FEXIT;
341 }
342
343 /* XXX in 2.3 there are "fast" and "slow" symlink ops for ext2 XXX */
344 void filter_setup_symlink_ops(struct filter_fs *cache, struct inode_operations *cache_iops, struct inode_operations *filter_iops)
345 {
346         struct inode_operations *u_iops;
347         FENTRY;
348
349         if ( cache->o_flags & FILTER_DID_SYMLINK_OPS ) {
350                 FEXIT;
351                 return;
352         }
353         cache->o_flags |= FILTER_DID_SYMLINK_OPS;
354
355         /* steal the old ops */
356         cache->o_caops.cache_sym_iops = cache_iops;
357         cache->o_caops.cache_sym_fops = 
358                 cache_iops->default_file_ops;
359
360         /* abbreviate */
361         u_iops = filter_c2usiops(cache); 
362
363         /* setup our dir iops: copy and modify */
364         memcpy(u_iops, cache_iops, sizeof(*cache_iops));
365
366         /* copy fops - careful for symlinks they might be NULL */
367         if ( cache_iops->default_file_ops ) { 
368                 memcpy(filter_c2usfops(cache), cache_iops->default_file_ops, 
369                        sizeof(*cache_iops->default_file_ops));
370         }
371
372         /* assign */
373         filter_c2usiops(cache)->default_file_ops = filter_c2usfops(cache);
374
375         if (cache_iops->readlink && filter_iops->readlink) 
376                 u_iops->readlink = filter_iops->readlink;
377         if (cache_iops->follow_link && filter_iops->follow_link)
378                 u_iops->follow_link = filter_iops->follow_link;
379
380         FEXIT;
381 }
382
383 void filter_setup_dentry_ops(struct filter_fs *cache,
384                              struct dentry_operations *cache_dop,
385                              struct dentry_operations *filter_dop)
386 {
387         if ( cache->o_flags & FILTER_DID_DENTRY_OPS ) {
388                 FEXIT;
389                 return;
390         }
391         cache->o_flags |= FILTER_DID_DENTRY_OPS;
392
393         cache->o_caops.cache_dentry_ops = cache_dop;
394         memcpy(&cache->o_fops.filter_dentry_ops,
395                filter_dop, sizeof(*filter_dop));
396         
397         if (cache_dop &&  cache_dop != filter_dop && cache_dop->d_revalidate){
398                 printk("WARNING: filter overriding revalidation!\n");
399         }
400         return;
401 }
402 /* snapfs : for snapshot operations */
403 void filter_setup_snapshot_ops (struct filter_fs *cache, 
404                                 struct snapshot_operations *cache_snapops)
405 {
406         FENTRY;
407
408         if ( cache->o_flags & FILTER_DID_SNAPSHOT_OPS ) {
409                 FEXIT;
410                 return;
411         }
412         cache->o_flags |= FILTER_DID_SNAPSHOT_OPS;
413
414         cache->o_snapops = cache_snapops;
415
416         FEXIT;
417 }
418
419 void filter_setup_journal_ops (struct filter_fs *cache,
420                                struct journal_ops *cache_journal_ops)
421 {
422         FENTRY;
423
424         if( cache->o_flags & FILTER_DID_JOURNAL_OPS ){
425                 FEXIT;
426                 return;
427         }
428         cache->o_flags |= FILTER_DID_JOURNAL_OPS;
429
430         cache->o_trops = cache_journal_ops;
431
432         FEXIT;
433 }