*
*/
-#define EXPORT_SYMTAB
+#define DEBUG_SUBSYSTEM S_SNAP
-
-#define __NO_VERSION__
-#include <linux/module.h>
-#include <asm/uaccess.h>
-#include <linux/sched.h>
-#include <linux/stat.h>
-#include <linux/string.h>
-#include <linux/locks.h>
-#include <linux/quotaops.h>
-#include <linux/list.h>
-#include <linux/file.h>
-#include <asm/bitops.h>
-#include <asm/byteorder.h>
-
-#ifdef CONFIG_SNAPFS_EXT2
-#include <linux/ext2_fs.h>
-#endif
-#ifdef CONFIG_SNAPFS_EXT3
+#include <linux/kmod.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/jbd.h>
#include <linux/ext3_fs.h>
-#endif
-
-#include <linux/filter.h>
-#include <linux/snapfs.h>
-#include <linux/snapsupport.h>
+#include <linux/string.h>
+#include <linux/snap.h>
+#include "snapfs_internal.h"
extern int currentfs_remount(struct super_block * sb, int *flags, char *data);
extern void currentfs_dotsnap_read_inode(struct snap_cache *, struct inode *);
-/* Superblock operations. */
-static void currentfs_read_inode(struct inode *inode)
+static kmem_cache_t *filter_info_cache = NULL;
+
+void cleanup_filter_info_cache()
{
- struct snap_cache *cache;
- ENTRY;
+ kmem_cache_destroy(filter_info_cache);
+}
- if( !inode )
- {
- EXIT;
- return;
- }
+int init_filter_info_cache()
+{
+ filter_info_cache = kmem_cache_create("snapfs_filter_info",
+ sizeof(struct filter_inode_info),
+ 0, 0, NULL, NULL);
+ if (!filter_info_cache) {
+ CERROR("unable to create snap_inode info cache\n");
+ return -ENOMEM;
+ }
+ return 0;
+}
- CDEBUG(D_INODE, "read_inode ino %lu\n", inode->i_ino);
+void init_filter_data(struct inode *inode,
+ int flag)
+{
+ struct filter_inode_info *i;
+ struct snap_cache *cache;
+ struct snapshot_operations *snapops;
+
+ if (inode->i_filterdata || inode->i_ino & 0xF0000000)
+ return;
cache = snap_find_cache(inode->i_dev);
- if ( !cache ) {
- printk("currentfs_read_inode: cannot find cache\n");
+ if (!cache) {
+ CERROR("currentfs_read_inode: cannot find cache\n");
make_bad_inode(inode);
- EXIT;
- return ;
- }
-
- if ( inode->i_ino & 0xF0000000 ) {
- CDEBUG(D_INODE, "\n");
- currentfs_dotsnap_read_inode(cache, inode);
- EXIT;
- return ;
+ return;
}
+ snapops = filter_c2csnapops(cache->cache_filter);
- if( filter_c2csops(cache->cache_filter) )
- filter_c2csops(cache->cache_filter)->read_inode(inode);
+ if (inode->i_filterdata) return;
+
+ inode->i_filterdata = (struct filter_inode_info *) \
+ kmem_cache_alloc(filter_info_cache, SLAB_KERNEL);
+ i = inode->i_filterdata;
+ i -> generation = snapops->get_generation(inode);
+ i -> flags = flag;
+}
+void set_filter_ops(struct snap_cache *cache, struct inode *inode)
+{
/* XXX now set the correct snap_{file,dir,sym}_iops */
- if ( S_ISDIR(inode->i_mode) )
+ if (S_ISDIR(inode->i_mode)) {
inode->i_op = filter_c2udiops(cache->cache_filter);
- else if ( S_ISREG(inode->i_mode) ) {
+ inode->i_fop = filter_c2udfops(cache->cache_filter);
+ } else if (S_ISREG(inode->i_mode)) {
if ( !filter_c2cfiops(cache->cache_filter) ) {
- filter_setup_file_ops(cache->cache_filter,
- inode->i_op, ¤tfs_file_iops);
+ filter_setup_file_ops(cache->cache_filter, inode,
+ ¤tfs_file_iops,
+ ¤tfs_file_fops,
+ ¤tfs_file_aops);
}
+ CDEBUG(D_INODE, "inode %lu, i_op at %p\n",
+ inode->i_ino, inode->i_op);
+ inode->i_fop = filter_c2uffops(cache->cache_filter);
inode->i_op = filter_c2ufiops(cache->cache_filter);
- printk("inode %lu, i_op at %p\n", inode->i_ino, inode->i_op);
+ if (inode->i_mapping)
+ inode->i_mapping->a_ops = filter_c2ufaops(cache->cache_filter);
+
}
- else if ( S_ISLNK(inode->i_mode) ) {
+ else if (S_ISLNK(inode->i_mode)) {
if ( !filter_c2csiops(cache->cache_filter) ) {
- filter_setup_symlink_ops(cache->cache_filter,
- inode->i_op, ¤tfs_sym_iops);
+ filter_setup_symlink_ops(cache->cache_filter, inode,
+ ¤tfs_sym_iops, ¤tfs_sym_fops);
}
inode->i_op = filter_c2usiops(cache->cache_filter);
- printk("inode %lu, i_op at %p\n", inode->i_ino, inode->i_op);
+ inode->i_fop = filter_c2usfops(cache->cache_filter);
+ CDEBUG(D_INODE, "inode %lu, i_op at %p\n",
+ inode->i_ino, inode->i_op);
}
-
- EXIT;
- return;
}
+int currentfs_setxattr(struct dentry *dentry, const char *name,
+ const void *value, size_t size, int flags)
+{
+ struct snap_cache *cache;
+ struct inode *inode = dentry->d_inode;
+ struct inode_operations *iops;
+ int rc;
+ ENTRY;
+
+ cache = snap_find_cache(inode->i_dev);
+ if (!cache) {
+ CERROR("currentfs_setxattr: cannot find cache\n");
+ RETURN(-EINVAL);
+ }
+
+ iops = filter_c2cfiops(cache->cache_filter);
+
+ if (!iops || !iops->setxattr) {
+ RETURN(-EINVAL);
+ }
+ if ( snap_needs_cow(inode) != -1 ) {
+ CDEBUG(D_SNAP, "snap_needs_cow for ino %lu \n",inode->i_ino);
+ snap_do_cow(inode, dentry->d_parent->d_inode->i_ino, 0);
+ }
+
+ rc = iops->setxattr(dentry, name, value, size, flags);
-static int currentfs_notify_change(struct dentry *dentry, struct iattr *iattr)
+ RETURN(rc);
+}
+int currentfs_removexattr(struct dentry *dentry, const char *name)
{
- struct snap_cache *cache;
- int rc;
- struct super_operations *sops;
+ struct snap_cache *cache;
+ struct inode *inode = dentry->d_inode;
+ struct inode_operations *iops;
+ int rc;
ENTRY;
-
- if (currentfs_is_under_dotsnap(dentry)) {
- EXIT;
- return -EPERM;
+
+ cache = snap_find_cache(inode->i_dev);
+ if (!cache) {
+ CERROR("currentfs_setxattr: cannot find cache\n");
+ RETURN(-EINVAL);
}
- cache = snap_find_cache(dentry->d_inode->i_dev);
- if ( !cache ) {
- EXIT;
- return -EINVAL;
+ iops = filter_c2cfiops(cache->cache_filter);
+
+ if (!iops || !iops->removexattr) {
+ RETURN(-EINVAL);
+ }
+
+ if (snap_needs_cow(inode) != -1) {
+ CDEBUG(D_SNAP, "snap_needs_cow for ino %lu \n",inode->i_ino);
+ snap_do_cow(inode, dentry->d_parent->d_inode->i_ino, 0);
}
+ rc = iops->removexattr(dentry, name);
- /* XXX better alloc a new dentry */
+ RETURN(rc);
+}
- if ( snap_needs_cow(dentry->d_inode) != -1 ) {
- printk("notify_change:snap_needs_cow for ino %lu \n",
- dentry->d_inode->i_ino);
- snap_do_cow(dentry->d_inode,
- dentry->d_parent->d_inode->i_ino, 0);
+int currentfs_setattr(struct dentry *dentry, struct iattr *attr)
+{
+ struct snap_cache *cache;
+ struct inode *inode = dentry->d_inode;
+ struct inode_operations *iops;
+ int rc;
+
+ ENTRY;
+
+ cache = snap_find_cache(inode->i_dev);
+ if (!cache) {
+ CERROR("currentfs_setxattr: cannot find cache\n");
+ RETURN(-EINVAL);
}
- sops = filter_c2csops(cache->cache_filter);
- if (!sops ||
- !sops->notify_change) {
- EXIT;
- return -EINVAL;
+ iops = filter_c2cfiops(cache->cache_filter);
+
+ if (!iops || !iops->setattr) {
+ RETURN(-EINVAL);
}
- rc = sops->notify_change(dentry, iattr);
-
- EXIT;
- return rc;
+ if ( snap_needs_cow(inode) != -1 ) {
+ CDEBUG(D_SNAP, "snap_needs_cow for ino %lu \n",inode->i_ino);
+ snap_do_cow(inode, dentry->d_parent->d_inode->i_ino, 0);
+ }
+
+ rc = iops->setattr(dentry, attr);
+
+ RETURN(rc);
}
+/* Superblock operations. */
+static void currentfs_read_inode(struct inode *inode)
+{
+ struct snap_cache *cache;
+ ENTRY;
+ if( !inode )
+ return;
+ CDEBUG(D_INODE, "read_inode ino %lu\n", inode->i_ino);
+
+ cache = snap_find_cache(inode->i_dev);
+ if (!cache) {
+ CERROR("currentfs_read_inode: cannot find cache\n");
+ make_bad_inode(inode);
+ return;
+ }
+
+ if (inode->i_ino & 0xF0000000) {
+ currentfs_dotsnap_read_inode(cache, inode);
+ return;
+ }
+
+ if(filter_c2csops(cache->cache_filter))
+ filter_c2csops(cache->cache_filter)->read_inode(inode);
+
+ CDEBUG(D_INODE, "read_inode ino %lu icount %d \n",
+ inode->i_ino, atomic_read(&inode->i_count));
+ set_filter_ops(cache, inode);
+ /*init filter_data struct
+ * FIXME flag should be set future*/
+ init_filter_data(inode, 0);
+ CDEBUG(D_INODE, "read_inode ino %lu icount %d \n",
+ inode->i_ino, atomic_read(&inode->i_count));
+ return;
+}
static void currentfs_put_super(struct super_block *sb)
{
CDEBUG(D_SUPER, "sb %lx, sb->u.generic_sbp: %lx\n",
(ulong) sb, (ulong) sb->u.generic_sbp);
cache = snap_find_cache(sb->s_dev);
- if (!cache) {
- EXIT;
- goto exit;
- }
+
+ if (!cache)
+ GOTO(exit, 0);
+
/* handle COMPAT_FEATUREs */
#ifdef CONFIG_SNAPFS_EXT2
else if( cache->cache_type == FILTER_FS_EXT2 ){
}
if (!list_empty(&cache->cache_clone_list)) {
- printk("Warning: snap_put_super: clones exist!\n");
+ CWARN("snap_put_super: clones exist!\n");
}
list_del(&cache->cache_chain);
CDEBUG(D_SUPER, "sb %lx, sb->u.generic_sbp: %lx\n",
(ulong) sb, (ulong) sb->u.generic_sbp);
exit:
- CDEBUG(D_MALLOC, "after umount: kmem %ld, vmem %ld\n",
- snap_kmemory, snap_vmemory);
- MOD_DEC_USE_COUNT;
EXIT;
- return ;
+ return;
+}
+static void currentfs_clear_inode(struct inode *inode)
+{
+ struct snap_cache *cache;
+ struct super_operations *sops;
+ ENTRY;
+ cache = snap_find_cache(inode->i_dev);
+ if (!cache) {
+ CDEBUG(D_INODE, "inode has invalid dev\n");
+ return;
+ }
+
+ if (inode->i_filterdata) {
+ kmem_cache_free(filter_info_cache, inode->i_filterdata);
+ inode->i_filterdata = NULL;
+ }
+
+ sops = filter_c2csops(cache->cache_filter);
+ if (sops && sops->clear_inode)
+ sops->clear_inode(inode);
}
struct super_operations currentfs_super_ops = {
- currentfs_read_inode,
- NULL, /* write inode */
- NULL, /* put inode */
- NULL, /* delete inode */
- currentfs_notify_change,
- currentfs_put_super,
- NULL, /* write super */
- NULL,
- NULL, /* remount */
+ read_inode: currentfs_read_inode,
+ put_super: currentfs_put_super,
+ clear_inode: currentfs_clear_inode,
};
+
+
+
+
+