Whamcloud - gitweb
263029c8881ce40aeb553835d98ceb14ad93ac5a
[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("ext2") &&
131              memcmp(cache_type, "ext2", strlen("ext2")) == 0 ) {
132                 ops = &filter_oppar[FILTER_FS_EXT2];
133                 CDEBUG(D_SUPER, "ops at %p\n", ops);
134         }
135
136         if ( strlen(cache_type) == strlen("ext3") &&
137              memcmp(cache_type, "ext3", strlen("ext3")) == 0 ) {
138                 ops = &filter_oppar[FILTER_FS_EXT3];
139                 CDEBUG(D_SUPER, "ops at %p\n", ops);
140         }
141         if ( strlen(cache_type) == strlen("reiser") &&
142              memcmp(cache_type, "reiser", strlen("reiser")) == 0 ) {
143                 ops = &filter_oppar[FILTER_FS_REISER];
144                 CDEBUG(D_SUPER, "ops at %p\n", ops);
145         }
146
147         if (ops == NULL) {
148                 CERROR("prepare to die: unrecognized cache type for Filter\n");
149         }
150         EXIT;
151         return ops;
152 }
153
154 /*
155  *  Frobnicate the InterMezzo/SnapFS operations
156  *    this establishes the link between the InterMezzo/SnapFS file system
157  *    and the underlying file system used for the cache.
158  */
159
160 void filter_setup_super_ops(struct filter_fs *cache, 
161                             struct super_operations *cache_sops, 
162                             struct super_operations *filter_sops)
163 {
164         /* Get ptr to the shared struct snapfs_ops structure. */
165         struct filter_ops *uops = &cache->o_fops;
166         /* Get ptr to the shared struct cache_ops structure. */
167         struct cache_ops *caops = &cache->o_caops;
168
169         ENTRY;
170
171         if ( cache->o_flags & FILTER_DID_SUPER_OPS ) {
172                 EXIT;
173                 return;
174         }
175         cache->o_flags |= FILTER_DID_SUPER_OPS;
176
177         /* Set the cache superblock operations to point to the
178            superblock operations of the underlying file system.  */
179         caops->cache_sops = cache_sops;
180         /*
181          * Copy the cache (real fs) superblock ops to the "filter"
182          * superblock ops as defaults. Some will be changed below
183          */
184         memcpy(&uops->filter_sops, cache_sops, sizeof(*cache_sops));
185
186         /*  now overwrite with filtering ops */
187         if (cache_sops->put_super && uops->filter_sops.put_super) { 
188                 uops->filter_sops.put_super = filter_sops->put_super;
189         }
190         if (cache_sops->read_inode && uops->filter_sops.read_inode) {
191                 uops->filter_sops.read_inode = filter_sops->read_inode;
192                 CDEBUG(D_INODE, "setting filter_read_inode, cache_ops %p, cache %p, ri at %p\n",
193                       cache, cache, uops->filter_sops.read_inode);
194         }
195         uops->filter_sops.clear_inode = filter_sops->clear_inode;
196         
197         EXIT;
198 }
199
200 void filter_setup_dir_ops(struct filter_fs *cache, 
201                           struct inode     *inode,
202                           struct inode_operations *filter_iops, 
203                           struct file_operations *filter_fops)
204 {
205         struct inode_operations *u_iops;
206         struct file_operations *u_fops;
207         
208         ENTRY;
209
210         if (cache->o_flags & FILTER_DID_DIR_OPS) {
211                 EXIT;
212                 return;
213         }
214         cache->o_flags |= FILTER_DID_DIR_OPS;
215
216         /* steal the old ops */
217         cache->o_caops.cache_dir_iops = inode->i_op;
218         cache->o_caops.cache_dir_fops = inode->i_fop;
219         
220         u_iops = filter_c2udiops(cache);
221         u_fops = filter_c2udfops(cache); 
222         
223         /* setup our dir iops and fops: copy and modify */
224         memcpy(u_iops, inode->i_op, sizeof(struct inode_operations));
225         memcpy(u_fops, inode->i_fop, sizeof(struct file_operations));
226
227         /* methods that filter if cache filesystem has these ops */
228         if (filter_iops) {
229                 struct inode_operations *cache_iops = inode->i_op;
230                 
231                 if (cache_iops->lookup && filter_iops->lookup) 
232                         u_iops->lookup = filter_iops->lookup;
233                 if (cache_iops->create && filter_iops->create)
234                         u_iops->create = filter_iops->create;
235                 if (cache_iops->link && filter_iops->link)
236                         u_iops->link = filter_iops->link;
237                 if (cache_iops->unlink && filter_iops->unlink)
238                         u_iops->unlink = filter_iops->unlink;
239                 if (cache_iops->mkdir && filter_iops->mkdir)
240                         u_iops->mkdir = filter_iops->mkdir;
241                 if (cache_iops->rmdir && filter_iops->rmdir)
242                         u_iops->rmdir = filter_iops->rmdir;
243                 if (cache_iops->symlink && filter_iops->symlink)
244                         u_iops->symlink = filter_iops->symlink;
245                 if (cache_iops->rename && filter_iops->rename)
246                         u_iops->rename = filter_iops->rename;
247                 if (cache_iops->mknod && filter_iops->mknod)
248                         u_iops->mknod = filter_iops->mknod;
249                 if (cache_iops->permission && filter_iops->permission)
250                         u_iops->permission = filter_iops->permission;
251         }
252         /* copy dir fops */
253         
254         if (filter_fops) {
255                 struct file_operations *cache_fops = inode->i_fop;
256                 
257                 if(cache_fops->readdir && filter_fops->readdir)
258                         u_fops->readdir = filter_fops->readdir;
259         }
260         EXIT;
261 }
262
263 void filter_setup_file_ops(struct filter_fs        *cache, 
264                            struct inode            *inode,
265                            struct inode_operations *filter_iops,
266                            struct file_operations  *filter_fops,
267                            struct address_space_operations *filter_aops)
268 {
269         struct inode_operations *u_iops;
270         struct file_operations *u_fops;
271         struct address_space_operations *u_aops;
272         ENTRY;
273
274         if (cache->o_flags & FILTER_DID_FILE_OPS || !inode ) { 
275                 EXIT;
276                 return;
277         }
278
279         cache->o_flags |= FILTER_DID_FILE_OPS;
280
281         /* steal the old ops */
282         cache->o_caops.cache_file_iops = inode->i_op; 
283         cache->o_caops.cache_file_fops = inode->i_fop;
284
285         /* abbreviate */
286         u_iops = filter_c2ufiops(cache); 
287         u_fops = filter_c2uffops(cache); 
288         u_aops = filter_c2ufaops(cache); 
289                 
290         /* setup our dir iops: copy and modify */
291         memcpy(u_iops, inode->i_op, sizeof(struct inode_operations));
292         memcpy(u_fops, inode->i_fop, sizeof(struct file_operations));
293
294         if (inode->i_mapping && inode->i_mapping->a_ops) {
295                 cache->o_caops.cache_file_aops = inode->i_mapping->a_ops; 
296                 memcpy(u_aops, inode->i_mapping->a_ops, 
297                        sizeof(struct address_space_operations));
298         }
299         if (filter_iops) {
300                 if (filter_iops->revalidate)
301                         u_iops->revalidate = filter_iops->revalidate;
302         }
303         if (filter_fops) {
304                 if (filter_fops->read)
305                         u_fops->read = filter_fops->read;
306         }
307         if (filter_aops) {
308                 if (filter_aops->readpage)
309                         u_aops->readpage = filter_aops->readpage;
310         }
311         EXIT;
312 }
313
314 void filter_setup_symlink_ops(struct filter_fs *cache, 
315                               struct inode *inode,
316                               struct inode_operations *filter_iops, 
317                               struct file_operations *filter_fops)
318 {
319         struct inode_operations *u_iops;
320         struct file_operations *u_fops;
321         
322         ENTRY;
323
324         if (cache->o_flags & FILTER_DID_SYMLINK_OPS || !inode ) {
325                 EXIT;
326                 return;
327         }
328         cache->o_flags |= FILTER_DID_SYMLINK_OPS;
329
330         /* steal the old ops */
331         cache->o_caops.cache_sym_iops = inode->i_op;
332         cache->o_caops.cache_sym_fops = inode->i_fop; 
333
334         /* abbreviate */
335         u_iops = filter_c2usiops(cache); 
336         u_fops = filter_c2usfops(cache); 
337
338         /* setup our dir iops: copy and modify */
339         memcpy(u_iops, inode->i_op, sizeof(struct inode_operations));
340         memcpy(u_fops, inode->i_fop, sizeof(struct file_operations));
341         if (filter_iops) {
342                 struct inode_operations *cache_iops = inode->i_op; 
343                 if (cache_iops->readlink && filter_iops->readlink) 
344                         u_iops->readlink = filter_iops->readlink;
345                 if (cache_iops->follow_link && filter_iops->follow_link)
346                         u_iops->follow_link = filter_iops->follow_link;
347         }
348         EXIT;
349 }
350
351 void filter_setup_dentry_ops(struct filter_fs *cache,
352                              struct dentry_operations *cache_dop,
353                              struct dentry_operations *filter_dop)
354 {
355         if ( cache->o_flags & FILTER_DID_DENTRY_OPS ) {
356                 EXIT;
357                 return;
358         }
359         cache->o_flags |= FILTER_DID_DENTRY_OPS;
360
361         cache->o_caops.cache_dentry_ops = cache_dop;
362         memcpy(&cache->o_fops.filter_dentry_ops,
363                filter_dop, sizeof(*filter_dop));
364         
365         if (cache_dop &&  cache_dop != filter_dop && cache_dop->d_revalidate){
366                 CWARN("filter overriding revalidation!\n");
367         }
368         EXIT;
369         return;
370 }
371 /* snapfs : for snapshot operations */
372 void filter_setup_snapshot_ops (struct filter_fs *cache, 
373                                 struct snapshot_operations *cache_snapops)
374 {
375         ENTRY;
376
377         if ( cache->o_flags & FILTER_DID_SNAPSHOT_OPS ) {
378                 EXIT;
379                 return;
380         }
381         cache->o_flags |= FILTER_DID_SNAPSHOT_OPS;
382
383         cache->o_snapops = cache_snapops;
384
385         EXIT;
386 }
387
388 void filter_setup_journal_ops (struct filter_fs *cache,
389                                struct journal_ops *cache_journal_ops)
390 {
391         ENTRY;
392
393         if( cache->o_flags & FILTER_DID_JOURNAL_OPS ){
394                 EXIT;
395                 return;
396         }
397         cache->o_flags |= FILTER_DID_JOURNAL_OPS;
398
399         cache->o_trops = cache_journal_ops;
400
401         EXIT;
402 }