1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
4 * Copyright (C) 2000 Stelias Computing, Inc.
5 * Copyright (C) 2000 Red Hat, Inc.
6 * Copyright (C) 2000 Mountain View Data, Inc.
8 * Extended Attribute Support
9 * Copyright (C) 2001 Shirish H. Phatak, Tacit Networks, Inc.
11 * This file is part of InterMezzo, http://www.inter-mezzo.org.
13 * InterMezzo is free software; you can redistribute it and/or
14 * modify it under the terms of version 2 of the GNU General Public
15 * License as published by the Free Software Foundation.
17 * InterMezzo is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with InterMezzo; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 #include <asm/bitops.h>
29 #include <asm/uaccess.h>
30 #include <asm/system.h>
32 #include <linux/errno.h>
34 #include <linux/ext2_fs.h>
35 #include <linux/slab.h>
36 #include <linux/vmalloc.h>
37 #include <linux/sched.h>
38 #include <linux/stat.h>
39 #include <linux/string.h>
40 #include <linux/blkdev.h>
41 #include <linux/init.h>
42 #include <linux/module.h>
44 #include <linux/fsfilter.h>
45 #include "intermezzo_fs.h"
48 int filter_print_entry = 0;
49 int filter_debug = 0xfffffff;
51 * The function in this file are responsible for setting up the
52 * correct methods layered file systems like InterMezzo and snapfs
56 static struct filter_fs filter_oppar[FILTER_FS_TYPES];
58 /* get to the upper methods (intermezzo, snapfs) */
59 inline struct super_operations *filter_c2usops(struct filter_fs *cache)
61 return &cache->o_fops.filter_sops;
64 inline struct inode_operations *filter_c2udiops(struct filter_fs *cache)
66 return &cache->o_fops.filter_dir_iops;
70 inline struct inode_operations *filter_c2ufiops(struct filter_fs *cache)
72 return &cache->o_fops.filter_file_iops;
75 inline struct inode_operations *filter_c2usiops(struct filter_fs *cache)
77 return &cache->o_fops.filter_sym_iops;
81 inline struct file_operations *filter_c2udfops(struct filter_fs *cache)
83 return &cache->o_fops.filter_dir_fops;
86 inline struct file_operations *filter_c2uffops(struct filter_fs *cache)
88 return &cache->o_fops.filter_file_fops;
91 inline struct file_operations *filter_c2usfops(struct filter_fs *cache)
93 return &cache->o_fops.filter_sym_fops;
96 inline struct dentry_operations *filter_c2udops(struct filter_fs *cache)
98 return &cache->o_fops.filter_dentry_ops;
101 /* get to the cache (lower) methods */
102 inline struct super_operations *filter_c2csops(struct filter_fs *cache)
104 return cache->o_caops.cache_sops;
107 inline struct inode_operations *filter_c2cdiops(struct filter_fs *cache)
109 return cache->o_caops.cache_dir_iops;
112 inline struct inode_operations *filter_c2cfiops(struct filter_fs *cache)
114 return cache->o_caops.cache_file_iops;
117 inline struct inode_operations *filter_c2csiops(struct filter_fs *cache)
119 return cache->o_caops.cache_sym_iops;
122 inline struct file_operations *filter_c2cdfops(struct filter_fs *cache)
124 return cache->o_caops.cache_dir_fops;
127 inline struct file_operations *filter_c2cffops(struct filter_fs *cache)
129 return cache->o_caops.cache_file_fops;
132 inline struct file_operations *filter_c2csfops(struct filter_fs *cache)
134 return cache->o_caops.cache_sym_fops;
137 inline struct dentry_operations *filter_c2cdops(struct filter_fs *cache)
139 return cache->o_caops.cache_dentry_ops;
143 void filter_setup_journal_ops(struct filter_fs *ops, char *cache_type)
145 if ( strlen(cache_type) == strlen("ext2") &&
146 memcmp(cache_type, "ext2", strlen("ext2")) == 0 ) {
147 #ifdef CONFIG_EXT2_FS
148 ops->o_trops = &presto_ext2_journal_ops;
152 FDEBUG(D_SUPER, "ops at %p\n", ops);
155 if ( strlen(cache_type) == strlen("ext3") &&
156 memcmp(cache_type, "ext3", strlen("ext3")) == 0 ) {
157 #if defined(CONFIG_EXT3_FS) || defined (CONFIG_EXT3_FS_MODULE)
158 ops->o_trops = &presto_ext3_journal_ops;
162 FDEBUG(D_SUPER, "ops at %p\n", ops);
165 if ( strlen(cache_type) == strlen("tmpfs") &&
166 memcmp(cache_type, "tmpfs", strlen("tmpfs")) == 0 ) {
167 #if defined(CONFIG_TMPFS)
168 ops->o_trops = &presto_tmpfs_journal_ops;
172 FDEBUG(D_SUPER, "ops at %p\n", ops);
175 if ( strlen(cache_type) == strlen("reiserfs") &&
176 memcmp(cache_type, "reiserfs", strlen("reiserfs")) == 0 ) {
178 /* #if defined(CONFIG_REISERFS_FS) || defined(CONFIG_REISERFS_FS_MODULE) */
179 ops->o_trops = &presto_reiserfs_journal_ops;
183 FDEBUG(D_SUPER, "ops at %p\n", ops);
186 if ( strlen(cache_type) == strlen("xfs") &&
187 memcmp(cache_type, "xfs", strlen("xfs")) == 0 ) {
189 /*#if defined(CONFIG_XFS_FS) || defined (CONFIG_XFS_FS_MODULE) */
190 ops->o_trops = &presto_xfs_journal_ops;
194 FDEBUG(D_SUPER, "ops at %p\n", ops);
197 if ( strlen(cache_type) == strlen("obdfs") &&
198 memcmp(cache_type, "obdfs", strlen("obdfs")) == 0 ) {
199 #if defined(CONFIG_OBDFS_FS) || defined (CONFIG_OBDFS_FS_MODULE)
200 ops->o_trops = presto_obdfs_journal_ops;
204 FDEBUG(D_SUPER, "ops at %p\n", ops);
209 /* find the cache for this FS */
210 struct filter_fs *filter_get_filter_fs(const char *cache_type)
212 struct filter_fs *ops = NULL;
215 if ( strlen(cache_type) == strlen("ext2") &&
216 memcmp(cache_type, "ext2", strlen("ext2")) == 0 ) {
217 ops = &filter_oppar[FILTER_FS_EXT2];
218 FDEBUG(D_SUPER, "ops at %p\n", ops);
221 if ( strlen(cache_type) == strlen("xfs") &&
222 memcmp(cache_type, "xfs", strlen("xfs")) == 0 ) {
223 ops = &filter_oppar[FILTER_FS_XFS];
224 FDEBUG(D_SUPER, "ops at %p\n", ops);
227 if ( strlen(cache_type) == strlen("ext3") &&
228 memcmp(cache_type, "ext3", strlen("ext3")) == 0 ) {
229 ops = &filter_oppar[FILTER_FS_EXT3];
230 FDEBUG(D_SUPER, "ops at %p\n", ops);
233 if ( strlen(cache_type) == strlen("tmpfs") &&
234 memcmp(cache_type, "tmpfs", strlen("tmpfs")) == 0 ) {
235 ops = &filter_oppar[FILTER_FS_TMPFS];
236 FDEBUG(D_SUPER, "ops at %p\n", ops);
239 if ( strlen(cache_type) == strlen("reiserfs") &&
240 memcmp(cache_type, "reiserfs", strlen("reiserfs")) == 0 ) {
241 ops = &filter_oppar[FILTER_FS_REISERFS];
242 FDEBUG(D_SUPER, "ops at %p\n", ops);
244 if ( strlen(cache_type) == strlen("obdfs") &&
245 memcmp(cache_type, "obdfs", strlen("obdfs")) == 0 ) {
246 ops = &filter_oppar[FILTER_FS_OBDFS];
247 FDEBUG(D_SUPER, "ops at %p\n", ops);
251 CERROR("prepare to die: unrecognized cache type for Filter\n");
259 * Frobnicate the InterMezzo operations
260 * this establishes the link between the InterMezzo file system
261 * and the underlying file system used for the cache.
264 void filter_setup_super_ops(struct filter_fs *cache, struct super_operations *cache_sops, struct super_operations *filter_sops)
266 /* Get ptr to the shared struct snapfs_ops structure. */
267 struct filter_ops *props = &cache->o_fops;
268 /* Get ptr to the shared struct cache_ops structure. */
269 struct cache_ops *caops = &cache->o_caops;
273 if ( cache->o_flags & FILTER_DID_SUPER_OPS ) {
277 cache->o_flags |= FILTER_DID_SUPER_OPS;
279 /* Set the cache superblock operations to point to the
280 superblock operations of the underlying file system. */
281 caops->cache_sops = cache_sops;
284 * Copy the cache (real fs) superblock ops to the "filter"
285 * superblock ops as defaults. Some will be changed below
287 memcpy(&props->filter_sops, cache_sops, sizeof(*cache_sops));
289 /* 'put_super' unconditionally is that of filter */
290 if (filter_sops->put_super) {
291 props->filter_sops.put_super = filter_sops->put_super;
294 if (cache_sops->read_inode) {
295 props->filter_sops.read_inode = filter_sops->read_inode;
296 FDEBUG(D_INODE, "setting filter_read_inode, cache_ops %p, cache %p, ri at %p\n",
297 cache, cache, props->filter_sops.read_inode);
300 if (cache_sops->remount_fs)
301 props->filter_sops.remount_fs = filter_sops->remount_fs;
306 void filter_setup_dir_ops(struct filter_fs *cache, struct inode *inode, struct inode_operations *filter_iops, struct file_operations *filter_fops)
308 struct inode_operations *cache_filter_iops;
309 struct inode_operations *cache_iops = inode->i_op;
310 struct file_operations *cache_fops = inode->i_fop;
313 if ( cache->o_flags & FILTER_DID_DIR_OPS ) {
317 cache->o_flags |= FILTER_DID_DIR_OPS;
319 /* former ops become cache_ops */
320 cache->o_caops.cache_dir_iops = cache_iops;
321 cache->o_caops.cache_dir_fops = cache_fops;
322 FDEBUG(D_SUPER, "filter at %p, cache iops %p, iops %p\n",
323 cache, cache_iops, filter_c2udiops(cache));
325 /* setup our dir iops: copy and modify */
326 memcpy(filter_c2udiops(cache), cache_iops, sizeof(*cache_iops));
329 cache_filter_iops = filter_c2udiops(cache);
331 /* methods that filter if cache filesystem has these ops */
332 if (cache_iops->lookup && filter_iops->lookup)
333 cache_filter_iops->lookup = filter_iops->lookup;
334 if (cache_iops->create && filter_iops->create)
335 cache_filter_iops->create = filter_iops->create;
336 if (cache_iops->link && filter_iops->link)
337 cache_filter_iops->link = filter_iops->link;
338 if (cache_iops->unlink && filter_iops->unlink)
339 cache_filter_iops->unlink = filter_iops->unlink;
340 if (cache_iops->mkdir && filter_iops->mkdir)
341 cache_filter_iops->mkdir = filter_iops->mkdir;
342 if (cache_iops->rmdir && filter_iops->rmdir)
343 cache_filter_iops->rmdir = filter_iops->rmdir;
344 if (cache_iops->symlink && filter_iops->symlink)
345 cache_filter_iops->symlink = filter_iops->symlink;
346 if (cache_iops->rename && filter_iops->rename)
347 cache_filter_iops->rename = filter_iops->rename;
348 if (cache_iops->mknod && filter_iops->mknod)
349 cache_filter_iops->mknod = filter_iops->mknod;
350 if (cache_iops->permission && filter_iops->permission)
351 cache_filter_iops->permission = filter_iops->permission;
352 if (cache_iops->getattr)
353 cache_filter_iops->getattr = filter_iops->getattr;
354 /* Some filesystems do not use a setattr method of their own
355 instead relying on inode_setattr/write_inode. We still need to
356 journal these so we make setattr an unconditional operation.
357 XXX: we should probably check for write_inode. SHP
359 /*if (cache_iops->setattr)*/
360 cache_filter_iops->setattr = filter_iops->setattr;
361 #ifdef CONFIG_FS_EXT_ATTR
362 /* For now we assume that posix acls are handled through extended
363 * attributes. If this is not the case, we must explicitly trap
366 if (cache_iops->set_ext_attr && filter_iops->set_ext_attr)
367 cache_filter_iops->set_ext_attr = filter_iops->set_ext_attr;
372 memcpy(filter_c2udfops(cache), cache_fops, sizeof(*cache_fops));
374 /* unconditional filtering operations */
375 filter_c2udfops(cache)->ioctl = filter_fops->ioctl;
381 void filter_setup_file_ops(struct filter_fs *cache, struct inode *inode, struct inode_operations *filter_iops, struct file_operations *filter_fops)
383 struct inode_operations *pr_iops;
384 struct inode_operations *cache_iops = inode->i_op;
385 struct file_operations *cache_fops = inode->i_fop;
388 if ( cache->o_flags & FILTER_DID_FILE_OPS ) {
392 cache->o_flags |= FILTER_DID_FILE_OPS;
394 /* steal the old ops */
395 /* former ops become cache_ops */
396 cache->o_caops.cache_file_iops = cache_iops;
397 cache->o_caops.cache_file_fops = cache_fops;
400 pr_iops = filter_c2ufiops(cache);
402 /* setup our dir iops: copy and modify */
403 memcpy(pr_iops, cache_iops, sizeof(*cache_iops));
406 CERROR("*** cache file ops at %p\n", cache_fops);
407 memcpy(filter_c2uffops(cache), cache_fops, sizeof(*cache_fops));
410 /* See comments above in filter_setup_dir_ops. SHP */
411 /*if (cache_iops->setattr)*/
412 pr_iops->setattr = filter_iops->setattr;
413 if (cache_iops->getattr)
414 pr_iops->getattr = filter_iops->getattr;
415 /* XXX Should this be conditional rmr ? */
416 pr_iops->permission = filter_iops->permission;
417 #ifdef CONFIG_FS_EXT_ATTR
418 /* For now we assume that posix acls are handled through extended
419 * attributes. If this is not the case, we must explicitly trap and
422 if (cache_iops->set_ext_attr && filter_iops->set_ext_attr)
423 pr_iops->set_ext_attr = filter_iops->set_ext_attr;
427 /* unconditional filtering operations */
428 filter_c2uffops(cache)->open = filter_fops->open;
429 filter_c2uffops(cache)->release = filter_fops->release;
430 filter_c2uffops(cache)->write = filter_fops->write;
431 filter_c2uffops(cache)->ioctl = filter_fops->ioctl;
436 /* XXX in 2.3 there are "fast" and "slow" symlink ops for ext2 XXX */
437 void filter_setup_symlink_ops(struct filter_fs *cache, struct inode *inode, struct inode_operations *filter_iops, struct file_operations *filter_fops)
439 struct inode_operations *pr_iops;
440 struct inode_operations *cache_iops = inode->i_op;
441 struct file_operations *cache_fops = inode->i_fop;
444 if ( cache->o_flags & FILTER_DID_SYMLINK_OPS ) {
448 cache->o_flags |= FILTER_DID_SYMLINK_OPS;
450 /* steal the old ops */
451 cache->o_caops.cache_sym_iops = cache_iops;
452 cache->o_caops.cache_sym_fops = cache_fops;
455 pr_iops = filter_c2usiops(cache);
457 /* setup our dir iops: copy and modify */
458 memcpy(pr_iops, cache_iops, sizeof(*cache_iops));
460 /* See comments above in filter_setup_dir_ops. SHP */
461 /* if (cache_iops->setattr) */
462 pr_iops->setattr = filter_iops->setattr;
463 if (cache_iops->getattr)
464 pr_iops->getattr = filter_iops->getattr;
467 /* copy fops - careful for symlinks they might be NULL */
469 memcpy(filter_c2usfops(cache), cache_fops, sizeof(*cache_fops));
475 void filter_setup_dentry_ops(struct filter_fs *cache,
476 struct dentry_operations *cache_dop,
477 struct dentry_operations *filter_dop)
479 if ( cache->o_flags & FILTER_DID_DENTRY_OPS ) {
483 cache->o_flags |= FILTER_DID_DENTRY_OPS;
485 cache->o_caops.cache_dentry_ops = cache_dop;
486 memcpy(&cache->o_fops.filter_dentry_ops,
487 filter_dop, sizeof(*filter_dop));
489 if (cache_dop && cache_dop != filter_dop && cache_dop->d_revalidate){
490 CERROR("WARNING: filter overriding revalidation!\n");