Whamcloud - gitweb
update snapfs 1. fix bug in write table_count in write snap_table 2. fixbug in repla...
[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         }
243         /* copy dir fops */
244         
245         if (filter_fops) {
246                 struct file_operations *cache_fops = inode->i_fop;
247                 
248                 if(cache_fops->readdir && filter_fops->readdir)
249                         u_fops->readdir = filter_fops->readdir;
250         }
251         EXIT;
252 }
253
254 void filter_setup_file_ops(struct filter_fs        *cache, 
255                            struct inode            *inode,
256                            struct inode_operations *filter_iops,
257                            struct file_operations  *filter_fops,
258                            struct address_space_operations *filter_aops)
259 {
260         struct inode_operations *u_iops;
261         struct file_operations *u_fops;
262         struct address_space_operations *u_aops;
263         ENTRY;
264
265         if (cache->o_flags & FILTER_DID_FILE_OPS || !inode ) { 
266                 EXIT;
267                 return;
268         }
269
270         cache->o_flags |= FILTER_DID_FILE_OPS;
271
272         /* steal the old ops */
273         cache->o_caops.cache_file_iops = inode->i_op; 
274         cache->o_caops.cache_file_fops = inode->i_fop;
275
276         /* abbreviate */
277         u_iops = filter_c2ufiops(cache); 
278         u_fops = filter_c2uffops(cache); 
279         u_aops = filter_c2ufaops(cache); 
280                 
281         /* setup our dir iops: copy and modify */
282         memcpy(u_iops, inode->i_op, sizeof(struct inode_operations));
283         memcpy(u_fops, inode->i_fop, sizeof(struct file_operations));
284
285         if (inode->i_mapping && inode->i_mapping->a_ops) {
286                 cache->o_caops.cache_file_aops = inode->i_mapping->a_ops; 
287                 memcpy(u_aops, inode->i_mapping->a_ops, 
288                        sizeof(struct address_space_operations));
289         }
290         if (filter_iops) {
291                 if (filter_iops->revalidate)
292                         u_iops->revalidate = filter_iops->revalidate;
293         }
294         if (filter_fops) {
295                 if (filter_fops->read)
296                         u_fops->read = filter_fops->read;
297                 if (filter_fops->write)
298                         u_fops->write = filter_fops->write;
299         }
300         if (filter_aops) {
301                 if (filter_aops->readpage)
302                         u_aops->readpage = filter_aops->readpage;
303         }
304         EXIT;
305 }
306
307 void filter_setup_symlink_ops(struct filter_fs *cache, 
308                               struct inode *inode,
309                               struct inode_operations *filter_iops, 
310                               struct file_operations *filter_fops)
311 {
312         struct inode_operations *u_iops;
313         struct file_operations *u_fops;
314         
315         ENTRY;
316
317         if (cache->o_flags & FILTER_DID_SYMLINK_OPS || !inode ) {
318                 EXIT;
319                 return;
320         }
321         cache->o_flags |= FILTER_DID_SYMLINK_OPS;
322
323         /* steal the old ops */
324         cache->o_caops.cache_sym_iops = inode->i_op;
325         cache->o_caops.cache_sym_fops = inode->i_fop; 
326
327         /* abbreviate */
328         u_iops = filter_c2usiops(cache); 
329         u_fops = filter_c2usfops(cache); 
330
331         /* setup our dir iops: copy and modify */
332         memcpy(u_iops, inode->i_op, sizeof(struct inode_operations));
333         memcpy(u_fops, inode->i_fop, sizeof(struct file_operations));
334         if (filter_iops) {
335                 struct inode_operations *cache_iops = inode->i_op; 
336                 if (cache_iops->readlink && filter_iops->readlink) 
337                         u_iops->readlink = filter_iops->readlink;
338                 if (cache_iops->follow_link && filter_iops->follow_link)
339                         u_iops->follow_link = filter_iops->follow_link;
340         }
341         EXIT;
342 }
343
344 void filter_setup_dentry_ops(struct filter_fs *cache,
345                              struct dentry_operations *cache_dop,
346                              struct dentry_operations *filter_dop)
347 {
348         if ( cache->o_flags & FILTER_DID_DENTRY_OPS ) {
349                 EXIT;
350                 return;
351         }
352         cache->o_flags |= FILTER_DID_DENTRY_OPS;
353
354         cache->o_caops.cache_dentry_ops = cache_dop;
355         memcpy(&cache->o_fops.filter_dentry_ops,
356                filter_dop, sizeof(*filter_dop));
357         
358         if (cache_dop &&  cache_dop != filter_dop && cache_dop->d_revalidate){
359                 CWARN("filter overriding revalidation!\n");
360         }
361         EXIT;
362         return;
363 }
364 /* snapfs : for snapshot operations */
365 void filter_setup_snapshot_ops (struct filter_fs *cache, 
366                                 struct snapshot_operations *cache_snapops)
367 {
368         ENTRY;
369
370         if ( cache->o_flags & FILTER_DID_SNAPSHOT_OPS ) {
371                 EXIT;
372                 return;
373         }
374         cache->o_flags |= FILTER_DID_SNAPSHOT_OPS;
375
376         cache->o_snapops = cache_snapops;
377
378         EXIT;
379 }
380
381 void filter_setup_journal_ops (struct filter_fs *cache,
382                                struct journal_ops *cache_journal_ops)
383 {
384         ENTRY;
385
386         if( cache->o_flags & FILTER_DID_JOURNAL_OPS ){
387                 EXIT;
388                 return;
389         }
390         cache->o_flags |= FILTER_DID_JOURNAL_OPS;
391
392         cache->o_trops = cache_journal_ops;
393
394         EXIT;
395 }