-/*
- *
- *
- * Copyright (C) 2000 Stelias Computing, Inc.
- * Copyright (C) 2000 Red Hat, Inc.
- *
- *
+/*
+ * snapfs/cache.c
*/
+#define DEBUG_SUBSYSTEM S_SNAP
-#include <stdarg.h>
-
-#include <asm/bitops.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-
-#include <linux/errno.h>
+#include <linux/kmod.h>
+#include <linux/init.h>
#include <linux/fs.h>
-#include <linux/ext2_fs.h>
-#include <linux/malloc.h>
-#include <linux/vmalloc.h>
-#include <linux/sched.h>
-#include <linux/stat.h>
+#include <linux/slab.h>
#include <linux/string.h>
-#include <linux/locks.h>
-#include <linux/blkdev.h>
-#include <linux/init.h>
-#define __NO_VERSION__
-#include <linux/module.h>
-
-#include <linux/filter.h>
-#include <linux/snapfs.h>
-#include <linux/snapsupport.h>
-
+#include <linux/jbd.h>
+#include <linux/ext3_fs.h>
+#include <linux/snap.h>
+#include <portals/list.h>
+#include "snapfs_internal.h"
/*
* XXX - Not sure for snapfs that the cache functions are even needed.
* Can't all lookups be done by an inode->superblock->u.generic_sbp
* lookup?
*/
-/*
- This file contains the routines associated with managing a
- cache of files . These caches need to be found
- fast so they are hashed by the device, with an attempt to have
- collision chains of length 1.
-*/
+extern struct snap_table snap_tables[SNAP_MAX_TABLES];
/* the intent of this hash is to have collision chains of length 1 */
#define CACHES_BITS 8
#define CACHES_SIZE (1 << CACHES_BITS)
#define CACHES_MASK CACHES_SIZE - 1
+
static struct list_head snap_caches[CACHES_SIZE];
+
static inline int snap_cache_hash(kdev_t dev)
{
return (CACHES_MASK) & ((0x000F & (dev)) + ((0x0F00 & (dev)) >>8));
struct list_head *lh, *tmp;
lh = tmp = &(snap_caches[snap_cache_hash(dev)]);
- while ( (tmp = lh->next) != lh ) {
- cache = list_entry(tmp, struct snap_cache, cache_chain);
+ list_for_each_entry(cache, lh, cache_chain) {
if ( cache->cache_dev == dev )
return cache;
}
return NULL;
}
-
-/* map an inode to a cache */
-struct snap_cache *snap_get_cache(struct inode *inode)
-{
- struct snap_cache *cache;
-
- /* find the correct snap_cache here, based on the device */
- cache = snap_find_cache(inode->i_dev);
- if ( !cache ) {
- printk("WARNING: no cache for dev %d, ino %ld\n",
- inode->i_dev, inode->i_ino);
- return NULL;
- }
-
- return cache;
-}
-
-
-/* another debugging routine: check fs is InterMezzo fs */
-int snap_ispresto(struct inode *inode)
-{
- struct snap_cache *cache;
-
- if ( !inode )
- return 0;
- cache = snap_get_cache(inode);
- if ( !cache )
- return 0;
- return (inode->i_dev == cache->cache_dev);
-}
-
/* setup a cache structure when we need one */
struct snap_cache *snap_init_cache(void)
{
struct snap_cache *cache;
/* make a snap_cache structure for the hash */
- SNAP_ALLOC(cache, struct snap_cache *, sizeof(struct snap_cache));
+ SNAP_ALLOC(cache, sizeof(struct snap_cache));
if ( cache ) {
- memset(cache, 0, sizeof(struct snap_cache));
+ int i;
+
+ memset(cache, 0, sizeof(struct snap_cache));
INIT_LIST_HEAD(&cache->cache_chain);
INIT_LIST_HEAD(&cache->cache_clone_list);
- }
+
+ for (i = 0; i < SNAP_MAX_TABLES; i++) {
+ init_MUTEX(&snap_tables[i].tbl_sema);
+ }
+ }
return cache;
}
-
/* free a cache structure and all of the memory it is pointing to */
inline void snap_free_cache(struct snap_cache *cache)
{
if (!cache)
return;
-
-
SNAP_FREE(cache, sizeof(struct snap_cache));
}
*
*/
-#define __NO_VERSION__
+#define DEBUG_SUBSYSTEM S_SNAP
+
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/mm.h>
#include <linux/string.h>
+#include <linux/slab.h>
#include <linux/stat.h>
-#include <linux/errno.h>
-#include <linux/locks.h>
#include <linux/unistd.h>
+#include <linux/jbd.h>
+#include <linux/ext3_fs.h>
+#include <linux/snap.h>
+#include "snapfs_internal.h"
-#include <asm/system.h>
-#include <asm/uaccess.h>
-
-#include <linux/fs.h>
-#include <linux/stat.h>
-#include <linux/errno.h>
-#include <linux/locks.h>
-#include <linux/string.h>
-#include <asm/uaccess.h>
-#include <linux/malloc.h>
-#include <linux/vmalloc.h>
-#include <asm/segment.h>
-
-#include <linux/filter.h>
-#include <linux/snapfs.h>
-#include <linux/snapsupport.h>
/* Clone is a simple file system, read only that just follows redirectors
we have placed the entire implementation except clone_read_super in
this file
*/
-struct inode_operations clonefs_dir_inode_operations;
-struct inode_operations clonefs_file_inode_operations;
-struct inode_operations clonefs_symlink_inode_operations;
-struct inode_operations clonefs_special_inode_operations;
-struct file_operations clonefs_dir_file_operations;
-struct file_operations clonefs_file_file_operations;
-struct file_operations clonefs_special_file_operations;
+struct inode_operations clonefs_dir_inode_ops;
+struct inode_operations clonefs_file_inode_ops;
+struct inode_operations clonefs_symlink_inode_ops;
+//struct inode_operations clonefs_special_inode_operations;
+struct file_operations clonefs_dir_file_ops;
+struct file_operations clonefs_file_file_ops;
+//struct file_operations clonefs_special_file_operations;
+struct address_space_operations clonefs_file_address_ops;
/* support routines for following redirectors */
redirected_inode = snap_redirect(cache_inode, inode->i_sb);
CDEBUG(D_SNAP, "redirected_inode: %lx, cache_inode %lx\n",
- (ulong) redirected_inode, (ulong) cache_inode);
+ (unsigned long) redirected_inode, (unsigned long) cache_inode);
CDEBUG(D_SNAP, "cache_inode: %lx, ino %ld, sb %lx, count %d\n",
- (ulong) cache_inode, cache_inode->i_ino,
- (ulong) cache_inode->i_sb, cache_inode->i_count);
-
+ (unsigned long) cache_inode, cache_inode->i_ino,
+ (unsigned long) cache_inode->i_sb, atomic_read(&cache_inode->i_count));
+
iput(cache_inode);
- EXIT;
+
return redirected_inode;
}
ENTRY;
CDEBUG(D_SNAP, "inode: %lx, ino %ld, sb %lx, count %d\n",
- (ulong) inode , inode->i_ino, (long) inode->i_sb,
- inode->i_count);
+ (unsigned long)inode, inode->i_ino, (long) inode->i_sb,
+ atomic_read(&inode->i_count));
/* redirecting inode in the cache */
cache_inode = clonefs_get_inode(inode);
if (!cache_inode) {
make_bad_inode(inode);
- EXIT;
return;
}
/* copy attrs of that inode to our clone inode */
snapfs_cpy_attrs(inode, cache_inode);
- if (S_ISREG(inode->i_mode))
- inode->i_op = &clonefs_file_inode_operations;
- else if (S_ISDIR(inode->i_mode))
- inode->i_op = &clonefs_dir_inode_operations;
- else if (S_ISLNK(inode->i_mode))
- inode->i_op = &clonefs_symlink_inode_operations;
- else if (S_ISCHR(inode->i_mode))
- inode->i_op = &chrdev_inode_operations;
- else if (S_ISBLK(inode->i_mode))
- inode->i_op = &blkdev_inode_operations;
- else if (S_ISFIFO(inode->i_mode))
- init_fifo(inode);
-
+ if (S_ISREG(inode->i_mode)) {
+ inode->i_op = &clonefs_file_inode_ops;
+ if (inode->i_mapping)
+ inode->i_mapping->a_ops = &clonefs_file_address_ops;
+ } else if (S_ISDIR(inode->i_mode)) {
+ inode->i_op = &clonefs_dir_inode_ops;
+ } else if (S_ISLNK(inode->i_mode)) {
+ inode->i_op = &clonefs_symlink_inode_ops;
+ } else {
+ /* init special inode
+ * FIXME whether we should replace special inode ops*/
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+ init_special_inode(inode, inode->i_mode,
+ kdev_t_to_nr(inode->i_rdev));
+#else
+ init_special_inode(inode, inode->i_mode, inode->i_rdev);
+#endif
+ }
iput(cache_inode);
CDEBUG(D_SNAP, "cache_inode: %lx ino %ld, sb %lx, count %d\n",
- (ulong) cache_inode, cache_inode->i_ino,
- (ulong) cache_inode->i_sb, cache_inode->i_count);
- EXIT;
- return;
+ (unsigned long) cache_inode, cache_inode->i_ino,
+ (unsigned long) cache_inode->i_sb,
+ atomic_read(&cache_inode->i_count));
+ EXIT;
}
ENTRY;
CDEBUG(D_SUPER, "sb %lx, &sb->u.generic_sbp: %lx\n",
- (ulong) sb, (ulong) &sb->u.generic_sbp);
+ (unsigned long) sb, (unsigned long) &sb->u.generic_sbp);
clone_sb = (struct snap_clone_info *)&sb->u.generic_sbp;
- dput( clone_sb->clone_cache->cache_sb->s_root );
+ dput(clone_sb->clone_cache->cache_sb->s_root);
list_del(&clone_sb->clone_list_entry);
- MOD_DEC_USE_COUNT;
-
EXIT;
}
-static int clonefs_statfs(struct super_block *sb, struct statfs *buf,
- int bufsiz)
+static int clonefs_statfs(struct super_block *sb, struct statfs *buf)
{
struct snap_clone_info *clone_sb;
struct snap_cache *cache;
cache = clone_sb->clone_cache;
if (!cache) {
- printk("clone_statfs: no cache\n");
- return -EINVAL;
+ CERROR("clone_statfs: no cache\n");
+ RETURN(-EINVAL);
}
- EXIT;
return cache->cache_filter->o_caops.cache_sops->statfs
- (cache->cache_sb, buf, bufsiz);
+ (cache->cache_sb, buf);
}
struct super_operations clone_super_ops =
{
- clonefs_read_inode, /* read_inode */
- NULL, /* write_inode */
- NULL, /* put_inode */
- NULL, /* delete_inode */
- NULL, /* notify_change */
- clonefs_put_super, /* put_super */
- NULL, /* write_super */
- clonefs_statfs, /* statfs */
- NULL /* remount_fs */
+ read_inode: clonefs_read_inode, /* read_inode */
+ put_super: clonefs_put_super, /* put_super */
+ statfs: clonefs_statfs, /* statfs */
};
cache_dentry = d_alloc(dentry->d_parent, &dentry->d_name);
if (!cache_dentry) {
iput(cache_dir);
- EXIT;
- return ERR_PTR(-ENOENT);
+ RETURN(ERR_PTR(-ENOENT));
}
/* Lock cache directory inode. */
up(&cache_dir->i_sem);
iput(cache_dir);
dentry->d_inode = NULL;
- EXIT;
- return ERR_PTR(-ENOENT);
+ RETURN(ERR_PTR(-ENOENT));
}
/* Unlock cache directory inode. */
up(&cache_dir->i_sem);
if ( cache_inode != NULL ) {
CDEBUG(D_INODE, "cache ino %ld, count %d, dir %ld, count %d\n",
- cache_inode->i_ino, cache_inode->i_count, cache_dir->i_ino,
- cache_dir->i_count);
+ cache_inode->i_ino, atomic_read(&cache_inode->i_count),
+ cache_dir->i_ino, atomic_read(&cache_dir->i_count));
}
d_unalloc(cache_dentry);
*/
d_add(dentry, inode);
- EXIT;
- return NULL;
+ RETURN(NULL);
}
struct dentry *cache_dentry)
{
ENTRY;
- cache_file->f_pos = clone_file->f_pos;
+
+ cache_file->f_pos = clone_file->f_pos;
cache_file->f_mode = clone_file->f_mode;
cache_file->f_flags = clone_file->f_flags;
cache_file->f_count = clone_file->f_count;
cache_file->f_owner = clone_file->f_owner;
- cache_file->f_op = cache_inode->i_op->default_file_ops;
+ cache_file->f_op = cache_inode->i_fop;
cache_file->f_dentry = cache_dentry;
cache_file->f_dentry->d_inode = cache_inode;
+
EXIT;
- return ;
}
/* update the clonefs file struct after IO in cache file */
struct file *clone_file)
{
ENTRY;
- cache_file->f_pos = clone_file->f_pos;
+
+ cache_file->f_pos = clone_file->f_pos;
cache_inode->i_size = clone_inode->i_size;
+
EXIT;
- return;
}
static int clonefs_readdir(struct file *file, void *dirent,
ENTRY;
if(!inode) {
- EXIT;
- return -EINVAL;
+ RETURN(-EINVAL);
}
cache_inode = clonefs_get_inode(inode);
if (!cache_inode) {
make_bad_inode(inode);
- EXIT;
- return -ENOMEM;
+ RETURN(-ENOMEM);
}
CDEBUG(D_INODE,"clone ino %ld\n",cache_inode->i_ino);
}
clonefs_restore_snapfile(inode, file, cache_inode, &open_file);
iput(cache_inode);
- EXIT;
- return result;
+ RETURN(result);
}
-struct file_operations clonefs_dir_file_operations = {
- NULL, /* lseek */
- NULL, /* read -- bad */
- NULL, /* write */
- clonefs_readdir, /* readdir */
- NULL, /* select */
- NULL, /* ioctl */
- NULL, /* mmap */
- NULL, /* open */
- NULL,
- NULL, /* release */
- NULL, /* fsync */
- NULL,
- NULL,
- NULL
+struct file_operations clonefs_dir_file_ops = {
+ readdir: clonefs_readdir, /* readdir */
};
-struct inode_operations clonefs_dir_inode_operations =
-{
- &clonefs_dir_file_operations,
- NULL, /* create */
- clonefs_lookup, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* bmap */
- NULL, /* truncate */
- NULL, /* permission */
- NULL, /* smap */
- NULL, /* update page */
- NULL, /* revalidate */
+struct inode_operations clonefs_dir_inode_ops = {
+ lookup: clonefs_lookup, /* lookup */
};
/* ***************** end of clonefs dir ops ******************* */
/* ***************** begin clonefs file ops ******************* */
-int clonefs_readpage(struct file *file, struct page *page)
+static int clonefs_readpage(struct file *file, struct page *page)
{
int result = 0;
struct inode *cache_inode;
cache_inode = clonefs_get_inode(file->f_dentry->d_inode);
if (!cache_inode) {
make_bad_inode(file->f_dentry->d_inode);
- EXIT;
- return -ENOMEM;
+ RETURN(-ENOMEM);
}
clonefs_prepare_snapfile(inode, file, cache_inode, &open_file,
/* potemkin case: we are handed a directory inode */
down(&cache_inode->i_sem);
/* XXX - readpage NULL on directories... */
- if (cache_inode->i_op->readpage == NULL)
- printk("Yes, Grigori, directories are a problem.\n");
- else
- cache_inode->i_op->readpage(&open_file, page);
+ result = cache_inode->i_mapping->a_ops->readpage(&open_file, page);
+
up(&cache_inode->i_sem);
clonefs_restore_snapfile(inode, file, cache_inode, &open_file);
iput(cache_inode);
- EXIT;
- return result;
+ RETURN(result);
}
-
-struct file_operations clonefs_file_file_operations = {
- NULL, /* lseek */
- generic_file_read, /* read -- bad */
- NULL, /* write */
- NULL, /* readdir */
- NULL, /* select */
- NULL, /* ioctl */
- generic_file_mmap, /* mmap */
- NULL, /* open */
- NULL,
- NULL, /* release */
- NULL, /* fsync */
- NULL,
- NULL,
- NULL
+struct file_operations clonefs_file_file_ops = {
+ read: generic_file_read, /* read -- bad */
+ mmap: generic_file_mmap, /* mmap */
};
-struct inode_operations clonefs_file_inode_operations =
-{
- &clonefs_file_file_operations,
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- clonefs_readpage, /* readpage */
- NULL, /* writepage */
- NULL, /* bmap */
- NULL, /* truncate */
- NULL, /* permission */
- NULL, /* smap */
- NULL, /* update page */
- NULL, /* revalidate */
+struct address_space_operations clonefs_file_address_ops = {
+ readpage: clonefs_readpage
};
-
/* ***************** end of clonefs file ops ******************* */
/* ***************** begin clonefs symlink ops ******************* */
-int clonefs_readlink(struct dentry *dentry, char *buf, int len)
+static int clonefs_readlink(struct dentry *dentry, char *buf, int len)
{
int res;
struct inode * cache_inode;
if ( ! cache_inode ) {
CDEBUG(D_INODE, "clonefs_get_inode failed, NULL\n");
- EXIT;
- return res;
+ RETURN(res);
}
/* XXX: shall we allocate a new dentry ?
- The following is safe for ext2, etc. because ext2_readlink only
+ The following is safe for ext3, etc. because ext2_readlink only
use the inode info */
/* save the old dentry inode */
iput(cache_inode);
- EXIT;
- return res;
+ RETURN(res);
}
-struct dentry * clonefs_follow_link(struct dentry * dentry,
- struct dentry *base,
- unsigned int follow)
+static int clonefs_follow_link(struct dentry * dentry, struct nameidata *nd)
{
- struct dentry * res;
struct inode * cache_inode;
struct inode * old_inode;
+ int res;
ENTRY;
- res = ERR_PTR(-ENOENT);
cache_inode = clonefs_get_inode(dentry->d_inode);
if ( ! cache_inode ) {
CDEBUG(D_INODE, "clonefs_get_inode failed, NULL\n");
- EXIT;
- return res;
+ RETURN(-ENOENT);
}
/* XXX: shall we allocate a new dentry ?
dentry->d_inode = cache_inode;
if ( cache_inode->i_op->follow_link ) {
- res = cache_inode->i_op->follow_link(dentry, base, follow);
+ res = cache_inode->i_op->follow_link(dentry, nd);
}
/* restore the old inode */
iput(cache_inode);
- EXIT;
- return res;
+ RETURN(res);
}
-struct inode_operations clonefs_symlink_inode_operations =
+struct inode_operations clonefs_symlink_inode_ops =
{
- NULL, /* no file operations */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- clonefs_readlink, /* readlink */
- clonefs_follow_link,/* follow_link */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* bmap */
- NULL, /* truncate */
- NULL, /* permission */
- NULL, /* smap */
- NULL, /* update page */
- NULL, /* revalidate */
+ /*FIXME later getxattr, listxattr,
+ * other method need to be replaced too
+ * */
+ readlink: clonefs_readlink, /* readlink */
+ follow_link: clonefs_follow_link,/* follow_link */
};
* Directory operations for SnapFS filesystem
*/
-#include <linux/types.h>
+#define DEBUG_SUBSYSTEM S_SNAP
+
+#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/fs.h>
-#include <linux/stat.h>
-#include <linux/errno.h>
-#include <linux/locks.h>
-#include <asm/segment.h>
-#include <asm/uaccess.h>
#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/stat.h>
+#include <linux/unistd.h>
+#include <linux/jbd.h>
+#include <linux/ext3_fs.h>
+#include <linux/snap.h>
+
+#include "snapfs_internal.h"
-#include <linux/filter.h>
-#include <linux/snapfs.h>
-#include <linux/snapsupport.h>
/* called when a cache lookup succeeds */
return 0;
}
#else
- return 1;
+ RETURN(1);
#endif
}
/*
* dir.c
*/
+#define DEBUG_SUBSYSTEM S_SNAP
-#define EXPORT_SYMTAB
-
-
-#define __NO_VERSION__
#include <linux/module.h>
-#include <asm/uaccess.h>
-#include <linux/sched.h>
-#include <linux/stat.h>
+#include <linux/kernel.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>
+#include <linux/slab.h>
+#include <linux/stat.h>
+#include <linux/unistd.h>
+#include <linux/jbd.h>
+#include <linux/ext3_fs.h>
+#include <linux/snap.h>
-#include <linux/filter.h>
-#include <linux/snapfs.h>
-#include <linux/snapsupport.h>
-
-#ifdef CONFIG_SNAPFS_EXT3
-void ext3_orphan_del(handle_t *handle, struct inode *inode);
-#endif
+#include "snapfs_internal.h"
static ino_t get_parent_ino(struct inode * inode)
{
struct dentry * dentry;
if (list_empty(&inode->i_dentry)) {
- printk("snapfs ERROR: no dentry for ino %lu\n", inode->i_ino);
+ CERROR("No dentry for ino %lu\n", inode->i_ino);
return 0;
}
cache = snap_find_cache(dir->i_dev);
if ( !cache ) {
- EXIT;
- return ERR_PTR(-EINVAL);
+ RETURN(ERR_PTR(-EINVAL));
}
if ( dentry->d_name.len == strlen(".snap") &&
/* Don't permit .snap in clonefs */
if( dentry->d_sb != cache->cache_sb )
- return ERR_PTR(-ENOENT);
+ RETURN(ERR_PTR(-ENOENT));
/* Don't permit .snap under .snap */
if( currentfs_is_under_dotsnap(dentry) )
- return ERR_PTR(-ENOENT);
+ RETURN(ERR_PTR(-ENOENT));
ino = 0xF0000000 | dir->i_ino;
snap = iget(dir->i_sb, ino);
CDEBUG(D_INODE, ".snap inode ino %ld, mode %o\n", snap->i_ino, snap->i_mode);
d_add(dentry, snap);
- EXIT;
- return NULL;
+ RETURN(NULL);
}
iops = filter_c2cdiops(cache->cache_filter);
if (!iops || !iops->lookup) {
- EXIT;
- return ERR_PTR(-EINVAL);
+ RETURN(ERR_PTR(-EINVAL));
}
rc = iops->lookup(dir, dentry);
if ( rc || !dentry->d_inode) {
- EXIT;
- return NULL;
+ RETURN(NULL);
}
/*
dentry->d_fsdata = (void*)pri_ino;
}
- EXIT;
- return NULL;
+ RETURN(NULL);
#if 0
/* XXX: PJB these need to be set up again. See dcache.c */
err_out:
d_unadd_iput(dentry);
- EXIT;
- return ERR_PTR(-EINVAL);
+ RETURN(ERR_PTR(-EINVAL));
}
static int currentfs_create(struct inode *dir, struct dentry *dentry, int mode)
{
- struct snap_cache *cache;
- int rc;
+ struct snap_cache *cache;
struct inode_operations *iops;
- void *handle = NULL;
+ struct snapshot_operations *snapops;
+ void *handle = NULL;
+ int rc;
ENTRY;
if (currentfs_is_under_dotsnap(dentry)) {
- EXIT;
- return -EPERM;
+ RETURN(-EPERM);
}
cache = snap_find_cache(dir->i_dev);
if ( !cache ) {
- EXIT;
- return -EINVAL;
+ RETURN(-EINVAL);
}
+ snapops = filter_c2csnapops(cache->cache_filter);
+ if (!snapops || !snapops->get_generation)
+ RETURN(-EINVAL);
+
handle = snap_trans_start(cache, dir, SNAP_OP_CREATE);
if ( snap_needs_cow(dir) != -1 ) {
- printk("snap_needs_cow for ino %lu \n",dir->i_ino);
+ CDEBUG(D_INODE, "snap_needs_cow for ino %lu \n",dir->i_ino);
snap_debug_device_fail(dir->i_dev, SNAP_OP_CREATE, 1);
- snap_do_cow(dir, get_parent_ino(dir), 0);
+ if (!(snap_do_cow(dir, get_parent_ino(dir), 0))) {
+ CERROR("Do cow error\n");
+ RETURN(-EINVAL);
+ }
}
iops = filter_c2cdiops(cache->cache_filter);
- if (!iops ||
- !iops->create) {
- rc = -EINVAL;
- goto exit;
+ if (!iops || !iops->create) {
+ RETURN(-EINVAL);
}
snap_debug_device_fail(dir->i_dev, SNAP_OP_CREATE, 2);
rc = iops->create(dir, dentry, mode);
/* XXX now set the correct snap_{file,dir,sym}_iops */
- if ( ! dentry->d_inode) {
- printk("Error in currentfs_create, dentry->d_inode is NULL\n");
- goto exit;
+ if (!dentry->d_inode) {
+ CERROR("Error in currentfs_create, dentry->d_inode is NULL\n");
+ GOTO(exit, 0);
}
- if ( S_ISDIR(dentry->d_inode->i_mode) )
+ if (S_ISDIR(dentry->d_inode->i_mode))
dentry->d_inode->i_op = filter_c2udiops(cache->cache_filter);
- else if ( S_ISREG(dentry->d_inode->i_mode) ) {
- if ( !filter_c2cfiops(cache->cache_filter) ) {
- filter_setup_file_ops(cache->cache_filter,
- dentry->d_inode->i_op, ¤tfs_file_iops);
+ else if (S_ISREG(dentry->d_inode->i_mode)) {
+ if (!filter_c2cfiops(cache->cache_filter)) {
+ filter_setup_file_ops(cache->cache_filter, dentry->d_inode,
+ ¤tfs_file_iops, ¤tfs_file_fops,
+ ¤tfs_file_aops);
}
dentry->d_inode->i_op = filter_c2ufiops(cache->cache_filter);
}
- printk("inode %lu, i_op %p\n", dentry->d_inode->i_ino, dentry->d_inode->i_op);
-
+ CDEBUG(D_INODE, "inode %lu, i_op %p\n", dentry->d_inode->i_ino, dentry->d_inode->i_op);
snap_debug_device_fail(dir->i_dev, SNAP_OP_CREATE, 3);
-
-exit:
+ init_filter_data(dentry->d_inode, snapops, 0); exit:
snap_trans_commit(cache, handle);
- EXIT;
- return rc;
+ RETURN(rc);
}
static int currentfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
ENTRY;
if (currentfs_is_under_dotsnap(dentry)) {
- EXIT;
- return -EPERM;
+ RETURN(-EPERM);
}
cache = snap_find_cache(dir->i_dev);
if ( !cache ) {
- EXIT;
- return -EINVAL;
+ RETURN(-EINVAL);
}
handle = snap_trans_start(cache, dir, SNAP_OP_MKDIR);
if ( snap_needs_cow(dir) != -1 ) {
- CDEBUG(D_FILE, "snap_needs_cow for ino %lu \n",dir->i_ino);
+ CDEBUG(D_INODE, "snap_needs_cow for ino %lu \n",dir->i_ino);
snap_debug_device_fail(dir->i_dev, SNAP_OP_MKDIR, 1);
snap_do_cow(dir, get_parent_ino(dir), 0);
}
iops = filter_c2cdiops(cache->cache_filter);
- if (!iops ||
- !iops->mkdir) {
+ if (!iops || !iops->mkdir) {
rc = -EINVAL;
goto exit;
}
/* XXX now set the correct snap_{file,dir,sym}_iops */
if ( dentry->d_inode) {
dentry->d_inode->i_op = filter_c2udiops(cache->cache_filter);
- printk("inode %lu, i_op %p\n", dentry->d_inode->i_ino, dentry->d_inode->i_op);
+ CDEBUG(D_INODE, "inode %lu, i_op %p\n", dentry->d_inode->i_ino, dentry->d_inode->i_op);
} else {
- printk("Error in currentfs_mkdir, dentry->d_inode is NULL\n");
+ CERROR("Error in currentfs_mkdir, dentry->d_inode is NULL\n");
}
snap_debug_device_fail(dir->i_dev, SNAP_OP_MKDIR, 3);
exit:
snap_trans_commit(cache, handle);
- EXIT;
- return rc;
+ RETURN(rc);
}
static int currentfs_link (struct dentry * old_dentry, struct inode * dir,
ENTRY;
- if (currentfs_is_under_dotsnap(dentry)) {
- EXIT;
- return -EPERM;
- }
+ if (currentfs_is_under_dotsnap(dentry))
+ RETURN(-EPERM);
cache = snap_find_cache(dir->i_dev);
- if ( !cache ) {
- EXIT;
- return -EINVAL;
- }
+ if ( !cache )
+ RETURN(-EINVAL);
handle = snap_trans_start(cache, dir, SNAP_OP_LINK);
if ( snap_needs_cow(dir) != -1 ) {
- printk("snap_needs_cow for ino %lu \n",dir->i_ino);
+ CDEBUG(D_INODE, "snap_needs_cow for ino %lu \n",dir->i_ino);
snap_debug_device_fail(dir->i_dev, SNAP_OP_LINK, 1);
snap_do_cow(dir, get_parent_ino(dir), 0);
}
if ( snap_needs_cow(old_dentry->d_inode) != -1 ) {
- printk("snap_needs_cow for ino %lu \n",old_dentry->d_inode->i_ino);
+ CDEBUG(D_INODE, "snap_needs_cow for ino %lu \n",old_dentry->d_inode->i_ino);
snap_debug_device_fail(dir->i_dev, SNAP_OP_LINK, 2);
snap_do_cow(old_dentry->d_inode, dir->i_ino, 0);
}
iops = filter_c2cdiops(cache->cache_filter);
- if (!iops ||
- !iops->link) {
- rc = -EINVAL;
- goto exit;
- }
+
+ if (!iops || !iops->link)
+ GOTO(exit, rc = -EINVAL);
+
snap_debug_device_fail(dir->i_dev, SNAP_OP_LINK, 2);
rc = iops->link(old_dentry,dir, dentry);
snap_debug_device_fail(dir->i_dev, SNAP_OP_LINK, 3);
-
exit:
snap_trans_commit(cache, handle);
- EXIT;
- return rc;
+ RETURN(rc);
}
static int currentfs_symlink(struct inode *dir, struct dentry *dentry,
ENTRY;
cache = snap_find_cache(dir->i_dev);
- if ( !cache ) {
- EXIT;
- return -EINVAL;
- }
+ if (!cache)
+ RETURN(-EINVAL);
handle = snap_trans_start(cache, dir, SNAP_OP_SYMLINK);
if ( snap_needs_cow(dir) != -1 ) {
- printk("snap_needs_cow for ino %lu \n",dir->i_ino);
+ CDEBUG(D_INODE, "snap_needs_cow for ino %lu \n",dir->i_ino);
snap_debug_device_fail(dir->i_dev, SNAP_OP_SYMLINK, 1);
snap_do_cow(dir, get_parent_ino(dir), 0);
}
iops = filter_c2cdiops(cache->cache_filter);
- if (!iops ||
- !iops->symlink) {
- rc = -EINVAL;
- goto exit;
- }
+ if (!iops || !iops->symlink)
+ GOTO(exit, rc = -EINVAL);
+
snap_debug_device_fail(dir->i_dev, SNAP_OP_SYMLINK, 2);
rc = iops->symlink(dir, dentry, symname);
snap_debug_device_fail(dir->i_dev, SNAP_OP_SYMLINK, 3);
exit:
snap_trans_commit(cache, handle);
- EXIT;
- return rc;
+ RETURN(rc);
}
static int currentfs_mknod(struct inode *dir, struct dentry *dentry, int mode,
ENTRY;
if (currentfs_is_under_dotsnap(dentry)) {
- EXIT;
- return -EPERM;
+ RETURN(-EPERM);
}
cache = snap_find_cache(dir->i_dev);
if ( !cache ) {
- EXIT;
- return -EINVAL;
+ RETURN(-EINVAL);
}
handle = snap_trans_start(cache, dir, SNAP_OP_MKNOD);
if ( snap_needs_cow(dir) != -1 ) {
- printk("snap_needs_cow for ino %lu \n",dir->i_ino);
+ CDEBUG(D_INODE, "snap_needs_cow for ino %lu \n",dir->i_ino);
snap_debug_device_fail(dir->i_dev, SNAP_OP_MKNOD, 1);
snap_do_cow(dir, get_parent_ino(dir), 0);
}
iops = filter_c2cdiops(cache->cache_filter);
- if (!iops ||
- !iops->mknod) {
- rc = -EINVAL;
- goto exit;
- }
+ if (!iops || !iops->mknod)
+ GOTO(exit, rc = -EINVAL);
+
snap_debug_device_fail(dir->i_dev, SNAP_OP_MKNOD, 2);
rc = iops->mknod(dir, dentry, mode, rdev);
snap_debug_device_fail(dir->i_dev, SNAP_OP_MKNOD, 3);
exit:
snap_trans_commit(cache, handle);
- EXIT;
- return rc;
+ RETURN(rc);
}
static int currentfs_rmdir(struct inode *dir, struct dentry *dentry)
ENTRY;
if (currentfs_is_under_dotsnap(dentry)) {
- EXIT;
- return -EPERM;
+ RETURN(-EPERM);
}
cache = snap_find_cache(dir->i_dev);
if ( !cache ) {
- EXIT;
- return -EINVAL;
+ RETURN(-EINVAL);
}
handle = snap_trans_start(cache, dir, SNAP_OP_RMDIR);
if ( snap_needs_cow(dir) != -1 ) {
- printk("snap_needs_cow for ino %lu \n",dir->i_ino);
+ CDEBUG(D_INODE, "snap_needs_cow for ino %lu \n",dir->i_ino);
snap_debug_device_fail(dir->i_dev, SNAP_OP_RMDIR, 1);
snap_do_cow(dir, get_parent_ino(dir), 0);
}
iops = filter_c2cdiops(cache->cache_filter);
- if (!iops ||
- !iops->rmdir) {
- rc = -EINVAL;
- goto exit;
- }
+ if (!iops || !iops->rmdir)
+ GOTO(exit, rc = -EINVAL);
/* XXX : there are two cases that we can't remove this inode from disk.
1. the inode needs to be cowed.
will not be deleted after rmdir, will only remove dentry
*/
- if( snap_needs_cow(dentry->d_inode) != -1) {
+ if (snap_needs_cow(dentry->d_inode) != -1 ||
+ snap_is_redirector(dentry->d_inode)) {
snap_debug_device_fail(dir->i_dev, SNAP_OP_RMDIR, 2);
- snap_do_cow (dentry->d_inode, dir->i_ino,
- SNAP_DEL_PRI_WITHOUT_IND);
+ snap_do_cow (dir, get_parent_ino(dir), SNAP_CREATE_IND_DEL_PRI);
keep_inode = 1;
}
- else if( snap_is_redirector(dentry->d_inode) ) {
- snap_debug_device_fail(dir->i_dev, SNAP_OP_RMDIR, 3);
- snap_do_cow(dentry->d_inode, dir->i_ino, SNAP_DEL_PRI_WITH_IND);
- keep_inode = 1;
- }
#if 0
if ( keep_inode ) {
printk("set up dentry ops, before %p\n",dentry->d_op);
// i_ctime = dentry->d_inode->i_ctime;
i_nlink = dentry->d_inode->i_nlink;
i_size = dentry->d_inode->i_size;
-
-}
+ }
snap_debug_device_fail(dir->i_dev, SNAP_OP_RMDIR, 4);
rc = iops->rmdir(dir, dentry);
snap_debug_device_fail(dir->i_dev, SNAP_OP_RMDIR, 6);
}
}
-
exit:
snap_trans_commit(cache, handle);
EXIT;
ENTRY;
if (currentfs_is_under_dotsnap(dentry)) {
- EXIT;
- return -EPERM;
+ RETURN(-EPERM);
}
cache = snap_find_cache(dir->i_dev);
if ( !cache ) {
- EXIT;
- return -EINVAL;
+ RETURN(-EINVAL);
}
handle = snap_trans_start(cache, dir, SNAP_OP_UNLINK);
if ( snap_needs_cow(dir) != -1 ) {
- printk("snap_needs_cow for ino %lu \n",dir->i_ino);
+ CDEBUG(D_INODE, "snap_needs_cow for ino %lu \n",dir->i_ino);
snap_debug_device_fail(dir->i_dev, SNAP_OP_UNLINK, 1);
snap_do_cow(dir, get_parent_ino(dir), 0);
}
iops = filter_c2cdiops(cache->cache_filter);
- if (!iops ||
- !iops->unlink) {
+ if (!iops || !iops->unlink) {
rc = -EINVAL;
goto exit;
}
if( snap_needs_cow (inode) != -1) {
/* call snap_do_cow with DEL_WITHOUT_IND option */
snap_debug_device_fail(dir->i_dev, SNAP_OP_UNLINK, 2);
- snap_do_cow(inode, dir->i_ino,SNAP_DEL_PRI_WITHOUT_IND);
+ snap_do_cow(inode, dir->i_ino, SNAP_CREATE_IND_DEL_PRI);
if( inode->i_nlink == 1 )
inode->i_nlink++;
- }
- else if( snap_is_redirector (inode) && inode->i_nlink == 1 ) {
+ } else if (snap_is_redirector (inode) && inode->i_nlink == 1) {
/* call snap_do_cow with DEL_WITH_IND option
* just free the blocks of inode, not really delete it
*/
snap_debug_device_fail(dir->i_dev, SNAP_OP_UNLINK, 3);
- snap_do_cow (inode, dir->i_ino, SNAP_DEL_PRI_WITH_IND);
+ snap_do_cow (inode, dir->i_ino, SNAP_CREATE_IND_DEL_PRI);
inode->i_nlink++;
- }
+ }
snap_debug_device_fail(dir->i_dev, SNAP_OP_UNLINK, 4);
rc = iops->unlink(dir, dentry);
exit:
snap_trans_commit(cache, handle);
- EXIT;
- return rc;
+ RETURN(rc);
}
static int currentfs_rename (struct inode * old_dir, struct dentry *old_dentry,
if (currentfs_is_under_dotsnap(old_dentry) ||
currentfs_is_under_dotsnap(new_dentry)) {
- EXIT;
- return -EPERM;
+ RETURN(-EPERM);
}
cache = snap_find_cache(old_dir->i_dev);
if ( !cache ) {
- EXIT;
- return -EINVAL;
+ RETURN(-EINVAL);
}
handle = snap_trans_start(cache, old_dir, SNAP_OP_RENAME);
/* Always cow the old dir and old dentry->d_inode */
if ( snap_needs_cow(old_dir) != -1 ) {
- printk("rename: needs_cow for old_dir %lu\n",old_dir->i_ino);
+ CDEBUG(D_INODE, "rename: needs_cow for old_dir %lu\n",old_dir->i_ino);
snap_debug_device_fail(old_dir->i_dev, SNAP_OP_RENAME, 1);
snap_do_cow(old_dir, get_parent_ino(old_dir), 0);
}
if( snap_needs_cow (old_dentry->d_inode) != -1) {
- printk("rename: needs_cow for old_dentry, ino %lu\n",
+ CDEBUG(D_INODE, "rename: needs_cow for old_dentry, ino %lu\n",
old_dentry->d_inode->i_ino);
snap_debug_device_fail(old_dir->i_dev, SNAP_OP_RENAME, 2);
snap_do_cow(old_dentry->d_inode, old_dir->i_ino,0);
*/
if(( old_dir != new_dir) ) {
if( snap_needs_cow(new_dir) !=-1 ){
- printk("rename:snap_needs_cow for new_dir %lu\n",
+ CDEBUG(D_INODE, "rename:snap_needs_cow for new_dir %lu\n",
new_dir->i_ino);
snap_debug_device_fail(old_dir->i_dev,SNAP_OP_RENAME,3);
- snap_do_cow(new_dir, get_parent_ino(new_dir),0);
+ snap_do_cow(new_dir, get_parent_ino(new_dir), 0);
}
}
/* call snap_do_cow with DEL_WITHOUT_IND option */
snap_debug_device_fail(old_dir->i_dev,SNAP_OP_RENAME,4);
snap_do_cow(new_dentry->d_inode, new_dir->i_ino,
- SNAP_DEL_PRI_WITHOUT_IND);
+ SNAP_CREATE_IND_DEL_PRI);
new_dentry->d_inode->i_nlink++;
}
else if( snap_is_redirector (new_dentry->d_inode) ) {
*/
snap_debug_device_fail(old_dir->i_dev,SNAP_OP_RENAME,4);
snap_do_cow (new_dentry->d_inode, new_dir->i_ino,
- SNAP_DEL_PRI_WITH_IND);
+ SNAP_CREATE_IND_DEL_PRI);
new_dentry->d_inode->i_nlink++;
}
}
iops = filter_c2cdiops(cache->cache_filter);
- if (!iops ||
- !iops->rename) {
+ if (!iops || !iops->rename) {
rc = -EINVAL;
goto exit;
}
exit:
snap_trans_commit(cache, handle);
- EXIT;
- return rc;
+ RETURN(rc);
}
static int currentfs_readdir(struct file *filp, void *dirent,
ENTRY;
if( !filp || !filp->f_dentry || !filp->f_dentry->d_inode ) {
- EXIT;
- return -EINVAL;
+ RETURN(-EINVAL);
}
cache = snap_find_cache(filp->f_dentry->d_inode->i_dev);
if ( !cache ) {
- EXIT;
- return -EINVAL;
+ RETURN(-EINVAL);
}
fops = filter_c2cdfops( cache->cache_filter );
if( !fops ) {
- EXIT;
- return -EINVAL;
+ RETURN(-EINVAL);
}
/*
if( filp->f_pos == 0 ){
if( filldir(dirent, ".snap",
strlen(".snap")+1, filp->f_pos,
- 0xF0000000|filp->f_dentry->d_inode->i_ino) ){
+ -1, 0) ){
return -EINVAL;
}
filp->f_pos += strlen(".snap")+1;
}else
rc = fops->readdir(filp, dirent, filldir);
- return rc;
+ RETURN(rc);
}
struct file_operations currentfs_dir_fops = {
};
struct inode_operations currentfs_dir_iops = {
- default_file_ops: ¤tfs_dir_fops,
- create: currentfs_create,
- mkdir: currentfs_mkdir,
- link: currentfs_link,
- symlink: currentfs_symlink,
- mknod: currentfs_mknod,
- rmdir: currentfs_rmdir,
- unlink: currentfs_unlink,
- rename: currentfs_rename,
- lookup: currentfs_lookup
+ create: currentfs_create,
+ mkdir: currentfs_mkdir,
+ link: currentfs_link,
+ symlink: currentfs_symlink,
+ mknod: currentfs_mknod,
+ rmdir: currentfs_rmdir,
+ unlink: currentfs_unlink,
+ rename: currentfs_rename,
+ lookup: currentfs_lookup
};
* dotsnap.c - support for .snap directories
*/
-#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/kernel.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>
+#include <linux/slab.h>
+#include <linux/stat.h>
+#include <linux/unistd.h>
+#include <linux/jbd.h>
+#include <linux/ext3_fs.h>
+#include <linux/snap.h>
-#include <linux/filter.h>
-#include <linux/snapfs.h>
-#include <linux/snapsupport.h>
+#include "snapfs_internal.h"
struct inode_operations dotsnap_inode_operations;
struct file_operations dotsnap_file_operations;
de = de->d_parent;
}
- EXIT;
- return 0;
+ RETURN(0);
}
void currentfs_dotsnap_read_inode(struct snap_cache *cache,
cache = snap_find_cache(dir->i_dev);
if ( !cache ) {
- printk("dotsnap_readdir: cannot find cache\n");
+ CERROR("dotsnap_readdir: cannot find cache\n");
make_bad_inode(dir);
- EXIT;
- return ERR_PTR(-EINVAL);
+ RETURN(ERR_PTR(-EINVAL));
}
snapops = filter_c2csnapops(cache->cache_filter);
if (!snapops || !snapops->get_indirect_ino) {
- EXIT;
- return ERR_PTR(-EINVAL);
+ RETURN(ERR_PTR(-EINVAL));
}
tableno = cache->cache_snap_tableno;
table = &snap_tables[tableno];
if( table->tbl_count <= 1 )
- return NULL;
+ RETURN(NULL);
- index = table->tbl_index[0];
+ index = table->snap_items[0].index;;
for ( i = 1 ; i < table->tbl_count ; i++ ) {
- if ( (dentry->d_name.len == strlen(table->tbl_name[i])) &&
- (memcmp(dentry->d_name.name, table->tbl_name[i],
+ if ( (dentry->d_name.len == strlen(table->snap_items[i].name)) &&
+ (memcmp(&dentry->d_name.name[0], &table->snap_items[i].name[0],
dentry->d_name.len) == 0) ) {
- index = table->tbl_index[i];
+ index = table->snap_items[i].index;
break;
}
}
if( i >= table->tbl_count )
- return ERR_PTR(-ENOENT);
+ RETURN(ERR_PTR(-ENOENT));
inode = iget(dir->i_sb, dir->i_ino & (~0xF0000000));
if ( !inode )
- return ERR_PTR(-EINVAL);
+ RETURN(ERR_PTR(-EINVAL));
ino = snapops->get_indirect_ino(inode, index);
iput(inode);
}
if ( ino == -EINVAL ) {
- return ERR_PTR(-EINVAL);
+ RETURN(ERR_PTR(-EINVAL));
}
-CDEBUG(D_INODE, "index %d, ino is %lu\n",index, ino);
+ CDEBUG(D_INODE, "index %d, ino is %lu\n",index, ino);
inode = iget(dir->i_sb, ino);
d_add(dentry, inode);
dentry->d_fsdata = (void*)index;
inode->i_op = dentry->d_parent->d_parent->d_inode->i_op;
- return NULL;
+ RETURN(NULL);
}
cache = snap_find_cache(filp->f_dentry->d_inode->i_dev);
if ( !cache ) {
- printk("dotsnap_readdir: cannot find cache\n");
+ CDEBUG(D_INODE, "dotsnap_readdir: cannot find cache\n");
make_bad_inode(filp->f_dentry->d_inode);
- EXIT;
- return -EINVAL;
+ RETURN(-EINVAL);
}
snapops = filter_c2csnapops(cache->cache_filter);
if (!snapops || !snapops->get_indirect_ino) {
- EXIT;
- return -EINVAL;
+ RETURN(-EINVAL);
}
tableno = cache->cache_snap_tableno;
table = &snap_tables[tableno];
- CDEBUG(D_INODE, "\n");
for (i = filp->f_pos ; i < table->tbl_count -1 ; i++) {
int index;
struct inode *inode;
ino_t ino;
- CDEBUG(D_INODE, "%d\n",i);
inode = filp->f_dentry->d_inode;
- index = table->tbl_index[i+1];
+ index = table->snap_items[i+1].index;
ino = snapops->get_indirect_ino
(filp->f_dentry->d_inode, index);
- CDEBUG(D_INODE, "\n");
-
if ( ino == -ENOATTR || ino == 0 ) {
ino = filp->f_dentry->d_parent->d_inode->i_ino;
}
-
- CDEBUG(D_INODE, "\n");
+
if ( ino == -EINVAL ) {
return -EINVAL;
}
- CDEBUG(D_INODE, "Listing %s\n", table->tbl_name[i+1]);
- if (filldir(dirent, table->tbl_name[i+1],
- strlen(table->tbl_name[i+1]),
- filp->f_pos, ino) < 0){
+ CDEBUG(D_INODE, "Listing %s\n", &table->snap_items[i+1].name[0]);
+ if (filldir(dirent, &table->snap_items[i+1].name[0],
+ strlen(&table->snap_items[i+1].name[0]),
+ filp->f_pos, ino, 0) < 0){
CDEBUG(D_INODE, "\n");
break;
}
filp->f_pos++;
}
- EXIT;
- return 0;
+ RETURN(0);
}
struct inode_operations dotsnap_inode_operations =
{
- default_file_ops: &dotsnap_file_operations,
lookup: dotsnap_lookup
};
* file.c
*/
-#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/kernel.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>
+#include <linux/slab.h>
+#include <linux/stat.h>
+#include <linux/unistd.h>
+#include <linux/jbd.h>
+#include <linux/ext3_fs.h>
+#include <linux/snap.h>
-#include <linux/filter.h>
-#include <linux/snapfs.h>
-#include <linux/snapsupport.h>
+#include "snapfs_internal.h"
/* instantiate a file handle to the cache file */
static void currentfs_prepare_snapfile(struct inode *inode,
struct file *cache_file,
struct dentry *cache_dentry)
{
- ENTRY;
cache_file->f_pos = clone_file->f_pos;
cache_file->f_mode = clone_file->f_mode;
cache_file->f_flags = clone_file->f_flags;
cache_file->f_count = clone_file->f_count;
cache_file->f_owner = clone_file->f_owner;
- cache_file->f_op = cache_inode->i_op->default_file_ops;
cache_file->f_dentry = cache_dentry;
cache_file->f_dentry->d_inode = cache_inode;
- EXIT;
- return ;
}
/* update the currentfs file struct after IO in cache file */
struct inode *clone_inode,
struct file *clone_file)
{
- ENTRY;
cache_file->f_pos = clone_file->f_pos;
- EXIT;
- return;
}
struct snap_table *table;
int slot = 0;
int index = 0;
- struct inode_operations *ciops;
+ struct address_space_operations *aops;
struct inode *cache_inode = NULL;
struct snapshot_operations *snapops;
ENTRY;
- if (currentfs_is_under_dotsnap(filp->f_dentry)) {
- EXIT;
- return -ENOSPC;
- }
+ if (currentfs_is_under_dotsnap(filp->f_dentry))
+ RETURN(-ENOSPC);
cache = snap_find_cache(inode->i_dev);
- if ( !cache ) {
- EXIT;
- return -EINVAL;
- }
+ if ( !cache )
+ RETURN(-EINVAL);
if ( snap_needs_cow(inode) != -1 ) {
- CDEBUG(D_FILE, "snap_needs_cow for ino %lu \n",inode->i_ino);
+ CDEBUG(D_SNAP, "snap_needs_cow for ino %lu \n",inode->i_ino);
snap_do_cow(inode, filp->f_dentry->d_parent->d_inode->i_ino, 0);
}
fops = filter_c2cffops(cache->cache_filter);
- if (!fops ||
- !fops->write) {
- EXIT;
- return -EINVAL;
- }
+ if (!fops || !fops->write)
+ RETURN(-EINVAL);
if (filp->f_flags & O_APPEND)
pos = inode->i_size;
else {
pos = *ppos;
if (pos != *ppos)
- return -EINVAL;
+ RETURN(-EINVAL);
}
/*
block[1] = pos >> inode->i_sb->s_blocksize_bits;
if( block[0] == block[1] )
block[1] = -1;
-
- ciops = filter_c2cfiops(cache->cache_filter);
+
+ aops = filter_c2cfaops(cache->cache_filter);
snapops = filter_c2csnapops(cache->cache_filter);
for( i=0; i<2; i++ ){
- if( block[i]!=-1 && !ciops->bmap(inode, block[i]) ) {
+ if(block[i]!=-1 && aops->bmap(inode->i_mapping, block[i])) {
table = &snap_tables[cache->cache_snap_tableno];
- for (slot = table->tbl_count ; slot >= 1; slot--)
- {
+ for (slot = table->tbl_count ; slot >= 1; slot--) {
+ struct address_space_operations *c_aops =
+ cache_inode->i_mapping->a_ops;
cache_inode = NULL;
- index = table->tbl_index[slot];
+ index = table->snap_items[slot].index;
cache_inode = snap_get_indirect(inode, NULL, index);
if ( !cache_inode ) continue;
- if (cache_inode->i_op->bmap(cache_inode, block[i])) {
- CDEBUG(D_FILE, "find cache_ino %lu\n",
+ if (c_aops->bmap(cache_inode->i_mapping, block[i])) {
+ CDEBUG(D_SNAP, "find cache_ino %lu\n",
cache_inode->i_ino);
if( snapops && snapops->copy_block) {
- snapops->copy_block( inode,
+ snapops->copy_block(inode,
cache_inode, block[i]);
}
-
iput(cache_inode);
break;
}
- iput(cache_inode);
+ iput(cache_inode);
}
}
}
-
rc = fops->write(filp, buf, count, ppos);
-
- EXIT;
- return rc;
+ RETURN(rc);
}
static int currentfs_readpage(struct file *file, struct page *page)
struct inode *cache_inode = NULL;
struct file open_file;
struct dentry open_dentry ;
- struct inode_operations *ciops;
+ struct address_space_operations *c_aops;
struct snap_cache *cache;
long block;
struct snap_table *table;
cache = snap_find_cache(inode->i_dev);
if ( !cache ) {
- EXIT;
- return -EINVAL;
+ RETURN(-EINVAL);
}
+
+ c_aops = filter_c2cfaops(cache->cache_filter);
- ciops = filter_c2cfiops(cache->cache_filter);
-
- block = page->offset >> inode->i_sb->s_blocksize_bits;
+ block = page->index >> inode->i_sb->s_blocksize_bits;
/* if there is a block in the cache, return the cache readpage */
- if( inode->i_blocks && ciops->bmap(inode, block) ) {
- CDEBUG(D_FILE, "block %lu in cache, ino %lu\n",
+ if( inode->i_blocks && c_aops->bmap(inode->i_mapping, block) ) {
+ CDEBUG(D_SNAP, "block %lu in cache, ino %lu\n",
block, inode->i_ino);
- result = ciops->readpage(file, page);
- EXIT;
- return result;
+ result = c_aops->readpage(file, page);
+ RETURN(result);
}
/*
if( file->f_dentry->d_fsdata ){
pri_inode = iget(inode->i_sb, (unsigned long)file->f_dentry->d_fsdata);
if( !pri_inode )
- return -EINVAL;
+ RETURN(-EINVAL);
inode = pri_inode;
search_older = 1;
}
for (slot = table->tbl_count ; slot >= 1; slot--)
{
+ struct address_space_operations *c_aops =
+ cache_inode->i_mapping->a_ops;
cache_inode = NULL;
- index = table->tbl_index[slot];
+ index = table->snap_items[slot].index;
cache_inode = snap_get_indirect(inode, NULL, index);
- if ( !cache_inode ) continue;
+ if (!cache_inode ) continue;
/* we only want slots between cache_inode to the oldest one */
- if( search_older && cache_inode->i_ino == ind_ino )
+ if(search_older && cache_inode->i_ino == ind_ino )
search_older = 0;
- if ( !search_older && cache_inode->i_op->bmap(cache_inode, block)) {
+ if (!search_older && c_aops->bmap(cache_inode->i_mapping, block))
break;
- }
iput(cache_inode);
}
if( pri_inode )
iput(pri_inode);
- if ( !cache_inode ) {
- EXIT;
- return -EINVAL;
- }
+ if ( !cache_inode )
+ RETURN(-EINVAL);
currentfs_prepare_snapfile(inode, file, cache_inode, &open_file,
&open_dentry);
down(&cache_inode->i_sem);
- if( ciops->readpage ) {
- CDEBUG(D_FILE, "block %lu NOT in cache, use redirected ino %lu\n", block, cache_inode->i_ino );
- result = ciops->readpage(&open_file, page);
+ if( c_aops->readpage ) {
+ CDEBUG(D_SNAP, "block %lu NOT in cache, use redirected ino %lu\n",
+ block, cache_inode->i_ino );
+ result = c_aops->readpage(&open_file, page);
}else {
- CDEBUG(D_FILE, "cache ino %lu, readpage is NULL\n",
- cache_inode->i_ino);
+ CDEBUG(D_SNAP, "cache ino %lu, readpage is NULL\n",
+ cache_inode->i_ino);
}
-
up(&cache_inode->i_sem);
currentfs_restore_snapfile(inode, file, cache_inode, &open_file);
iput(cache_inode);
- EXIT;
- return result;
+ RETURN(result);
}
-
+struct address_space_operations currentfs_file_aops = {
+ readpage: currentfs_readpage,
+};
+
struct file_operations currentfs_file_fops = {
- write:currentfs_write,
+ write: currentfs_write,
};
-
+
struct inode_operations currentfs_file_iops = {
- default_file_ops: ¤tfs_file_fops,
- readpage: currentfs_readpage,
+ revalidate: NULL,
};
+
/*
- *
- *
- * Copyright (C) 2000 Stelias Computing, Inc.
- * Copyright (C) 2000 Red Hat, Inc.
- * Copyright (C) 2000 Mountain View Data, Inc.
- *
- *
+ * filter.c
*/
+#define DEBUG_SUBSYSTEM S_SNAP
-#include <stdarg.h>
-
-#include <asm/bitops.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/ext2_fs.h>
-#include <linux/malloc.h>
-#include <linux/vmalloc.h>
-#include <linux/sched.h>
-#include <linux/stat.h>
-#include <linux/string.h>
-#include <linux/locks.h>
-#include <linux/blkdev.h>
-#include <linux/init.h>
-#define __NO_VERSION__
#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/stat.h>
+#include <linux/unistd.h>
+#include <linux/jbd.h>
+#include <linux/ext3_fs.h>
+#include <linux/snap.h>
+
+#include "snapfs_internal.h"
-#include <linux/filter.h>
-int filter_print_entry = 1;
-int filter_debug = 0xfffffff;
/*
* The function in this file are responsible for setting up the
* correct methods layered file systems like InterMezzo and SnapFS
return &cache->o_fops.filter_file_fops;
}
+inline struct address_space_operations *filter_c2ufaops(struct filter_fs *cache)
+{
+ return &cache->o_fops.filter_file_aops;
+}
+
inline struct file_operations *filter_c2usfops(struct filter_fs *cache)
{
return &cache->o_fops.filter_sym_fops;
return cache->o_caops.cache_file_iops;
}
+inline struct address_space_operations *filter_c2cfaops(struct filter_fs *cache)
+{
+ return cache->o_caops.cache_file_aops;
+}
+
inline struct inode_operations *filter_c2csiops(struct filter_fs *cache)
{
return cache->o_caops.cache_sym_iops;
struct filter_fs *filter_get_filter_fs(const char *cache_type)
{
struct filter_fs *ops = NULL;
- FENTRY;
+ ENTRY;
if ( strlen(cache_type) == strlen("ext2") &&
memcmp(cache_type, "ext2", strlen("ext2")) == 0 ) {
ops = &filter_oppar[FILTER_FS_EXT2];
- FDEBUG(D_SUPER, "ops at %p\n", ops);
+ CDEBUG(D_SUPER, "ops at %p\n", ops);
}
if ( strlen(cache_type) == strlen("ext3") &&
memcmp(cache_type, "ext3", strlen("ext3")) == 0 ) {
ops = &filter_oppar[FILTER_FS_EXT3];
- FDEBUG(D_SUPER, "ops at %p\n", ops);
+ CDEBUG(D_SUPER, "ops at %p\n", ops);
}
if ( strlen(cache_type) == strlen("reiser") &&
memcmp(cache_type, "reiser", strlen("reiser")) == 0 ) {
ops = &filter_oppar[FILTER_FS_REISER];
- FDEBUG(D_SUPER, "ops at %p\n", ops);
+ CDEBUG(D_SUPER, "ops at %p\n", ops);
}
if (ops == NULL) {
- printk("prepare to die: unrecognized cache type for Filter\n");
+ CERROR("prepare to die: unrecognized cache type for Filter\n");
}
- FEXIT;
+ EXIT;
return ops;
}
-
/*
* Frobnicate the InterMezzo/SnapFS operations
* this establishes the link between the InterMezzo/SnapFS file system
* and the underlying file system used for the cache.
*/
-void filter_setup_super_ops(struct filter_fs *cache, struct super_operations *cache_sops, struct super_operations *filter_sops)
+void filter_setup_super_ops(struct filter_fs *cache,
+ struct super_operations *cache_sops,
+ struct super_operations *filter_sops)
{
/* Get ptr to the shared struct snapfs_ops structure. */
struct filter_ops *uops = &cache->o_fops;
/* Get ptr to the shared struct cache_ops structure. */
struct cache_ops *caops = &cache->o_caops;
- FENTRY;
+ ENTRY;
if ( cache->o_flags & FILTER_DID_SUPER_OPS ) {
- FEXIT;
+ EXIT;
return;
}
cache->o_flags |= FILTER_DID_SUPER_OPS;
/* Set the cache superblock operations to point to the
superblock operations of the underlying file system. */
caops->cache_sops = cache_sops;
-
/*
* Copy the cache (real fs) superblock ops to the "filter"
* superblock ops as defaults. Some will be changed below
}
if (cache_sops->read_inode && uops->filter_sops.read_inode) {
uops->filter_sops.read_inode = filter_sops->read_inode;
- FDEBUG(D_INODE, "setting filter_read_inode, cache_ops %p, cache %p, ri at %p\n",
+ CDEBUG(D_INODE, "setting filter_read_inode, cache_ops %p, cache %p, ri at %p\n",
cache, cache, uops->filter_sops.read_inode);
}
- if (cache_sops->notify_change && uops->filter_sops.notify_change)
- uops->filter_sops.notify_change = filter_sops->notify_change;
- if (cache_sops->remount_fs && uops->filter_sops.remount_fs)
- uops->filter_sops.remount_fs = filter_sops->remount_fs;
- FEXIT;
+ uops->filter_sops.clear_inode = filter_sops->clear_inode;
+
+ EXIT;
}
-
-void filter_setup_dir_ops(struct filter_fs *cache, struct inode_operations *cache_iops, struct inode_operations *filter_iops)
+void filter_setup_dir_ops(struct filter_fs *cache,
+ struct inode *inode,
+ struct inode_operations *filter_iops,
+ struct file_operations *filter_fops)
{
struct inode_operations *u_iops;
- struct file_operations *u_fops, *c_fops, *f_fops;
- FENTRY;
+ struct file_operations *u_fops;
+
+ ENTRY;
- if ( cache->o_flags & FILTER_DID_DIR_OPS ) {
- FEXIT;
+ if (cache->o_flags & FILTER_DID_DIR_OPS) {
+ EXIT;
return;
}
- FDEBUG(D_SUPER, "\n");
cache->o_flags |= FILTER_DID_DIR_OPS;
/* steal the old ops */
- cache->o_caops.cache_dir_iops = cache_iops;
- cache->o_caops.cache_dir_fops =
- cache_iops->default_file_ops;
-
- FDEBUG(D_SUPER, "\n");
- /* abbreviate */
- u_iops = &cache->o_fops.filter_dir_iops;
-
- /* setup our dir iops: copy and modify */
- memcpy(u_iops, cache_iops, sizeof(*cache_iops));
- FDEBUG(D_SUPER, "\n");
+ cache->o_caops.cache_dir_iops = inode->i_op;
+ cache->o_caops.cache_dir_fops = inode->i_fop;
+
+ u_iops = filter_c2udiops(cache);
+ u_fops = filter_c2udfops(cache);
+
+ /* setup our dir iops and fops: copy and modify */
+ memcpy(u_iops, inode->i_op, sizeof(struct inode_operations));
+ memcpy(u_fops, inode->i_fop, sizeof(struct file_operations));
/* methods that filter if cache filesystem has these ops */
- if ( cache_iops->lookup && filter_iops->lookup ) {
- FDEBUG(D_SUPER, "\n");
- u_iops->lookup = filter_iops->lookup;
- FDEBUG(D_SUPER, "lookup at %p\n", &filter_iops->lookup);
+ if (filter_iops) {
+ struct inode_operations *cache_iops = inode->i_op;
+
+ if (cache_iops->lookup && filter_iops->lookup)
+ u_iops->lookup = filter_iops->lookup;
+ if (cache_iops->create && filter_iops->create)
+ u_iops->create = filter_iops->create;
+ if (cache_iops->link && filter_iops->link)
+ u_iops->link = filter_iops->link;
+ if (cache_iops->unlink && filter_iops->unlink)
+ u_iops->unlink = filter_iops->unlink;
+ if (cache_iops->mkdir && filter_iops->mkdir)
+ u_iops->mkdir = filter_iops->mkdir;
+ if (cache_iops->rmdir && filter_iops->rmdir)
+ u_iops->rmdir = filter_iops->rmdir;
+ if (cache_iops->symlink && filter_iops->symlink)
+ u_iops->symlink = filter_iops->symlink;
+ if (cache_iops->rename && filter_iops->rename)
+ u_iops->rename = filter_iops->rename;
+ if (cache_iops->mknod && filter_iops->mknod)
+ u_iops->mknod = filter_iops->mknod;
+ if (cache_iops->permission && filter_iops->permission)
+ u_iops->permission = filter_iops->permission;
}
- if (cache_iops->create && filter_iops->create)
- u_iops->create = filter_iops->create;
- FDEBUG(D_SUPER, "\n");
- if (cache_iops->link && filter_iops->link)
- u_iops->link = filter_iops->link;
- FDEBUG(D_SUPER, "\n");
- if (cache_iops->unlink && filter_iops->unlink)
- u_iops->unlink = filter_iops->unlink;
- FDEBUG(D_SUPER, "\n");
- if (cache_iops->mkdir && filter_iops->mkdir)
- u_iops->mkdir = filter_iops->mkdir;
- FDEBUG(D_SUPER, "\n");
- if (cache_iops->rmdir && filter_iops->rmdir)
- u_iops->rmdir = filter_iops->rmdir;
- FDEBUG(D_SUPER, "\n");
- if (cache_iops->symlink && filter_iops->symlink)
- u_iops->symlink = filter_iops->symlink;
- FDEBUG(D_SUPER, "\n");
- if (cache_iops->rename && filter_iops->rename)
- u_iops->rename = filter_iops->rename;
- FDEBUG(D_SUPER, "\n");
- if (cache_iops->mknod && filter_iops->mknod)
- u_iops->mknod = filter_iops->mknod;
- FDEBUG(D_SUPER, "\n");
- if (cache_iops->permission && filter_iops->permission)
- u_iops->permission = filter_iops->permission;
-
/* copy dir fops */
- FDEBUG(D_SUPER, "\n");
- u_fops = &cache->o_fops.filter_dir_fops;
- c_fops = cache_iops->default_file_ops;
- f_fops = filter_iops->default_file_ops;
-
- memcpy(u_fops, c_fops, sizeof(*c_fops));
-
- if( c_fops->readdir && f_fops->readdir )
- u_fops->readdir = f_fops->readdir;
-
- /* assign */
- FDEBUG(D_SUPER, "\n");
- filter_c2udiops(cache)->default_file_ops = filter_c2udfops(cache);
- FDEBUG(D_SUPER, "\n");
-
- /* unconditional filtering operations */
- if ( filter_iops->default_file_ops &&
- filter_iops->default_file_ops->open )
- filter_c2udfops(cache)->open =
- filter_iops->default_file_ops->open;
-
- FEXIT;
+
+ if (filter_fops) {
+ struct file_operations *cache_fops = inode->i_fop;
+
+ if(cache_fops->readdir && filter_fops->readdir)
+ u_fops->readdir = filter_fops->readdir;
+ }
+ EXIT;
}
-
-void filter_setup_file_ops(struct filter_fs *cache, struct inode_operations *cache_iops, struct inode_operations *filter_iops)
+void filter_setup_file_ops(struct filter_fs *cache,
+ struct inode *inode,
+ struct inode_operations *filter_iops,
+ struct file_operations *filter_fops,
+ struct address_space_operations *filter_aops)
{
struct inode_operations *u_iops;
- FENTRY;
+ struct file_operations *u_fops;
+ struct address_space_operations *u_aops;
+ ENTRY;
- if ( cache->o_flags & FILTER_DID_FILE_OPS ) {
- FEXIT;
+ if (cache->o_flags & FILTER_DID_FILE_OPS || !inode ) {
+ EXIT;
return;
}
+
cache->o_flags |= FILTER_DID_FILE_OPS;
/* steal the old ops */
- cache->o_caops.cache_file_iops = cache_iops;
- cache->o_caops.cache_file_fops =
- cache_iops->default_file_ops;
+ cache->o_caops.cache_file_iops = inode->i_op;
+ cache->o_caops.cache_file_fops = inode->i_fop;
/* abbreviate */
u_iops = filter_c2ufiops(cache);
-
+ u_fops = filter_c2uffops(cache);
+ u_aops = filter_c2ufaops(cache);
+
/* setup our dir iops: copy and modify */
- memcpy(u_iops, cache_iops, sizeof(*cache_iops));
+ memcpy(u_iops, inode->i_op, sizeof(struct inode_operations));
+ memcpy(u_fops, inode->i_fop, sizeof(struct file_operations));
- /* copy dir fops */
- memcpy(filter_c2uffops(cache), cache_iops->default_file_ops,
- sizeof(*cache_iops->default_file_ops));
- /* assign */
- filter_c2ufiops(cache)->default_file_ops = filter_c2uffops(cache);
-
- /* unconditional filtering operations */
- if (filter_iops->default_file_ops &&
- filter_iops->default_file_ops->open )
- filter_c2uffops(cache)->open =
- filter_iops->default_file_ops->open;
- if (filter_iops->default_file_ops &&
- filter_iops->default_file_ops->release )
- filter_c2uffops(cache)->release =
- filter_iops->default_file_ops->release;
- if (filter_iops->default_file_ops &&
- filter_iops->default_file_ops->write )
- filter_c2uffops(cache)->write =
- filter_iops->default_file_ops->write;
-
- /* set up readpage */
- if (filter_iops->readpage)
- filter_c2ufiops(cache)->readpage = filter_iops->readpage;
-
- FEXIT;
+ if (inode->i_mapping && inode->i_mapping->a_ops) {
+ cache->o_caops.cache_file_aops = inode->i_mapping->a_ops;
+ memcpy(u_aops, inode->i_mapping->a_ops,
+ sizeof(struct address_space_operations));
+ }
+ if (filter_iops) {
+ if (filter_iops->revalidate)
+ u_iops->revalidate = filter_iops->revalidate;
+ }
+ if (filter_fops) {
+ if (filter_fops->read)
+ u_fops->read = filter_fops->read;
+ }
+ if (filter_aops) {
+ if (filter_aops->readpage)
+ u_aops->readpage = filter_aops->readpage;
+ }
+ EXIT;
}
-/* XXX in 2.3 there are "fast" and "slow" symlink ops for ext2 XXX */
-void filter_setup_symlink_ops(struct filter_fs *cache, struct inode_operations *cache_iops, struct inode_operations *filter_iops)
+void filter_setup_symlink_ops(struct filter_fs *cache,
+ struct inode *inode,
+ struct inode_operations *filter_iops,
+ struct file_operations *filter_fops)
{
struct inode_operations *u_iops;
- FENTRY;
+ struct file_operations *u_fops;
+
+ ENTRY;
- if ( cache->o_flags & FILTER_DID_SYMLINK_OPS ) {
- FEXIT;
+ if (cache->o_flags & FILTER_DID_SYMLINK_OPS || !inode ) {
+ EXIT;
return;
}
cache->o_flags |= FILTER_DID_SYMLINK_OPS;
/* steal the old ops */
- cache->o_caops.cache_sym_iops = cache_iops;
- cache->o_caops.cache_sym_fops =
- cache_iops->default_file_ops;
+ cache->o_caops.cache_sym_iops = inode->i_op;
+ cache->o_caops.cache_sym_fops = inode->i_fop;
/* abbreviate */
u_iops = filter_c2usiops(cache);
+ u_fops = filter_c2usfops(cache);
/* setup our dir iops: copy and modify */
- memcpy(u_iops, cache_iops, sizeof(*cache_iops));
-
- /* copy fops - careful for symlinks they might be NULL */
- if ( cache_iops->default_file_ops ) {
- memcpy(filter_c2usfops(cache), cache_iops->default_file_ops,
- sizeof(*cache_iops->default_file_ops));
+ memcpy(u_iops, inode->i_op, sizeof(struct inode_operations));
+ memcpy(u_fops, inode->i_fop, sizeof(struct file_operations));
+ if (filter_iops) {
+ struct inode_operations *cache_iops = inode->i_op;
+ if (cache_iops->readlink && filter_iops->readlink)
+ u_iops->readlink = filter_iops->readlink;
+ if (cache_iops->follow_link && filter_iops->follow_link)
+ u_iops->follow_link = filter_iops->follow_link;
}
-
- /* assign */
- filter_c2usiops(cache)->default_file_ops = filter_c2usfops(cache);
-
- if (cache_iops->readlink && filter_iops->readlink)
- u_iops->readlink = filter_iops->readlink;
- if (cache_iops->follow_link && filter_iops->follow_link)
- u_iops->follow_link = filter_iops->follow_link;
-
- FEXIT;
+ EXIT;
}
void filter_setup_dentry_ops(struct filter_fs *cache,
struct dentry_operations *filter_dop)
{
if ( cache->o_flags & FILTER_DID_DENTRY_OPS ) {
- FEXIT;
+ EXIT;
return;
}
cache->o_flags |= FILTER_DID_DENTRY_OPS;
filter_dop, sizeof(*filter_dop));
if (cache_dop && cache_dop != filter_dop && cache_dop->d_revalidate){
- printk("WARNING: filter overriding revalidation!\n");
+ CWARN("filter overriding revalidation!\n");
}
+ EXIT;
return;
}
/* snapfs : for snapshot operations */
void filter_setup_snapshot_ops (struct filter_fs *cache,
struct snapshot_operations *cache_snapops)
{
- FENTRY;
+ ENTRY;
if ( cache->o_flags & FILTER_DID_SNAPSHOT_OPS ) {
- FEXIT;
+ EXIT;
return;
}
cache->o_flags |= FILTER_DID_SNAPSHOT_OPS;
cache->o_snapops = cache_snapops;
- FEXIT;
+ EXIT;
}
void filter_setup_journal_ops (struct filter_fs *cache,
struct journal_ops *cache_journal_ops)
{
- FENTRY;
+ ENTRY;
if( cache->o_flags & FILTER_DID_JOURNAL_OPS ){
- FEXIT;
+ EXIT;
return;
}
cache->o_flags |= FILTER_DID_JOURNAL_OPS;
cache->o_trops = cache_journal_ops;
- FEXIT;
+ EXIT;
}
*
*/
-#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 *);
+static kmem_cache_t *filter_info_cache = NULL;
+
+void cleanup_filter_info_cache()
+{
+ kmem_cache_destroy(filter_info_cache);
+}
+
+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;
+}
+
+
+void init_filter_data(struct inode *inode,
+ struct snapshot_operations *snapops,
+ int flag)
+{
+ struct filter_inode_info *i;
+
+ 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;
+}
/* Superblock operations. */
static void currentfs_read_inode(struct inode *inode)
{
struct snap_cache *cache;
+ struct snapshot_operations *snapops;
ENTRY;
if( !inode )
- {
- EXIT;
return;
- }
CDEBUG(D_INODE, "read_inode ino %lu\n", inode->i_ino);
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 ;
+ return;
}
- if ( inode->i_ino & 0xF0000000 ) {
- CDEBUG(D_INODE, "\n");
+ if (inode->i_ino & 0xF0000000) {
currentfs_dotsnap_read_inode(cache, inode);
- EXIT;
- return ;
+ return;
}
+ snapops = filter_c2csnapops(cache->cache_filter);
+
+ if (!snapops || !snapops->get_indirect)
+ return;
- if( filter_c2csops(cache->cache_filter) )
+ if(filter_c2csops(cache->cache_filter))
filter_c2csops(cache->cache_filter)->read_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) ) {
+ 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);
}
- inode->i_op = filter_c2ufiops(cache->cache_filter);
- printk("inode %lu, i_op at %p\n", inode->i_ino, inode->i_op);
+ CDEBUG(D_INODE, "inode %lu, i_op at %p\n",
+ inode->i_ino, inode->i_op);
}
- 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);
+ CDEBUG(D_INODE, "inode %lu, i_op at %p\n",
+ inode->i_ino, inode->i_op);
}
-
- EXIT;
+ /*init filter_data struct
+ * FIXME flag should be set future*/
+ init_filter_data(inode, snapops, 0);
return;
}
-
-static int currentfs_notify_change(struct dentry *dentry, struct iattr *iattr)
-{
- struct snap_cache *cache;
- int rc;
- struct super_operations *sops;
-
- ENTRY;
-
- if (currentfs_is_under_dotsnap(dentry)) {
- EXIT;
- return -EPERM;
- }
-
- cache = snap_find_cache(dentry->d_inode->i_dev);
- if ( !cache ) {
- EXIT;
- return -EINVAL;
- }
-
- /* XXX better alloc a new dentry */
-
- 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);
- }
-
- sops = filter_c2csops(cache->cache_filter);
- if (!sops ||
- !sops->notify_change) {
- EXIT;
- return -EINVAL;
- }
- rc = sops->notify_change(dentry, iattr);
-
- EXIT;
- return rc;
-}
-
-
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,
};
* Snapfs. (C) 2000 Peter J. Braam
*/
-#include <linux/types.h>
+#define DEBUG_SUBSYSTEM S_SNAP
+
+#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/fs.h>
-#include <linux/malloc.h>
-#include <linux/vmalloc.h>
-#include <linux/stat.h>
-#include <linux/errno.h>
-#include <linux/locks.h>
-#include <asm/segment.h>
-#include <asm/uaccess.h>
#include <linux/string.h>
-#ifdef CONFIG_SNAPFS_EXT3
-#include <linux/ext3_jfs.h>
-#endif
-#include "linux/filter.h"
-#include "linux/snapfs.h"
-#include "linux/snapsupport.h"
+#include <linux/slab.h>
+#include <linux/stat.h>
+#include <linux/unistd.h>
+#include <linux/jbd.h>
+#include <linux/ext3_jbd.h>
+#include <linux/ext3_fs.h>
+#include <linux/snap.h>
+
+#include "snapfs_internal.h"
-#ifdef CONFIG_SNAPFS_EXT3
#define EXT3_EA_TRANS_BLOCKS EXT3_DATA_TRANS_BLOCKS
jblocks = 4 * COW_CREDITS + 2 * EXT3_DATA_TRANS_BLOCKS + 2;
break;
default:
- CDEBUG(D_JOURNAL, "invalid operation %d for journal\n", op);
+ CDEBUG(D_INODE, "invalid operation %d for journal\n", op);
return NULL;
}
- CDEBUG(D_JOURNAL, "creating journal handle (%d blocks)\n", jblocks);
- return journal_start(EXT3_JOURNAL(inode), jblocks);
+ CDEBUG(D_INODE, "creating journal handle (%d blocks)\n", jblocks);
+ return ext3_journal_start(inode, jblocks);
}
static void snap_e3_trans_commit(void *handle)
{
- journal_stop(current->j_handle);
+ journal_stop(handle);
}
struct journal_ops snap_ext3_journal_ops = {
snap_e3_trans_commit
};
-#endif /* CONFIG_EXT3_FS */
#define EXPORT_SYMTAB
-#include <linux/config.h> /* for CONFIG_PROC_FS */
+
+#define DEBUG_SUBSYSTEM S_SNAP
+
#include <linux/module.h>
-#include <linux/errno.h>
#include <linux/kernel.h>
-#include <linux/major.h>
-/* #include <linux/kmod.h> for request_module() */
-#include <linux/sched.h>
-#include <linux/lp.h>
-#include <linux/malloc.h>
-#include <linux/ioport.h>
-#include <linux/fcntl.h>
-#include <linux/delay.h>
-#include <linux/skbuff.h>
-#include <linux/proc_fs.h>
-#include <linux/vmalloc.h>
-#include <linux/fs.h>
-#include <linux/poll.h>
-#include <linux/init.h>
-#include <linux/list.h>
-#include <asm/io.h>
-#include <asm/segment.h>
-#include <asm/system.h>
-#include <asm/poll.h>
-#include <asm/uaccess.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/stat.h>
+#include <linux/unistd.h>
#include <linux/miscdevice.h>
+#include <linux/jbd.h>
+#include <linux/ext3_fs.h>
+#include <linux/snap.h>
+
+#include "snapfs_internal.h"
-#include <linux/filter.h>
-#include <linux/snapfs.h>
-#include <linux/snapsupport.h>
-#if 1 /* XXX - enable for debug messages */
int snap_print_entry = 1;
-int snap_debug_level = ~D_INFO;
-#else
-int snap_print_entry = 0;
int snap_debug_level = 0;
-#endif
int snap_inodes = 0;
-long snap_memory = 0;
-
+long snap_kmemory = 0;
+int snap_stack = 0;
struct snap_control_device snap_dev;
extern int snap_ioctl (struct inode * inode, struct file * filp,
ENTRY;
if (!inode)
- return -EINVAL;
+ RETURN(-EINVAL);
dev = MINOR(inode->i_rdev);
if (dev != SNAP_PSDEV_MINOR)
- return -ENODEV;
+ RETURN(-ENODEV);
- MOD_INC_USE_COUNT;
- EXIT;
- return 0;
+ RETURN(0);
}
/* called when closing /dev/device */
ENTRY;
if (!inode)
- return -EINVAL;
+ RETURN(-EINVAL);
dev = MINOR(inode->i_rdev);
if (dev != SNAP_PSDEV_MINOR)
- return -ENODEV;
-
- MOD_DEC_USE_COUNT;
+ RETURN(-ENODEV);
- EXIT;
- return 0;
+ RETURN(0);
}
/* XXX need ioctls here to do snap_delete and snap_restore, snap_backup */
/* declare character device */
static struct file_operations snapcontrol_fops = {
- NULL, /* llseek */
- NULL, /* read */
- NULL, /* write */
- NULL, /* presto_psdev_readdir */
- NULL, /* poll */
- snap_ioctl, /* ioctl */
- NULL, /* presto_psdev_mmap */
- snap_psdev_open, /* open */
- NULL,
- snap_psdev_release, /* release */
- NULL, /* fsync */
- NULL, /* fasync */
- NULL /* lock */
+ ioctl: snap_ioctl, /* ioctl */
+ open: snap_psdev_open, /* open */
+ release: snap_psdev_release, /* release */
};
#define SNAPFS_MINOR 240
static struct miscdevice snapcontrol_dev = {
- SNAPFS_MINOR,
- "snapcontrol",
- &snapcontrol_fops
+ minor: SNAPFS_MINOR,
+ name: "snapcontrol",
+ fops: &snapcontrol_fops
};
int init_snap_psdev(void)
{
- printk(KERN_INFO "SNAP psdev driver v0.01, braam@mountainviewdata.com\n");
+ printk(KERN_INFO "SNAP psdev driver v0.01, braam@clusterfs.com\n");
misc_register( &snapcontrol_dev );
EXIT;
}
-#ifdef MODULE
MODULE_AUTHOR("Peter J. Braam <braam@cs.cmu.edu>");
MODULE_DESCRIPTION("Snapfs file system filters v0.01");
extern int init_clonefs(void);
extern int init_snap_sysctl(void);
-int init_module(void)
+static int __init snapfs_init(void)
{
int err;
if ( (err = init_snap_psdev()) ) {
printk("Error initializing snapfs proc sys, %d\n", err);
return -EINVAL;
}
-
-
+
return 0;
}
-void cleanup_module(void)
+static void __exit snapfs_cleanup(void)
{
cleanup_snapfs();
snap_cleanup_psdev();
}
-#endif
+module_init(snapfs_init);
+module_exit(snapfs_cleanup);
+
*
*/
-#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/kmod.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/slab.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>
-
-#include <linux/filter.h>
-#include <linux/snapfs.h>
-#include <linux/snapsupport.h>
+#include <linux/snap.h>
+#include "snapfs_internal.h"
/*
* Return true if the inode is a redirector inode.
cache = snap_find_cache(cache_inode->i_dev);
if (!cache) {
- EXIT;
return 0;
}
snapops = filter_c2csnapops(cache->cache_filter);
if (!snapops || !snapops->is_redirector) {
- EXIT;
return 0;
}
cache = snap_find_cache(cache_inode->i_dev);
if (!cache) {
- EXIT;
- return NULL;
+ RETURN(NULL);
}
snapops = filter_c2csnapops(cache->cache_filter);
if (!snapops || !snapops->get_indirect) {
- EXIT;
- return NULL;
+ RETURN(NULL);
}
CDEBUG(D_SNAP, "cache ino %ld\n", cache_inode->i_ino);
clone_info->clone_index);
/* if not found, get the FIRST index after this and before NOW */
/* XXX fix this later, now use tbl_count, not NOW */
- if(!redirected) {
+ if (!redirected) {
+ int index;
clone_slot = snap_index2slot(table, clone_info->clone_index);
- for(slot = table->tbl_count; slot >= clone_slot; slot --)
- {
- my_table[slot-clone_slot+1] = table->tbl_index[slot];
+ for (slot = table->tbl_count; slot >= clone_slot; slot --) {
+ my_table[slot-clone_slot+1] = table->snap_items[slot].index;
}
- redirected = snapops->get_indirect
- (cache_inode, my_table, table->tbl_count - clone_slot + 1);
+ index = table->tbl_count - clone_slot + 1;
+ redirected = snapops->get_indirect(cache_inode, my_table, index);
}
- /* old version
- redirected = snapops->get_indirect
- (cache_inode, table->tbl_index,
- snap_index2slot(table, clone_info->clone_index));
- */
- if(redirected) CDEBUG(D_SNAP,"redirected ino %ld\n",redirected->i_ino);
- EXIT;
+
+ if (redirected)
+ CDEBUG(D_SNAP,"redirected ino %ld\n",redirected->i_ino);
+
return redirected;
}
cache = snap_find_cache(inode->i_dev);
if (!cache) {
- EXIT;
- return -EINVAL;
+ RETURN(-EINVAL);
}
snapops = filter_c2csnapops(cache->cache_filter);
if (!snapops || !snapops->create_indirect) {
- EXIT;
- return -EINVAL;
+ RETURN(-EINVAL);
}
+
snap_last(cache, &snap);
- ind = snapops->create_indirect(inode, parent_ino, snap.index, del);
- EXIT;
- if(ind) {
- iput(ind);
- return 0;
- }
- else
- return -EINVAL;
+ ind = snapops->create_indirect(inode, snap.index, 0, parent_ino, del);
+ if(!ind)
+ RETURN(-EINVAL);
+ iput(ind);
+ RETURN(0);
}
int snap_iterate(struct super_block *sb,
cache = snap_find_cache(inode->i_dev);
if (!cache) {
- EXIT;
- return 0;
+ RETURN(0);
}
snapops = filter_c2csnapops(cache->cache_filter);
if (!snapops || !snapops->iterate) {
- EXIT;
- return 0;
+ RETURN(0);
}
- EXIT;
return snapops->iterate(sb, repeat, start, priv, flag);
}
ENTRY;
cache = snap_find_cache(pri->i_dev);
- if (!cache) {
- EXIT;
- return 0;
- }
+ if (!cache)
+ RETURN(0);
snapops = filter_c2csnapops(cache->cache_filter);
- if (!snapops || !snapops->destroy_indirect) {
- EXIT;
- return 0;
- }
+ if (!snapops || !snapops->destroy_indirect)
+ RETURN(0);
- EXIT;
return snapops->destroy_indirect(pri, index, next_ind);
}
ENTRY;
cache = snap_find_cache(pri->i_dev);
- if (!cache) {
- EXIT;
- return 0;
- }
+ if (!cache)
+ RETURN(0);
+
snapops = filter_c2csnapops(cache->cache_filter);
- if (!snapops || !snapops->restore_indirect) {
- EXIT;
- return 0;
- }
+ if (!snapops || !snapops->restore_indirect)
+ RETURN(0);
- EXIT;
return snapops->restore_indirect(pri, index);
}
ENTRY;
cache = snap_find_cache(pri->i_dev);
- if (!cache) {
- EXIT;
- return NULL;
- }
+ if (!cache)
+ RETURN(NULL);
+
snapops = filter_c2csnapops(cache->cache_filter);
- if (!snapops || !snapops->get_indirect) {
- EXIT;
- return NULL;
- }
+ if (!snapops || !snapops->get_indirect)
+ RETURN(NULL);
- EXIT;
return snapops->get_indirect(pri, table, slot);
}
-int snap_migrate_data(struct inode *dst, struct inode *src)
-{
- struct snap_cache *cache;
- struct snapshot_operations *snapops;
-
- ENTRY;
-
- cache = snap_find_cache(src->i_dev);
- if (!cache) {
- EXIT;
- return 0;
- }
- snapops = filter_c2csnapops(cache->cache_filter);
- if (!snapops || !snapops->migrate_data) {
- EXIT;
- return 0;
- }
-
- EXIT;
- return snapops->migrate_data(dst, src);
-}
-
int snap_set_indirect(struct inode *pri, ino_t ind_ino, int index, ino_t parent_ino)
{
struct snap_cache *cache;
ENTRY;
cache = snap_find_cache(pri->i_dev);
- if (!cache) {
- EXIT;
- return -EINVAL;
- }
- snapops = filter_c2csnapops(cache->cache_filter);
- if (!snapops || !snapops->set_indirect) {
- EXIT;
- return -EINVAL;
- }
+ if (!cache)
+ RETURN(-EINVAL);
+
+ snapops = filter_c2csnapops(cache->cache_filter);
+ if (!snapops || !snapops->set_indirect)
+ RETURN(-EINVAL);
EXIT;
return snapops->set_indirect(pri, ind_ino, index, parent_ino);
*
*/
-#include <linux/sched.h>
-#include <linux/fs.h>
-#include <linux/malloc.h>
-#include <linux/locks.h>
-#include <linux/errno.h>
-#include <linux/swap.h>
-#include <linux/smp_lock.h>
-#include <linux/vmalloc.h>
-#include <linux/blkdev.h>
-#include <linux/sysrq.h>
-#include <linux/file.h>
-#include <linux/init.h>
-#include <linux/quotaops.h>
+#define DEBUG_SUBSYSTEM S_SNAP
+#include <linux/module.h>
+#include <linux/kmod.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/snap.h>
#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/bitops.h>
-#include <asm/mmu_context.h>
+#include "snapfs_internal.h"
-#include <linux/filter.h>
-#include <linux/snapsupport.h>
-#include <linux/snapfs.h>
struct snap_table snap_tables[SNAP_MAX_TABLES];
int slot;
for ( slot=0 ; slot<snap_table->tbl_count ; slot++ )
- if ( snap_table->tbl_index[slot] == snap_index )
+ if ( snap_table->snap_items[slot].index == snap_index )
return slot;
return -1;
}
- the index of the latest snapshot before NOW
- hence it returns 0 in case all the volume snapshots lie in the future
- this is the index where a COW will land (will be created)
- */
+*/
+
void snap_last(struct snap_cache *info, struct snap *snap)
{
int i ;
ENTRY;
if ( tableno < 0 || tableno > SNAP_MAX_TABLES ) {
- printk(__FUNCTION__ ": invalid table no %d\n", tableno);
+ CERROR("invalid table no %d\n", tableno);
snap->index = -1;
}
+
table = &snap_tables[tableno];
/* start at the highest index in the superblock
i = table->tbl_count - 1;
/* NOTE: i>0 is an unnecessary check */
- while ( table->tbl_times[i] > now && i > 0) {
- CDEBUG(D_SNAP, "time: %ld, i: %d\n", table->tbl_times[i], i);
- i--;
- }
-
- snap->index = table->tbl_index[i];
- snap->time = table->tbl_times[i];
+ snap->index = table->snap_items[i].index;
+ snap->time = table->snap_items[i].time;
+ snap->gen = table->snap_items[i].gen;
CDEBUG(D_SNAP, "index: %d, time[i]: %ld, now: %ld\n",
snap->index, snap->time, now);
- EXIT;
return;
}
{
struct snap snap;
struct snap_cache *cache;
+ struct filter_inode_info *filter_info;
int index = -1;
ENTRY;
cache = snap_find_cache(inode->i_dev);
if ( !cache ) {
- EXIT;
- return -1;
+ RETURN(index);
}
-
+ filter_info = (struct filter_inode_info *) inode->i_filterdata;
/* here we find the time of the last snap to compare with */
- snap_last(cache, &snap);
+ snap_last(cache, &snap);
/* decision .... if the snapshot is more recent than the object,
* then any change to the object should cause a COW.
*/
- if (inode->i_mtime <= snap.time && inode->i_ctime <= snap.time) {
+ if (filter_info && filter_info->generation < snap.gen ) {
index = snap.index;
}
- printk("snap_needs_cow, ino %lu , get index %d\n",inode->i_ino, index);
- EXIT;
- return index;
-} /* snap_needs_cow */
+ CDEBUG(D_SNAP, "snap_needs_cow, ino %lu , get index %d\n",
+ inode->i_ino, index);
-#if 0
-int snap_obd2snap(struct snap_clone_info *info, struct snap *snap)
-{
- struct snap_table *table;
- int tableno = info->clone_cache->cache_snap_tableno;
- int index = info->clone_index;
- int slot;
-
- ENTRY;
- if ( tableno < 0 || tableno > SNAP_MAX_TABLES ) {
- printk(__FUNCTION__ ": invalid table no %d\n", tableno);
- snap->index = -1;
- }
- table = &snap_tables[tableno];
- slot = snap_index2slot(table, index);
-
- snap->index = index;
- snap->time = table->tbl_times[slot];
- EXIT;
- return slot;
-}
-#endif
-
-/* at what index is the current snapshot located */
-int snap_current(struct snap_cache *cache)
-{
- int tableno = cache->cache_snap_tableno;
-
- return snap_tables[tableno].tbl_index[0];
-}
-
-int snap_is_used(int table_no, int snap_index)
-
-{
- /* ENTRY; */
- if ( snap_index < 0 || snap_index >= SNAP_MAX ) {
- printk(__FUNCTION__ ": invalid snapno %d,table %d\n",
- snap_index, table_no);
- EXIT;
- return -1;
- }
- if ( table_no < 0 || table_no > SNAP_MAX_TABLES ) {
- printk(__FUNCTION__ ": invalid snapno %d,table %d\n",
- snap_index, table_no);
- EXIT;
- return -1;
- }
-
- /* EXIT; */
- return snap_tables[table_no].tbl_used & (1<<snap_index);
-}
-
-void snap_use(int table_no, int snap_index)
-{
- if ( snap_index < 0 || snap_index >= SNAP_MAX ) {
- printk(__FUNCTION__ ": invalid snapno %d,table %d\n",
- snap_index, table_no);
- return;
- }
- if ( table_no < 0 || table_no > SNAP_MAX_TABLES ) {
- printk(__FUNCTION__ ": invalid snapno %d,table %d\n",
- snap_index, table_no);
- return;
- }
- if ( snap_index2slot(&snap_tables[table_no], snap_index) < 0 )
- return;
-
- snap_tables[table_no].tbl_used |= (1<<snap_index);
-}
-
-void snap_unuse(int table_no, int snap_index)
-{
- if ( snap_index < 0 || snap_index >= SNAP_MAX ) {
- printk(__FUNCTION__ ": invalid snapno %d,table %d\n",
- snap_index, table_no);
- return;
- }
- if ( table_no < 0 || table_no > SNAP_MAX_TABLES ) {
- printk(__FUNCTION__ ": invalid snapno %d,table %d\n",
- snap_index, table_no);
- return;
- }
- if ( snap_index2slot(&snap_tables[table_no], snap_index) < 0 )
- return;
-
- snap_tables[table_no].tbl_used &= ~(1<<snap_index);
-}
+ RETURN(index);
+} /* snap_needs_cow */
static int nprint_buf(char *buf, int buflen, char *fmt, ...)
{
int nprint = 0;
if ( tableno < 0 || tableno > SNAP_MAX_TABLES ) {
- printk(__FUNCTION__ ": invalid table number %d\n", tableno);
- EXIT;
- return -EINVAL;
+ CERROR("invalid table number %d\n", tableno);
+ RETURN(-EINVAL);
}
table = &snap_tables[tableno];
printk("------- snap table %d\n", tableno);
printk(" -- snap count %d\n", table->tbl_count);
- printk(" -- snap used 0x%x\n", table->tbl_used);
for ( i = 0 ; i < SNAP_MAX ; i++ ) {
printk(" -- slot %d, idx %d, time %ld, name %s\n",
- i, table->tbl_index[i], table->tbl_times[i],
- table->tbl_name[i]);
+ i, table->snap_items[i].index, table->snap_items[i].time,
+ &table->snap_items[i].name[0]);
}
buf_ptr = buf;
nleft -= nprint;
if( nleft > 0 ) buf_ptr += nprint;
else goto exit;
- nprint = nprint_buf(buf_ptr, nleft, " -- snap used 0x%x\n", table->tbl_used);
- nleft -= nprint;
+
if( nleft > 0 ) buf_ptr += nprint;
else goto exit;
for ( i = 0 ; i < SNAP_MAX ; i++ ) {
nprint = nprint_buf( buf_ptr, nleft,
" -- slot %d, idx %d, time %ld, name %s\n",
- i, table->tbl_index[i], table->tbl_times[i],
- table->tbl_name[i]);
+ i, table->snap_items[i].index, table->snap_items[i].time,
+ &table->snap_items[i].name[0]);
nleft -= nprint;
if( nleft > 0 ) buf_ptr += nprint;
else goto exit;
return 0;
}
-
-int snap_install_table(int len, struct snap_table_data *data)
+static int inline get_index_of_item(struct snap_table *table)
{
+ int count = table->tbl_count;
int i, j;
- int tableno = data->tblcmd_no;
-// int found_current;
- struct snap_table *table;
+ for (i = 0; i < SNAP_MAX; i ++) {
+ for (j = 1; j < count; j++) {
+ if (table->snap_items[j].index == i)
+ break;
+ }
+ if (j >= count)
+ return i;
+ }
+ return -EINVAL;
+}
+/* This function will write one item(a snapshot) to snaptable
+ * and will also write to disk.
+ */
+int snaptable_add_item(struct snap_table_data *data)
+{
+ struct snap_table *table;
+ struct snap_disk_table *disk_snap_table;
+ struct snapshot_operations *snapops;
+ struct snap_cache *cache;
+ int tableno , index, i, count, rc;
+
+ if (!(cache = snap_find_cache((kdev_t)data->dev)))
+ RETURN(-ENODEV);
+
+ snapops = filter_c2csnapops(cache->cache_filter);
+ if (!snapops || !snapops->set_meta_attr)
+ RETURN(-EINVAL);
+
+ tableno = data->tblcmd_no;
if ( tableno < 0 || tableno > SNAP_MAX_TABLES ) {
- printk(__FUNCTION__ ": invalid table number %d\n", tableno);
- EXIT;
- return -EINVAL;
+ CERROR("invalid table number %d\n", tableno);
+ RETURN(-EINVAL);
}
table = &snap_tables[tableno];
+ count = table->tbl_count;
+
+ /* XXX Is down this sema necessary*/
+ down_interruptible(&table->tbl_sema);
+
+ /*add item in snap_table*/
+ table->snap_items[count+1].gen = table->generation;
+ table->snap_items[count+1].time = CURRENT_TIME;
+ /* find table index */
+ index = get_index_of_item(table);
+ if (index < 0)
+ RETURN(-EINVAL);
+
+ table->snap_items[count+1].index = index;
+ table->snap_items[count+1].flags = 0;
+ memcpy(&table->snap_items[count + 1].name[0],
+ &data->tblcmd_snaps[0].name[0], SNAP_MAX_NAMELEN);
+ /* we will write the whole snap_table to disk */
+ SNAP_ALLOC(disk_snap_table, sizeof(struct snap_disk_table));
+ if (!disk_snap_table)
+ RETURN(-ENOMEM);
+ disk_snap_table->magic = cpu_to_le32((__u32)DISK_SNAP_TABLE_MAGIC);
+ disk_snap_table->count = cpu_to_le32((__u32)table->tbl_count);
+ disk_snap_table->generation = cpu_to_le32((__u32)table->generation);
+ memset(&disk_snap_table->snap_items[0], 0,
+ SNAP_MAX * sizeof(struct snap_disk));
+ for (i = 1; i <= count; i++) {
+ struct snap *item = &table->snap_items[i];
+ disk_snap_table->snap_items[i].time = cpu_to_le64((__u64)item->time);
+ disk_snap_table->snap_items[i].gen = cpu_to_le32((__u32)item->gen);
+ disk_snap_table->snap_items[i].flags = cpu_to_le32((__u32)item->flags);
+ disk_snap_table->snap_items[i].index = cpu_to_le32((__u32)item->index);
+ memcpy(&disk_snap_table->snap_items[i].name , item->name, SNAP_MAX_NAMELEN);
+ }
+ rc = snapops->set_meta_attr(cache->cache_sb, DISK_SNAPTABLE_ATTR,
+ (char*)disk_snap_table, sizeof(struct snap_disk_table));
+
+ SNAP_FREE(disk_snap_table, sizeof(struct snap_disk_table));
+ table->tbl_count++;
+ table->generation++;
+
+ up(&table->tbl_sema);
+
+ return 0;
+}
- /* for each index that is used by the current table
- we need to make sure that the new table we are about
- to put in contains that index too
- */
- for ( i = 0; i < SNAP_MAX ; i++ ) {
- int foundit;
- int err;
-
- if ((err = snap_is_used(tableno, i)) < 0 ) {
- printk(__FUNCTION__ ": table %d not used\n", tableno);
- EXIT;
- return -EINVAL;
- } else if (err == 0) {
- continue;
- }
+static int delete_inode(struct inode *primary, void *param)
+{
+ struct snap_iterdata * data;
+ int tableno = 0;
+ int index = 0;
+ int rc = 0;
- foundit = 0;
- for (j = 0 ; j<= data->tblcmd_count ; j++) {
- if ( i == data->tblcmd_snaps[j].index ) {
- foundit = 1;
- break;
- }
- }
- if ( !foundit ) {
- printk(__FUNCTION__ ": index %d not in table %d\n",
- i, tableno);
- return -EINVAL;
- }
- }
+ struct inode *redirect;
+ ino_t old_ind = 0;
+ struct snap_table *table;
+ int slot;
+ int delete_slot;
+ int this_index;
+ struct inode *next_ind = NULL;
+ int my_table[SNAP_MAX];
- /* we must have:
- - valid indices
- - a current snapshot in the table
- - increasing snapshot times
- */
-// found_current = 0;
- CDEBUG(D_SNAP, "snaplist: tblcmd_count %d\n", data->tblcmd_count);
- for (i = 0 ; i < data->tblcmd_count ; i++) {
-
- if ( (data->tblcmd_snaps[i].index < 0) ||
- (data->tblcmd_snaps[i].index >= SNAP_MAX) ) {
- printk(__FUNCTION__ ": snap_index out of range!\n");
- return -EINVAL;
- }
+ if(!primary) return 0;
- if (i>0 && data->tblcmd_snaps[i].time <=
- data->tblcmd_snaps[i-1].time) {
- printk(__FUNCTION__ ": times not increasing\n");
- return -EINVAL;
- }
+ data = (struct snap_iterdata*) param;
-// if ( 0 == data->tblcmd_snaps[i].time ) {
-// found_current = 1;
-// break;
-// }
+ if(data) {
+ index = data->index;
+ tableno = data->tableno;
}
-// if ( !found_current ) {
-// printk(__FUNCTION__ "no current snapshot in table\n");
-// return -EINVAL;
-// }
-
- /* ready to go: over write the table */
-/*
- for (i = 0 ; i < data->tblcmd_count ; i++) {
-
- table->tbl_times[i] = data->tblcmd_snaps[i].time;
- table->tbl_index[i] = data->tblcmd_snaps[i].index;
- memcpy(table->tbl_name[i], data->tblcmd_snaps[i].name,
- SNAP_MAX_NAMELEN);
- table->tbl_name[i][SNAP_MAX_NAMELEN - 1] = '\0';
- CDEBUG(D_SNAP, "snaplist: i %d, time %ld, idx %d, name %s\n",
- i, table->tbl_times[i], table->tbl_index[i],
- table->tbl_name[i]);
- }
-*/
- /* below : new, we don't need current snapshot for data
- * current snapshot always has slot 0, index 0, name "current"
- */
- table->tbl_times[0] = 0;
- table->tbl_index[0] = 0;
- strcpy(table->tbl_name[0], "current");
+ CDEBUG(D_INODE, "delete_inode ino %lu, index %d\n", primary->i_ino, index);
- i=0;
- CDEBUG(D_SNAP, "snaplist: i %d, time %ld, idx %d, name %s\n",
- i, table->tbl_times[i], table->tbl_index[i],
- table->tbl_name[i]);
+ table = &snap_tables[tableno];
- for (i = 0 ; i < data->tblcmd_count ; i++) {
+ redirect = snap_get_indirect(primary, NULL, index);
- table->tbl_times[i+1] = data->tblcmd_snaps[i].time;
- table->tbl_index[i+1] = data->tblcmd_snaps[i].index;
- memcpy(table->tbl_name[i+1], data->tblcmd_snaps[i].name,
- SNAP_MAX_NAMELEN);
- table->tbl_name[i+1][SNAP_MAX_NAMELEN - 1] = '\0';
+ if(!redirect)
+ return 0;
- CDEBUG(D_SNAP, "snaplist: i %d, time %ld, idx %d, name %s\n",
- i+1, table->tbl_times[i+1], table->tbl_index[i+1],
- table->tbl_name[i+1]);
+ old_ind = redirect->i_ino;
+ iput(redirect);
+ slot = snap_index2slot(table, index) - 1;
+ if( slot > 0 ) {
+ this_index = table->snap_items[slot].index;
+ redirect = snap_get_indirect(primary, NULL, this_index);
+ if(redirect)
+ iput(redirect);
+ else {
+ snap_set_indirect(primary, old_ind, this_index, 0);
+ snap_set_indirect(primary, 0, index, 0);
+ return 0;
+ }
+ }
+
+ /* get the FIRST index after this and before NOW */
+ /* used for destroy_indirect and block level cow */
+ /* XXX fix this later, now use tbl_count, not NOW */
+ delete_slot = snap_index2slot(table, index);
+ for(slot = table->tbl_count; slot > delete_slot; slot --)
+ {
+ my_table[slot - delete_slot] = table->snap_items[slot].index;
+ }
+ next_ind = snap_get_indirect
+ (primary, my_table, table->tbl_count - delete_slot );
+ if( next_ind && (next_ind->i_ino == primary->i_ino) ) {
+ iput(next_ind);
+ next_ind = NULL;
}
- for ( i = data->tblcmd_count + 1 ; i < SNAP_MAX ; i++ ) {
- table->tbl_times[i] = 0;
- table->tbl_index[i] = 0;
- memset(table->tbl_name[i], 0, SNAP_MAX_NAMELEN);
+ if( next_ind && (next_ind->i_ino == old_ind) ) {
+ iput(next_ind);
+ next_ind = NULL;
}
- /* set the table count */
-// table->tbl_count = data->tblcmd_count;
- table->tbl_count = data->tblcmd_count + 1;
+ rc = snap_destroy_indirect(primary, index, next_ind);
+
+ if(next_ind) iput(next_ind);
+
+ if(rc != 0)
+ CERROR("snap_destroy_indirect(ino %lu,index %d),ret %d\n",
+ primary->i_ino, index, rc);
return 0;
}
+static int snap_delete(struct super_block *sb, struct snap_iterdata *data)
+{
+ CDEBUG(D_SNAP, "dev %d, tableno %d, index %d, time %lu\n",
+ data->dev, data->tableno, data->index, data->time );
-int snap_table_attach(int tableno, int snap_index)
+ snap_iterate(sb, &delete_inode, NULL, data, SNAP_ITERATE_COWED_INODE);
+
+ return 0;
+}
+
+/* This function will delete one item(a snapshot) in the snaptable
+ * and will also delete the item in the disk.
+ */
+int snaptable_delete_item(struct super_block *sb, struct snap_iterdata *data)
{
- struct snap_table *table;
+ struct snap_table *table;
+ struct snap_disk_table *disk_snap_table;
+ struct snapshot_operations *snapops;
+ struct snap_cache *cache;
+ int tableno = data->tableno, index, i, slot, rc, count;
+
+ if (!(cache = snap_find_cache((kdev_t)data->dev)))
+ RETURN(-ENODEV);
+
+ snapops = filter_c2csnapops(cache->cache_filter);
+ if (!snapops || !snapops->set_meta_attr)
+ RETURN(-EINVAL);
+
+ if (tableno < 0 || tableno > SNAP_MAX_TABLES) {
+ CERROR("invalid table number %d\n", tableno);
+ RETURN(-EINVAL);
+ }
+ /*first delete the snapshot
+ * FIXME if snap delete error, how to handle this error*/
+ rc = snap_delete(sb, data);
+ if (rc)
+ RETURN(-EINVAL);
+ /*delete item in snaptable */
+ table = &snap_tables[tableno];
+ index = data->index;
- if ( tableno < 0 || tableno > SNAP_MAX_TABLES ) {
- printk(__FUNCTION__ ": invalid table number %d\n", tableno);
- EXIT;
- return -EINVAL;
+ slot = snap_index2slot(table, index);
+ if (slot < 0)
+ RETURN(-EINVAL);
+
+ down_interruptible(&table->tbl_sema);
+ while(slot < table->tbl_count) {
+ struct snap *item = &table->snap_items[slot];
+ item->time = table->snap_items[slot + 1].time;
+ item->flags = table->snap_items[slot + 1].flags;
+ item->gen = table->snap_items[slot + 1].gen;
+ item->index = table->snap_items[slot + 1].index;
+ memcpy(&item->name[0], &table->snap_items[slot + 1].name[0],
+ SNAP_MAX_NAMELEN);
}
- table = &snap_tables[tableno];
+
+ table->tbl_count --;
- if ( snap_index2slot(table, snap_index) < 0 ) {
- printk(__FUNCTION__ ": snap index %d not present in table %d\n",
- snap_index, tableno);
- return -EINVAL;
+ SNAP_ALLOC(disk_snap_table, sizeof(struct snap_disk_table));
+
+ if (!disk_snap_table)
+ RETURN(-ENOMEM);
+ /* we will delete the item snap_table to disk */
+
+ disk_snap_table->magic = cpu_to_le32((__u32)DISK_SNAP_TABLE_MAGIC);
+ disk_snap_table->count = cpu_to_le32((__u32)table->tbl_count);
+ disk_snap_table->generation = cpu_to_le32((__u32)table->generation);
+ memset(&disk_snap_table->snap_items[0], 0,
+ SNAP_MAX * sizeof(struct snap_disk));
+
+ count = table->tbl_count;
+
+ for (i = 1; i <= count; i++) {
+ struct snap *item = &table->snap_items[i];
+ disk_snap_table->snap_items[i].time = cpu_to_le64((__u64)item->time);
+ disk_snap_table->snap_items[i].gen = cpu_to_le32((__u32)item->gen);
+ disk_snap_table->snap_items[i].flags = cpu_to_le32((__u32)item->flags);
+ disk_snap_table->snap_items[i].index = cpu_to_le32((__u32)item->index);
+ memcpy(&disk_snap_table->snap_items[i].name , item->name, SNAP_MAX_NAMELEN);
+ }
+ rc = snapops->set_meta_attr(cache->cache_sb, DISK_SNAPTABLE_ATTR,
+ (char*)disk_snap_table, sizeof(struct snap_disk_table));
+
+ SNAP_FREE(disk_snap_table, sizeof(struct snap_disk_table));
+
+ up(&table->tbl_sema);
+
+ RETURN(0);
+}
+
+int snapfs_read_snaptable(struct snap_cache *cache, int tableno)
+{
+ struct snap_table *table;
+ struct snap_disk_table *disk_snap_table;
+ struct snapshot_operations *snapops;
+ int i, rc;
+ int size = 0;
+
+
+ snapops = filter_c2csnapops(cache->cache_filter);
+ if (!snapops || !snapops->get_meta_attr)
+ RETURN(-EINVAL);
+
+ SNAP_ALLOC(disk_snap_table, sizeof(struct snap_disk_table));
+
+ size = sizeof(struct snap_disk_table);
+
+ rc = snapops->get_meta_attr(cache->cache_sb, DISK_SNAPTABLE_ATTR,
+ (char*)disk_snap_table, &size);
+ if (rc < 0) {
+ SNAP_FREE(disk_snap_table, sizeof(struct snap_disk_table));
+ RETURN(rc);
}
+ table = &snap_tables[tableno];
- snap_use(tableno, snap_index);
+ if (le32_to_cpu(disk_snap_table->magic) != DISK_SNAP_TABLE_MAGIC) {
+ CERROR("On disk snaptable is not right \n");
+ RETURN(rc);
+ }
+ table->generation = le32_to_cpu(disk_snap_table->generation);
+ table->tbl_count = le32_to_cpu(disk_snap_table->count);
+ for ( i = 0; i < disk_snap_table->count; i++) {
+ struct snap *item = &table->snap_items[i + 1];
+ item->time = le64_to_cpu(disk_snap_table->snap_items[i].time);
+ item->gen = le32_to_cpu(disk_snap_table->snap_items[i].gen);
+ item->flags = le32_to_cpu(disk_snap_table->snap_items[i].flags);
+ item->index = le32_to_cpu(disk_snap_table->snap_items[i].index);
+ memcpy(&item->name[0], &disk_snap_table->snap_items[i].name[0],
+ SNAP_MAX_NAMELEN);
+ }
+ SNAP_FREE(disk_snap_table, sizeof(struct snap_disk_table));
return 0;
}
return 0;
}
- SNAP_ALLOC(tmp, void *, len);
+ SNAP_ALLOC(tmp, len);
if ( !tmp )
return -ENOMEM;
- CDEBUG(D_MALLOC, "snap_alloc:len %d, add %p\n", len, tmp);
+ CDEBUG(D_SNAP, "snap_alloc:len %d, add %p\n", len, tmp);
memset(tmp, 0, len);
if ( copy_from_user(tmp, *data, len)) {
SNAP_FREE(tmp, len);
- CDEBUG(D_MALLOC, "snap_free:len %d, add %p\n", len, tmp);
+ CDEBUG(D_SNAP, "snap_free:len %d, add %p\n", len, tmp);
return -EFAULT;
}
*data = tmp;
static void freedata(void *data, int len) {
SNAP_FREE(data, len);
- CDEBUG(D_MALLOC, "snap_free:len %d, add %p\n", len, data);
+ CDEBUG(D_SNAP, "snap_free:len %d, add %p\n", len, data);
}
static int get_next_inode(struct inode *pri, void *ino)
*parent_ino = 0;
inode = iget (cache->cache_sb, *found_ino);
if (list_empty(&inode->i_dentry)) {
- printk("No dentry for ino %lu, Error(XXX)! \n", inode->i_ino);
+ CERROR("No dentry for ino %lu, Error(XXX)! \n", inode->i_ino);
iput(inode);
return 0;
}
return 0;
}
-/*
-static int snap_get_inode_info(struct snap_ino_list_data *data, int index)
-{
- kdev_t dev = data->dev;
- ino_t pri = data->ino;
- int index = data->index;
-
- struct snap_cache *cache;
-
- struct inode *pri;
- struct inode *ind;
- ino_t ind_ino = 0;
-
- ENTRY;
-
- cache = snap_find_cache(dev);
- if ( !cache ) {
- EXIT;
- return -EINVAL;
- }
- pri = iget(cache->cache->sb, pri_ino);
- ind = snap_get_indirect(pri, NULL, index);
- if(ind) {
- ind_ino = ind->i_ino;
- iput(ind);
- }
- return ind_ino;
-}
-*/
static int print_inode(struct inode *pri,void *param)
{
return 0;
}
-static int delete_inode(struct inode *primary, void *param)
-{
- struct snap_iterdata * data;
- int tableno = 0;
- int index = 0;
- int rc = 0;
-
- struct inode *redirect;
- ino_t old_ind = 0;
- struct snap_table *table;
- int slot;
- int delete_slot;
- int this_index;
- struct inode *next_ind = NULL;
- int my_table[SNAP_MAX];
-
- if(!primary) return 0;
-
- data = (struct snap_iterdata*) param;
-
- if(data) {
- index = data->index;
- tableno = data->tableno;
- }
-
- printk("delete_inode ino %lu, index %d\n", primary->i_ino, index);
-
- table = &snap_tables[tableno];
-
- redirect = snap_get_indirect(primary, NULL, index);
-
- if(!redirect)
- return 0;
-
- old_ind = redirect->i_ino;
- iput(redirect);
- slot = snap_index2slot(table, index) - 1;
- if( slot > 0 ) {
- this_index = table->tbl_index[slot];
- redirect = snap_get_indirect(primary, NULL, this_index);
- if(redirect)
- iput(redirect);
- else {
- snap_set_indirect(primary, old_ind, this_index, 0);
- snap_set_indirect(primary, 0, index, 0);
- return 0;
- }
- }
-
- /* get the FIRST index after this and before NOW */
- /* used for destroy_indirect and block level cow */
- /* XXX fix this later, now use tbl_count, not NOW */
- delete_slot = snap_index2slot(table, index);
- for(slot = table->tbl_count; slot > delete_slot; slot --)
- {
- my_table[slot - delete_slot] = table->tbl_index[slot];
- }
- next_ind = snap_get_indirect
- (primary, my_table, table->tbl_count - delete_slot );
- if( next_ind && (next_ind->i_ino == primary->i_ino) ) {
- iput(next_ind);
- next_ind = NULL;
- }
-
- if( next_ind && (next_ind->i_ino == old_ind) ) {
- iput(next_ind);
- next_ind = NULL;
- }
-
- rc = snap_destroy_indirect(primary, index, next_ind);
-
- if(next_ind) iput(next_ind);
-
- if(rc != 0)
- printk("ERROR:snap_destroy_indirect(ino %lu,index %d),ret %d\n", primary->i_ino, index, rc);
- return 0;
-}
-
-static int snap_delete(struct super_block *sb, struct snap_iterdata *data)
-//static int snap_delete(struct super_block *sb, void *data)
-{
- CDEBUG(D_SNAP, "dev %d, tableno %d, index %d, time %lu\n",
- data->dev, data->tableno, data->index, data->time );
-
- snap_iterate(sb,&delete_inode,NULL, data, SNAP_ITERATE_COWED_INODE);
- return 0;
-}
-
static int delete_new_inode(struct inode *pri, void *param)
{
struct snap_iterdata * data;
CDEBUG(D_SNAP, "snap_restore ino %lu is newer, delete \n",pri->i_ino);
for( pos = head->next; pos != head; pos = pos->next ){
-// d_invalidate( list_entry(pos, struct dentry, d_alias) );
d_drop( list_entry(pos, struct dentry, d_alias) );
}
pri->i_nlink = 0;
int slot;
int restore_slot;
struct snap_table *table;
-// int my_table[SNAP_MAX];
int restore_index;
ENTRY;
for(slot = restore_slot; slot <= table->tbl_count;
slot++) {
ind = snap_get_indirect (pri, NULL,
- table->tbl_index[slot]);
+ table->snap_items[slot].index);
if(ind) {
- restore_index = table->tbl_index[slot];
+ restore_index = table->snap_items[slot].index;
break;
}
}
-/* for(slot = table->tbl_count; slot >= restore_slot;
- slot --)
- {
- my_table[slot - restore_slot + 1] =
- table->tbl_index[slot];
- }
- ind = snap_get_indirect (pri, my_table,
- table->tbl_count - restore_slot + 1);
-
- if( ind && (ind->i_ino == pri->i_ino) ) {
- iput(ind);
- ind = NULL;
- }
-*/
}
if(ind) {
CDEBUG(D_SNAP, "restore ino %lu with index %d\n",
pri->i_ino, restore_index);
iput(ind);
-// snap_restore_indirect(pri, index);
snap_restore_indirect(pri, restore_index);
/* XXX */
//delete_inode(pri, param);
}
}
else {
- printk("ino %lu is older, don't restore\n",pri->i_ino);
+ CDEBUG(D_SNAP, "ino %lu is older, don't restore\n", pri->i_ino);
}
EXIT;
return 0;
int slot;
if ( tableno < 0 || tableno > SNAP_MAX_TABLES ) {
- printk(__FUNCTION__ ": invalid table number %d\n", tableno);
+ CDEBUG(D_SNAP, ": invalid table number %d\n", tableno);
return -EINVAL;
}
table = &snap_tables[tableno];
for ( slot = 0 ; slot < SNAP_MAX ; slot++ ) {
-/* if(memcmp (table->tbl_name[slot], name,
- strlen(table->tbl_name[slot]) ) == 0 ) {
- return table->tbl_index[slot];
- }
-*/
- if(strncmp (table->tbl_name[slot], name,
+ if(strncmp (&table->snap_items[slot].name[0], name,
SNAP_MAX_NAMELEN) == 0 ) {
- return table->tbl_index[slot];
+ return table->snap_items[slot].index;
}
}
return -EINVAL;
int snap_iterate_func(int len, struct snap_ioc_data *ioc_data, unsigned int cmd)
{
struct snap_iterdata data;
-
- kdev_t dev ;
- char name[SNAP_MAX_NAMELEN];
-
- int index ;
- int tableno;
- int name_len;
- int slot;
-
struct super_block *sb;
struct snap_cache *cache;
struct snap_table *table;
+ char name[SNAP_MAX_NAMELEN];
+ int index, tableno, name_len, slot, rc;
+
+ kdev_t dev ;
ENTRY;
dev = ioc_data->dev;
cache = snap_find_cache(dev);
- if ( !cache ) {
- EXIT;
- return -EINVAL;
- }
+ if ( !cache )
+ RETURN(-EINVAL);
sb = cache->cache_sb;
tableno = cache->cache_snap_tableno;
if(name_len < 0 )
name_len = 0;
memcpy(name, ioc_data->name, name_len);
- if ( (index = snap_get_index_from_name (tableno, name)) < 0 ) {
- EXIT;
- return -EINVAL;
- }
+
+ if ((index = snap_get_index_from_name (tableno, name)) < 0)
+ RETURN(-EINVAL);
data.dev = dev;
data.index = index;
data.tableno = tableno;
slot = snap_index2slot (table, index);
- if( slot < 0 ) {
- EXIT;
- return -EINVAL;
- }
- data.time = table->tbl_times[slot];
-
+ if( slot < 0 )
+ RETURN(-EINVAL);
+
+ data.time = table->snap_items[slot].time;
CDEBUG(D_SNAP, "dev %d, tableno %d, index %d, time %lu\n",
data.dev, data.tableno, data.index, data.time );
switch (cmd) {
case IOC_SNAP_DEBUG:
- snap_print(sb, &data);
+ rc = snap_print(sb, &data);
break;
case IOC_SNAP_DELETE:
- snap_delete(sb, &data);
+ rc = snaptable_delete_item(sb, &data);
break;
case IOC_SNAP_RESTORE:
- snap_restore(sb, &data);
+ rc = snap_restore(sb, &data);
break;
default:
- return -EINVAL;
+ CERROR("unrecognized cmd %d \n", cmd);
+ rc = -EINVAL;
+ break;
}
-
- EXIT;
-
- return 0;
+ RETURN(0);
}
int snap_ioctl (struct inode * inode, struct file * filp,
if ( _IOC_TYPE(cmd) != IOC_SNAP_TYPE ||
_IOC_NR(cmd) < IOC_SNAP_MIN_NR ||
_IOC_NR(cmd) > IOC_SNAP_MAX_NR ) {
- CDEBUG(D_IOCTL, "invalid ioctl ( type %d, nr %d, size %d )\n",
+ /*FIXME: Sometimes Gettimeof the day will come here
+ * Do not know the reason*/
+ CDEBUG(D_IOCTL, "invalid ioctl ( type %d, nr %d, size %d )\n",
_IOC_TYPE(cmd), _IOC_NR(cmd), _IOC_SIZE(cmd));
EXIT;
- return -EINVAL;
+ return 0;
}
/* get data structures */
}
switch (cmd) {
- case IOC_SNAP_SETTABLE:
- rc = snap_install_table(len, karg);
+ case IOC_SNAP_ADD:
+ rc = snaptable_add_item(karg);
break;
case IOC_SNAP_PRINTTABLE: {
struct output_data{
case IOC_SNAP_DEBUG:
rc = snap_iterate_func(len, karg, cmd);
break;
+#ifdef SNAP_DEBUG
case IOC_SNAP_DEVFAIL:
snap_debug_failcode = (unsigned int)arg;
break;
+#endif
case IOC_SNAP_SHOW_DOTSNAP: {
struct ioc_show_info{
kdev_t dev;
*
* Author: Peter J. Braam <braam@mountainviewdata.com>
*/
+#define DEBUG_SUBSYSTEM S_SNAP
-
-#include <stdarg.h>
-
-#include <asm/bitops.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-
-#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/kmod.h>
+#include <linux/init.h>
#include <linux/fs.h>
-#include <linux/dcache.h>
-
-#ifdef CONFIG_SNAPFS_EXT2
-#include <linux/ext2_fs.h>
-#endif
-#ifdef CONFIG_SNAPFS_EXT3
-#include <linux/ext3_fs.h>
-#endif
-
-#include <linux/malloc.h>
-#include <linux/vmalloc.h>
-#include <linux/sched.h>
-#include <linux/stat.h>
+#include <linux/slab.h>
#include <linux/string.h>
-#include <linux/locks.h>
-#include <linux/blkdev.h>
-#include <linux/init.h>
-#define __NO_VERSION__
-#include <linux/module.h>
+#include <linux/jbd.h>
+#include <linux/ext3_fs.h>
+#include <linux/snap.h>
+#include <linux/errno.h>
+#include "snapfs_internal.h"
-#include <linux/filter.h>
-#include <linux/snapfs.h>
-#include <linux/snapsupport.h>
#ifdef SNAP_DEBUG
-long snap_vmemory = 0;
-long snap_kmemory = 0;
unsigned int snap_debug_failcode = 0;
#endif
extern int snap_get_index_from_name (int tableno, char *name);
-#ifdef CONFIG_SNAPFS_EXT2
-extern struct snapshot_operations ext2_snap_operations;
-extern struct journal_ops snap_ext2_journal_ops;
-#endif
-#ifdef CONFIG_SNAPFS_EXT3
extern struct snapshot_operations ext3_snap_operations;
extern struct journal_ops snap_ext3_journal_ops;
-#endif
+
+static void put_filesystem(struct file_system_type *fs)
+{
+ if (fs->owner)
+ __MOD_DEC_USE_COUNT(fs->owner);
+}
+
/* returns an allocated string, copied out from data if opt is found */
static char *read_opt(const char *opt, char *data)
return NULL;
value++;
- SNAP_ALLOC(retval, char *, strlen(value) + 1);
+ SNAP_ALLOC(retval, strlen(value) + 1);
if ( !retval ) {
- printk("snapfs: Out of memory!\n");
+ CERROR("snapfs: Out of memory!\n");
return NULL;
}
/* set the defaults here */
if (cache_type && !*cache_type) {
- SNAP_ALLOC(*cache_type, char *, strlen("ext2") + 1);
- strcpy(*cache_type, "ext2");
+ SNAP_ALLOC(*cache_type, strlen("ext3") + 1);
+ strcpy(*cache_type, "ext3");
}
if (cow_type && !*cow_type) {
- SNAP_ALLOC(*cow_type, char *, strlen("block") + 1);
+ SNAP_ALLOC(*cow_type, strlen("block") + 1);
strcpy(*cow_type, "block");
}
if (snaptable && !*snaptable) {
- SNAP_ALLOC(*snaptable, char *, strlen("-1")+1);
+ SNAP_ALLOC(*snaptable, strlen("-1")+1);
strcpy(*snaptable, "-1");
}
int err = 0;
ENTRY;
- CDEBUG(D_MALLOC, "before remount: kmem %ld, vmem %ld\n",
- snap_kmemory, snap_vmemory);
CDEBUG(D_SUPER, "remount opts: %s\n", data ? (char *)data : "(none)");
if (data) {
/* reserve space for the cache's data */
- SNAP_ALLOC(cache_data, void *, PAGE_SIZE);
- if ( !cache_data ) {
- err = -ENOMEM;
- EXIT;
- goto out_err;
- }
+ SNAP_ALLOC(cache_data, PAGE_SIZE);
+ if ( !cache_data )
+ GOTO(out_err, err = -ENOMEM);
}
cache = snap_find_cache(sb->s_dev);
if (!cache) {
- printk(__FUNCTION__ ": cannot find cache on remount\n");
- err = -ENODEV;
- EXIT;
- goto out_err;
+ CERROR("cannot find cache on remount\n");
+ GOTO(out_err, err = -ENODEV);
}
/* If an option has not yet been set, we allow it to be set on
err = sops->remount_fs(sb, flags, cache_data);
}
- CDEBUG(D_MALLOC, "after remount: kmem %ld, vmem %ld\n",
- snap_kmemory, snap_vmemory);
EXIT;
out_err:
if (cache_data)
int tableno;
ENTRY;
- CDEBUG(D_MALLOC, "before parsing: kmem %ld, vmem %ld\n",
- snap_kmemory, snap_vmemory);
/* reserve space for the cache's data */
- SNAP_ALLOC(cache_data, void *, PAGE_SIZE);
+ SNAP_ALLOC(cache_data, PAGE_SIZE);
if ( !cache_data ) {
- printk("snapfs_read_super: Cannot allocate data page.\n");
- EXIT;
- goto out_err;
+ CERROR("snapfs_read_super: Cannot allocate data page.\n");
+ GOTO(out_err, 0);
}
CDEBUG(D_SUPER, "mount opts: %s\n", data ? (char *)data : "(none)");
/* set up the cache */
cache = snap_init_cache();
if ( !cache ) {
- printk("snapfs_read_super: failure allocating cache.\n");
- EXIT;
- goto out_err;
+ CERROR("snapfs_read_super: failure allocating cache.\n");
+ GOTO(out_err, 0);
}
fstype = get_fs_type(cache_type);
if ( !fstype || !fstype->read_super) {
- EXIT;
- goto out_err;
+ GOTO(out_err, 0);
}
cache->cache_filter = filter_get_filter_fs((const char *)cache_type);
- /* XXX if cache->cache_filter==NULL?although it's rare ***/
-
+
+ if (!cache->cache_filter) {
+ CERROR("Unrecognized cache type %s \n", cache_type);
+ GOTO(out_err, 0);
+ }
/*
* Read the underlying file system superblock - ext2, ext3, reiser.
*
* Note: It's assumed that sb is always returned.
*/
- CDEBUG(D_SUPER, "\n");
if (fstype->read_super(sb, cache_data, silent) != sb) {
- printk("snapfs: cache mount failure.\n");
- EXIT;
- goto out_err;
+ CERROR("snapfs: cache mount failure.\n");
+ GOTO(out_err, 0);
}
- /* XXX now look at the flags in the superblock and determine if this
- is a block cow file system or a file cow fs. Then assign the
- snap operations accordingly. This goes in the sections for ext2/ext3/xfs etc
- */
-
/* this might have been freed above */
- CDEBUG(D_SUPER, "\n");
if (cache_data) {
SNAP_FREE(cache_data, PAGE_SIZE);
cache_data = NULL;
* 'cache' is the struct snap_cache allocated for this
* snapfs mount.
*/
- CDEBUG(D_SUPER, "\n");
snap_cache_add(cache, sb->s_dev);
tableno = simple_strtoul(snapno, &endptr, 0);
cache->cache_snap_tableno = tableno;
- CDEBUG(D_SUPER, "get tableno %d\n", cache->cache_snap_tableno);
+ CDEBUG(D_SUPER, "get tableno %d\n", cache->cache_snap_tableno);
/*
* make sure we have our own super operations
*
* struct snap_ops structure set based on the underlying
* file system type.
*/
- CDEBUG(D_SUPER, "\n");
filter_setup_super_ops(cache->cache_filter, sb->s_op,
¤tfs_super_ops);
- CDEBUG(D_SUPER, "\n");
sb->s_op = filter_c2usops(cache->cache_filter);
/*
* Save pointers in the snap_cache structure to the
/* set up snapshot ops, handle COMPAT_FEATUREs */
if( 0 ){
}
-#ifdef CONFIG_SNAPFS_EXT2
- else if ( strcmp (cache_type,"ext2") == 0 ){
- cache->cache_type = FILTER_FS_EXT2;
- filter_setup_snapshot_ops(cache->cache_filter,
- &ext2_snap_operations);
- filter_setup_journal_ops(cache->cache_filter,
- &snap_ext2_journal_ops);
- if( !EXT2_HAS_COMPAT_FEATURE(sb, EXT2_FEATURE_COMPAT_SNAPFS) ){
- if( strcmp(cow_type, "block")==0 ){
- sb->u.ext2_sb.s_feature_compat |=
- EXT2_FEATURE_COMPAT_BLOCKCOW;
- sb->u.ext2_sb.s_es->s_feature_compat |=
- cpu_to_le32(EXT2_FEATURE_COMPAT_BLOCKCOW);
- }
- }
- sb->u.ext2_sb.s_last_cowed_ino = 0;
- }
-#endif
-#ifdef CONFIG_SNAPFS_EXT3
else if ( strcmp (cache_type,"ext3") == 0 ){
cache->cache_type = FILTER_FS_EXT3;
filter_setup_snapshot_ops(cache->cache_filter,
cpu_to_le32(EXT3_FEATURE_COMPAT_BLOCKCOW);
}
}
- sb->u.ext3_sb.s_last_cowed_ino = 0;
+ sb->u.ext3_sb.s_last_cowed_pri_ino = 0;
+ sb->u.ext3_sb.s_first_cowed_pri_ino = 0;
}
-#endif
-
- CDEBUG(D_SUPER, "\n");
/* now get our own directory operations */
if ( sb->s_root && sb->s_root->d_inode ) {
- CDEBUG(D_SUPER, "\n");
filter_setup_dir_ops(cache->cache_filter,
- sb->s_root->d_inode->i_op,
- ¤tfs_dir_iops);
- CDEBUG(D_SUPER, "\n");
+ sb->s_root->d_inode,
+ ¤tfs_dir_iops, ¤tfs_dir_fops);
sb->s_root->d_inode->i_op =filter_c2udiops(cache->cache_filter);
-// CDEBUG(D_SUPER, "\n");
-// sb->s_root->d_inode->i_snapop = ext2_snapops();
CDEBUG(D_SUPER, "lookup at %p\n",
sb->s_root->d_inode->i_op->lookup);
-#if 0
- /* XXX is this needed ?? */
+ /* XXX is this needed ?? ext3 do not have dentry operations*/
filter_setup_dentry_ops(cache->cache_filter,
sb->s_root->d_op,
¤tfs_dentry_ops);
sb->s_root->d_op = filter_c2udops(cache->cache_filter);
-#endif
}
/*
* Save a pointer to the snap_cache structure in the
* "snap_current" superblock.
*/
(struct snap_cache *) sb->u.generic_sbp = cache;
+
+ snapfs_read_snaptable(cache, tableno);
+
CDEBUG(D_SUPER, "sb %lx, sb->u.generic_sbp: %lx\n",
(ulong) sb, (ulong) sb->u.generic_sbp);
SNAP_FREE(cow_type, strlen(cow_type) + 1);
cow_type = NULL;
}
+ /* Inc in get_fs_type, Dec in put_fs_type*/
- CDEBUG(D_MALLOC, "after mounting: kmem %ld, vmem %ld\n",
- snap_kmemory, snap_vmemory);
-
- MOD_INC_USE_COUNT;
- EXIT;
+ put_filesystem(fstype);
+
return sb;
out_err:
SNAP_FREE(cache_type, strlen(cache_type) + 1);
if (cow_type)
SNAP_FREE(cow_type, strlen(cow_type) + 1);
+ if (fstype)
+ put_filesystem(fstype);
- CDEBUG(D_MALLOC, "mount error exit: kmem %ld, vmem %ld\n",
- snap_kmemory, snap_vmemory);
return NULL;
}
-
-struct file_system_type snapfs_current_type = {
- "snap_current",
- FS_REQUIRES_DEV, /* can use Ibaskets when ext2 does */
- snapfs_read_super,
- NULL
-};
+static DECLARE_FSTYPE_DEV(snapfs_current_type, "snap_current", snapfs_read_super);
/* Find the options for the clone. These consist of a cache device
static int snapfs_path2dev(char *dev_path, kdev_t *dev)
{
struct dentry *dentry;
+ struct nameidata nd;
+ int error = 0;
+
+ if (path_init(dev_path, LOOKUP_FOLLOW, &nd)) {
+ error = path_walk(dev_path, &nd);
+ if (error)
+ return error;
+ } else
+ return -EINVAL;
- dentry = lookup_dentry(dev_path, NULL, 0);
- if (IS_ERR(dentry))
- return PTR_ERR(dentry);
+ dentry = nd.dentry;
- if (!dentry->d_inode)
- return -ENODEV;
-
- if (!S_ISBLK(dentry->d_inode->i_mode))
+ if (!dentry->d_inode || !S_ISBLK(dentry->d_inode->i_mode) ||
+ is_bad_inode(dentry->d_inode) ) {
+ path_release(&nd);
return -ENODEV;
+ }
*dev = dentry->d_inode->i_rdev;
-
+ path_release(&nd);
return 0;
}
ENTRY;
- CDEBUG(D_MALLOC, "before parsing: kmem %ld, vmem %ld\n",
- snap_kmemory, snap_vmemory);
/* reserve space for the cache's data */
- SNAP_ALLOC(cache_data, void *, PAGE_SIZE);
+ SNAP_ALLOC(cache_data, PAGE_SIZE);
if ( !cache_data ) {
- printk("clone_read_super: Cannot allocate data page.\n");
- EXIT;
- goto out_err;
+ CERROR("clone_read_super: Cannot allocate data page.\n");
+ GOTO(out_err, 0);
}
CDEBUG(D_SUPER, "mount opts: %s\n", data ? (char *)data : "(none)");
SNAP_FREE(cache_data, PAGE_SIZE);
cache_data = NULL;
} else {
- printk("clonefs: invalid mount option %s\n", cache_data);
- EXIT;
- goto out_err;
+ CERROR("clonefs: invalid mount option %s\n", cache_data);
+ GOTO(out_err, 0);
}
if (!namestr || !devstr) {
- printk("snapfs: mount options name and dev mandatory\n");
- EXIT;
- goto out_err;
+ CERROR("snapfs: mount options name and dev mandatory\n");
+ GOTO(out_err, 0);
}
err = snapfs_path2dev(devstr, &dev);
if ( err ) {
- printk("snap: incorrect device option %s\n", devstr);
- EXIT;
- goto out_err;
+ CERROR("snap: incorrect device option %s\n", devstr);
+ GOTO(out_err, 0);
}
snap_cache = snap_find_cache(dev);
if ( !snap_cache ) {
- printk("snap: incorrect device option %s\n", devstr);
- EXIT;
- goto out_err;
+ CERROR("snap: incorrect device option %s\n", devstr);
+ GOTO(out_err, 0);
}
/*index = simple_strtoul(indexstr, &endptr, 0);
snap_cache->cache_snap_tableno, namestr, index);
if(index < 0 ) {
- printk("No valid index for name %s passed to mount\n",namestr);
- EXIT;
- goto out_err;
+ CERROR("No valid index for name %s passed to mount\n",namestr);
+ GOTO(out_err, 0);
}
/*
CDEBUG(D_SUPER, "readinode %p, root ino %ld, root inode at %p\n",
sb->s_op->read_inode, root_ino, root_inode);
- sb->s_root = d_alloc_root(root_inode, NULL);
+ sb->s_root = d_alloc_root(root_inode);
if (!sb->s_root) {
list_del(&clone_sb->clone_list_entry);
sb = NULL;
}
- dget( snap_cache->cache_sb->s_root );
+ dget(snap_cache->cache_sb->s_root);
if (cache_data)
SNAP_FREE(cache_data, PAGE_SIZE);
SNAP_FREE(namestr, strlen(namestr) + 1);
CDEBUG(D_SUPER, "sb %lx, &sb->u.generic_sbp: %lx\n",
(ulong) sb, (ulong) &sb->u.generic_sbp);
-
- MOD_INC_USE_COUNT;
- EXIT;
return sb;
out_err:
- CDEBUG(D_MALLOC, "mount error exit: kmem %ld, vmem %ld\n",
- snap_kmemory, snap_vmemory);
return NULL;
}
-
-struct file_system_type snapfs_clone_type = {
- "snap_clone",
- 0,
- clone_read_super,
- NULL
-};
-
+static DECLARE_FSTYPE(snapfs_clone_type, "snap_clone", clone_read_super, 0);
int init_snapfs(void)
{
int status;
snap_init_cache_hash();
+ init_filter_info_cache();
- status = register_filesystem(&snapfs_current_type);
- if (status) {
- printk("snapfs: failed in register current filesystem!\n");
- }
status = register_filesystem(&snapfs_clone_type);
if (status) {
unregister_filesystem(&snapfs_current_type);
- printk("snapfs: failed in register clone filesystem!\n");
+ CERROR("snapfs: failed in register clone filesystem!\n");
+ }
+
+ status = register_filesystem(&snapfs_current_type);
+ if (status) {
+ CERROR("snapfs: failed in register current filesystem!\n");
}
return status;
}
ENTRY;
+ cleanup_filter_info_cache();
err = unregister_filesystem(&snapfs_clone_type);
if ( err ) {
- printk("snapfs: failed to unregister clone filesystem\n");
+ CERROR("snapfs: failed to unregister clone filesystem\n");
}
err = unregister_filesystem(&snapfs_current_type);
if ( err ) {
- printk("snapfs: failed to unregister filesystem\n");
+ CERROR("snapfs: failed to unregister filesystem\n");
}
-
return 0;
}
* A snap shot file system.
*
*/
+#define DEBUG_SUBSYSTEM S_SNAP
-#define EXPORT_SYMTAB
-
-
-#define __NO_VERSION__
-#include <linux/module.h>
-#include <asm/uaccess.h>
-#include <linux/sched.h>
-#include <linux/stat.h>
+#include <linux/kmod.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/slab.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>
+#include <linux/jbd.h>
+#include <linux/ext3_fs.h>
+#include <linux/snap.h>
+
+#include "snapfs_internal.h"
-#include <linux/filter.h>
-#include <linux/snapfs.h>
-#include <linux/snapsupport.h>
static inline int inode_has_ea(struct inode *inode)
{
* (1) we are not lies in .snap
* (2) we are already in the root's .snap
*/
-static struct dentry * dotsnap_follow_link(struct dentry *base,
- struct dentry *dentry,
- int follow)
+static int dotsnap_follow_link(struct dentry *dentry,
+ struct nameidata *nd)
{
struct super_block *sb = dentry->d_inode->i_sb;
- struct dentry *rc = NULL;
struct dentry *de = dentry, *de_save1=NULL, *de_save2=NULL;
char *buf = NULL;
- int pos = D_MAXLEN;
+ int pos = D_MAXLEN, rc;
- SNAP_ALLOC(buf, char*, D_MAXLEN);
+ SNAP_ALLOC(buf, D_MAXLEN);
if( !buf )
- return ERR_PTR(-ENOMEM);
+ RETURN(-ENOMEM);
/*
* iterate upward to construct the path
pos = cat_str_ahead(buf, pos, ".snap");
buf[D_MAXLEN-1] = 0;
- CDEBUG(D_FILE, "constructed path: %s\n", &buf[pos]);
+ CDEBUG(D_SNAP, "constructed path: %s\n", &buf[pos]);
/* FIXME lookup_dentry will never return NULL ?? */
+#if 0
rc = lookup_dentry(&buf[pos], dget(sb->s_root), follow);
if( !rc ){
rc = ERR_PTR(-ENOENT);
- CDEBUG(D_FILE, "lookup_dentry return NULL~!@#$^&*\n");
+ CDEBUG(D_SNAP, "lookup_dentry return NULL~!@#$^&*\n");
}
- dput(base);
-
+#else
+ if (path_init(&buf[pos], LOOKUP_FOLLOW, nd)) {
+ rc = path_walk(&buf[pos], nd);
+ if (rc)
+ GOTO(exit, rc);
+ }
+#endif
exit:
SNAP_FREE(buf, D_MAXLEN);
return rc;
}
-static struct dentry * currentfs_follow_link ( struct dentry *dentry,
- struct dentry *base,
- unsigned int follow)
+static int currentfs_follow_link (struct dentry *dentry, struct nameidata *nd)
{
struct snap_cache *cache;
- struct dentry * rc;
struct inode_operations *iops;
struct inode * inode = dentry->d_inode;
int bpib = inode->i_sb->s_blocksize >> 9;
__u32 save_i_blocks;
-
+ int rc;
ENTRY;
cache = snap_find_cache(inode->i_dev);
if ( !cache ) {
- EXIT;
- return ERR_PTR(-EINVAL);
+ RETURN(-EINVAL);
}
iops = filter_c2csiops(cache->cache_filter);
if (!iops ||
!iops->follow_link) {
- rc = ERR_PTR(-EINVAL);
- goto exit;
+ GOTO(exit, rc = -EINVAL);
}
if( currentfs_is_under_dotsnap(dentry) ){
- rc = dotsnap_follow_link( base, dentry, follow );
+ rc = dotsnap_follow_link(dentry, nd);
if( rc )
goto exit;
}
if( inode_has_ea(inode) && inode->i_blocks == bpib ) {
inode->i_blocks = 0;
}
- rc = iops->follow_link(dentry, base, follow);
+ rc = iops->follow_link(dentry, nd);
if( inode->i_blocks != save_i_blocks ){
inode->i_blocks = save_i_blocks;
}
exit:
- EXIT;
- return rc;
+ RETURN(rc);
}
struct inode_operations currentfs_sym_iops = {
readlink: currentfs_readlink,
- follow_link: currentfs_follow_link
+ follow_link: currentfs_follow_link,
};
-struct file_operations currentfs_sym_fops;
+struct file_operations currentfs_sym_fops = {
+ ioctl: NULL,
+};
* Sysctrl entries for Snapfs
*/
-#define __NO_VERSION__
-#include <linux/config.h> /* for CONFIG_PROC_FS */
+/* /proc entries */
+
+#define DEBUG_SUBSYSTEM S_SNAP
+
#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
+#include <linux/kmod.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/string.h>
#include <linux/sysctl.h>
-#include <linux/swapctl.h>
#include <linux/proc_fs.h>
-#include <linux/malloc.h>
-#include <linux/vmalloc.h>
-#include <linux/stat.h>
-#include <linux/ctype.h>
-#include <linux/init.h>
-#include <asm/bitops.h>
-#include <asm/segment.h>
-#include <asm/uaccess.h>
-#include <linux/utsname.h>
-#include <linux/blk.h>
-
-#include <linux/filter.h>
-#include <linux/snapfs.h>
-#include <linux/snapsupport.h>
+#include <linux/jbd.h>
+#include <linux/ext3_fs.h>
+#include <linux/snap.h>
+#include "snapfs_internal.h"
-/* /proc entries */
#ifdef CONFIG_PROC_FS
-
-
-static void snapfs_proc_modcount(struct inode *inode, int fill)
-{
- if (fill)
- MOD_INC_USE_COUNT;
- else
- MOD_DEC_USE_COUNT;
-}
-
-struct proc_dir_entry proc_fs_snapfs = {
- 0, 10, "snapfs",
- S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
- 0, &proc_dir_inode_operations,
- NULL, NULL,
- NULL,
- NULL, NULL
-};
-
-
+static struct proc_dir_entry *proc_snapfs_root;
#endif
#define ENTRY_CNT 3
/* XXX - doesn't seem to be working in 2.2.15 */
-static struct ctl_table snapfs_ctltable[ENTRY_CNT] =
+static struct ctl_table snapfs_ctltable[] =
{
+#ifdef SNAP_DEBUG
{PSDEV_DEBUG, "debug", &snap_debug_level, sizeof(int), 0644, NULL, &proc_dointvec},
+#endif
{PSDEV_TRACE, "trace", &snap_print_entry, sizeof(int), 0644, NULL, &proc_dointvec},
{0}
};
};
-int /* __init */ init_snapfs_proc_sys(void)
+int __init init_snapfs_proc_sys(void)
{
+#ifdef CONFIG_PROC_FS
+ proc_snapfs_root = proc_mkdir("snapfs", proc_root_fs);
+ if (!proc_snapfs_root) {
+ printk(KERN_ERR "SNAPFS: error registering /proc/fs/snapfs\n");
+ RETURN(-ENOMEM);
+ }
+ proc_snapfs_root->owner = THIS_MODULE;
+#endif
#ifdef CONFIG_SYSCTL
if ( !snapfs_table_header )
snapfs_table_header =
register_sysctl_table(snapfs_table, 0);
#endif
-#ifdef CONFIG_PROC_FS
- proc_register(&proc_root_fs, &proc_fs_snapfs);
- proc_fs_snapfs.fill_inode = &snapfs_proc_modcount;
-#endif
return 0;
}
-void cleanup_snapfs_proc_sys(void) {
-
+void cleanup_snapfs_proc_sys(void)
+{
#ifdef CONFIG_SYSCTL
if ( snapfs_table_header )
unregister_sysctl_table(snapfs_table_header);
snapfs_table_header = NULL;
#endif
-
#if CONFIG_PROC_FS
- proc_unregister(&proc_root_fs, proc_fs_snapfs.low_ino);
+ remove_proc_entry("snapfs", proc_root_fs);
#endif
+
}