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