4 #define DEBUG_SUBSYSTEM S_SNAP
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>
16 #include "snapfs_internal.h"
20 * The function in this file are responsible for setting up the
21 * correct methods layered file systems like InterMezzo and SnapFS
25 static struct filter_fs filter_oppar[FILTER_FS_TYPES];
27 /* get to the upper methods (intermezzo, snapfs) */
28 inline struct super_operations *filter_c2usops(struct filter_fs *cache)
30 return &cache->o_fops.filter_sops;
33 inline struct inode_operations *filter_c2udiops(struct filter_fs *cache)
35 return &cache->o_fops.filter_dir_iops;
38 inline struct inode_operations *filter_c2ufiops(struct filter_fs *cache)
40 return &cache->o_fops.filter_file_iops;
43 inline struct inode_operations *filter_c2usiops(struct filter_fs *cache)
45 return &cache->o_fops.filter_sym_iops;
48 inline struct file_operations *filter_c2udfops(struct filter_fs *cache)
50 return &cache->o_fops.filter_dir_fops;
53 inline struct file_operations *filter_c2uffops(struct filter_fs *cache)
55 return &cache->o_fops.filter_file_fops;
58 inline struct address_space_operations *filter_c2ufaops(struct filter_fs *cache)
60 return &cache->o_fops.filter_file_aops;
63 inline struct file_operations *filter_c2usfops(struct filter_fs *cache)
65 return &cache->o_fops.filter_sym_fops;
68 inline struct dentry_operations *filter_c2udops(struct filter_fs *cache)
70 return &cache->o_fops.filter_dentry_ops;
73 /* get to the cache (lower) methods */
74 inline struct super_operations *filter_c2csops(struct filter_fs *cache)
76 return cache->o_caops.cache_sops;
79 inline struct inode_operations *filter_c2cdiops(struct filter_fs *cache)
81 return cache->o_caops.cache_dir_iops;
84 inline struct inode_operations *filter_c2cfiops(struct filter_fs *cache)
86 return cache->o_caops.cache_file_iops;
89 inline struct address_space_operations *filter_c2cfaops(struct filter_fs *cache)
91 return cache->o_caops.cache_file_aops;
94 inline struct inode_operations *filter_c2csiops(struct filter_fs *cache)
96 return cache->o_caops.cache_sym_iops;
99 inline struct file_operations *filter_c2cdfops(struct filter_fs *cache)
101 return cache->o_caops.cache_dir_fops;
104 inline struct file_operations *filter_c2cffops(struct filter_fs *cache)
106 return cache->o_caops.cache_file_fops;
109 inline struct file_operations *filter_c2csfops(struct filter_fs *cache)
111 return cache->o_caops.cache_sym_fops;
114 inline struct dentry_operations *filter_c2cdops(struct filter_fs *cache)
116 return cache->o_caops.cache_dentry_ops;
118 /* snapfs: for snapshot operations */
119 inline struct snapshot_operations *filter_c2csnapops(struct filter_fs *cache)
121 return cache->o_snapops;
124 /* find the cache for this FS */
125 struct filter_fs *filter_get_filter_fs(const char *cache_type)
127 struct filter_fs *ops = NULL;
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);
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);
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);
148 CERROR("prepare to die: unrecognized cache type for Filter\n");
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.
160 void filter_setup_super_ops(struct filter_fs *cache,
161 struct super_operations *cache_sops,
162 struct super_operations *filter_sops)
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;
171 if ( cache->o_flags & FILTER_DID_SUPER_OPS ) {
175 cache->o_flags |= FILTER_DID_SUPER_OPS;
177 /* Set the cache superblock operations to point to the
178 superblock operations of the underlying file system. */
179 caops->cache_sops = cache_sops;
181 * Copy the cache (real fs) superblock ops to the "filter"
182 * superblock ops as defaults. Some will be changed below
184 memcpy(&uops->filter_sops, cache_sops, sizeof(*cache_sops));
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;
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);
195 uops->filter_sops.clear_inode = filter_sops->clear_inode;
200 void filter_setup_dir_ops(struct filter_fs *cache,
202 struct inode_operations *filter_iops,
203 struct file_operations *filter_fops)
205 struct inode_operations *u_iops;
206 struct file_operations *u_fops;
210 if (cache->o_flags & FILTER_DID_DIR_OPS) {
214 cache->o_flags |= FILTER_DID_DIR_OPS;
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;
220 u_iops = filter_c2udiops(cache);
221 u_fops = filter_c2udfops(cache);
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));
227 /* methods that filter if cache filesystem has these ops */
229 struct inode_operations *cache_iops = inode->i_op;
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;
255 struct file_operations *cache_fops = inode->i_fop;
257 if(cache_fops->readdir && filter_fops->readdir)
258 u_fops->readdir = filter_fops->readdir;
263 void filter_setup_file_ops(struct filter_fs *cache,
265 struct inode_operations *filter_iops,
266 struct file_operations *filter_fops,
267 struct address_space_operations *filter_aops)
269 struct inode_operations *u_iops;
270 struct file_operations *u_fops;
271 struct address_space_operations *u_aops;
274 if (cache->o_flags & FILTER_DID_FILE_OPS || !inode ) {
279 cache->o_flags |= FILTER_DID_FILE_OPS;
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;
286 u_iops = filter_c2ufiops(cache);
287 u_fops = filter_c2uffops(cache);
288 u_aops = filter_c2ufaops(cache);
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));
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));
300 if (filter_iops->revalidate)
301 u_iops->revalidate = filter_iops->revalidate;
304 if (filter_fops->read)
305 u_fops->read = filter_fops->read;
308 if (filter_aops->readpage)
309 u_aops->readpage = filter_aops->readpage;
314 void filter_setup_symlink_ops(struct filter_fs *cache,
316 struct inode_operations *filter_iops,
317 struct file_operations *filter_fops)
319 struct inode_operations *u_iops;
320 struct file_operations *u_fops;
324 if (cache->o_flags & FILTER_DID_SYMLINK_OPS || !inode ) {
328 cache->o_flags |= FILTER_DID_SYMLINK_OPS;
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;
335 u_iops = filter_c2usiops(cache);
336 u_fops = filter_c2usfops(cache);
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));
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;
351 void filter_setup_dentry_ops(struct filter_fs *cache,
352 struct dentry_operations *cache_dop,
353 struct dentry_operations *filter_dop)
355 if ( cache->o_flags & FILTER_DID_DENTRY_OPS ) {
359 cache->o_flags |= FILTER_DID_DENTRY_OPS;
361 cache->o_caops.cache_dentry_ops = cache_dop;
362 memcpy(&cache->o_fops.filter_dentry_ops,
363 filter_dop, sizeof(*filter_dop));
365 if (cache_dop && cache_dop != filter_dop && cache_dop->d_revalidate){
366 CWARN("filter overriding revalidation!\n");
371 /* snapfs : for snapshot operations */
372 void filter_setup_snapshot_ops (struct filter_fs *cache,
373 struct snapshot_operations *cache_snapops)
377 if ( cache->o_flags & FILTER_DID_SNAPSHOT_OPS ) {
381 cache->o_flags |= FILTER_DID_SNAPSHOT_OPS;
383 cache->o_snapops = cache_snapops;
388 void filter_setup_journal_ops (struct filter_fs *cache,
389 struct journal_ops *cache_journal_ops)
393 if( cache->o_flags & FILTER_DID_JOURNAL_OPS ){
397 cache->o_flags |= FILTER_DID_JOURNAL_OPS;
399 cache->o_trops = cache_journal_ops;