*
*/
-#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;
+ inode->i_fop = &clonefs_file_file_ops;
+ } else if (S_ISDIR(inode->i_mode)) {
+ inode->i_op = &clonefs_dir_inode_ops;
+ inode->i_fop = &clonefs_dir_file_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;
+
+ put_snap_current_mnt(clone_sb->clone_cache->cache_sb);
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 */
};
dput(dentry); /* this will free the dentry memory */
}
+static void prepare_parent_dentry(struct dentry *dentry, struct inode *inode)
+{
+ atomic_set(&dentry->d_count, 1);
+ dentry->d_vfs_flags = 0;
+ dentry->d_flags = 0;
+ dentry->d_inode = inode;
+ dentry->d_op = NULL;
+ dentry->d_fsdata = NULL;
+ dentry->d_mounted = 0;
+ INIT_LIST_HEAD(&dentry->d_hash);
+ INIT_LIST_HEAD(&dentry->d_lru);
+ INIT_LIST_HEAD(&dentry->d_subdirs);
+ INIT_LIST_HEAD(&dentry->d_alias);
+}
/*
* Return the underlying fs dentry with name in 'dentry' that points
* to the right inode. 'dir' is the clone fs directory to search for
*/
struct dentry *clonefs_lookup(struct inode *dir, struct dentry *dentry)
{
- struct inode *cache_dir;
- struct dentry *cache_dentry;
+ struct inode *cache_dir = NULL;
+ struct dentry *cache_dentry = NULL;
struct inode *cache_inode;
struct dentry *result;
+ struct dentry tmp;
struct inode *inode;
struct snap_clone_info *clone_sb;
ENTRY;
cache_dir = clonefs_get_inode(dir);
-
- cache_dentry = d_alloc(dentry->d_parent, &dentry->d_name);
+ if (!cache_dir)
+ RETURN(ERR_PTR(-ENOENT));
+ /*FIXME later, we make parent dentry here
+ *there may some problems in lookup
+ */
+ prepare_parent_dentry(&tmp, cache_dir);
+ cache_dentry = d_alloc(&tmp, &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,
struct inode *cache_inode;
struct file open_file;
struct dentry open_dentry;
- struct inode *inode=file->f_dentry->d_inode;
+ struct inode *inode = file->f_dentry->d_inode;
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,
&open_dentry);
/* tell currentfs_readpage the primary inode number */
open_dentry.d_fsdata = (void*)inode->i_ino;
-
+ page->mapping->host = cache_inode;
/* 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);
+ page->mapping->host = inode;
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;
struct inode * old_inode;
+ int rc = -ENOENT;
ENTRY;
cache_inode = clonefs_get_inode(dentry->d_inode);
- res = -ENOENT;
-
- if ( ! cache_inode ) {
+ if (!cache_inode) {
CDEBUG(D_INODE, "clonefs_get_inode failed, NULL\n");
- EXIT;
- return res;
+ RETURN(rc);
}
/* 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 */
/* set dentry inode to cache inode */
dentry->d_inode = cache_inode;
- if ( cache_inode->i_op->readlink ) {
- res = cache_inode->i_op->readlink(dentry, buf, len);
+ if (cache_inode->i_op->readlink) {
+ rc = cache_inode->i_op->readlink(dentry, buf, len);
}else {
CDEBUG(D_INODE,"NO readlink for ino %lu\n", cache_inode->i_ino);
}
iput(cache_inode);
- EXIT;
- return res;
+ RETURN(rc);
}
-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 rc = -ENOENT;
ENTRY;
- res = ERR_PTR(-ENOENT);
cache_inode = clonefs_get_inode(dentry->d_inode);
- if ( ! cache_inode ) {
+ if (!cache_inode) {
CDEBUG(D_INODE, "clonefs_get_inode failed, NULL\n");
- EXIT;
- return res;
+ RETURN(rc);
}
/* XXX: shall we allocate a new dentry ?
/* set dentry inode to cache inode */
dentry->d_inode = cache_inode;
- if ( cache_inode->i_op->follow_link ) {
- res = cache_inode->i_op->follow_link(dentry, base, follow);
+ if (cache_inode->i_op->follow_link) {
+ rc = cache_inode->i_op->follow_link(dentry, nd);
}
/* restore the old inode */
iput(cache_inode);
- EXIT;
- return res;
+ RETURN(rc);
}
+static ssize_t
+clonefs_getxattr(struct dentry *dentry, const char *name,
+ void *buffer, size_t size)
+{
+ struct inode * cache_inode;
+ struct inode * old_inode;
+ int rc = -ENOENT;
+
+ ENTRY;
+
+ cache_inode = clonefs_get_inode(dentry->d_inode);
+ if (!cache_inode) {
+ CDEBUG(D_INODE, "clonefs_get_inode failed, NULL\n");
+ RETURN(rc);
+ }
+
+ /* XXX: shall we allocate a new dentry ?
+ The following is safe for ext2, etc. because ext2_follow_link
+ only use the inode info */
-struct inode_operations clonefs_symlink_inode_operations =
+ /* save the old dentry inode */
+ old_inode = dentry->d_inode;
+ /* set dentry inode to cache inode */
+ dentry->d_inode = cache_inode;
+
+ if (cache_inode->i_op->getxattr) {
+ rc = cache_inode->i_op->getxattr(dentry, name, buffer, size);
+ }
+
+ /* restore the old inode */
+ dentry->d_inode = old_inode;
+
+ iput(cache_inode);
+
+ RETURN(rc);
+}
+static ssize_t
+clonefs_listxattr(struct dentry *dentry, char *buffer, size_t size)
+{
+ struct inode * cache_inode;
+ struct inode * old_inode;
+ int rc = -ENOENT;
+
+ ENTRY;
+
+ cache_inode = clonefs_get_inode(dentry->d_inode);
+ if (!cache_inode) {
+ CDEBUG(D_INODE, "clonefs_get_inode failed, NULL\n");
+ RETURN(rc);
+ }
+
+ /* XXX: shall we allocate a new dentry ?
+ The following is safe for ext2, etc. because ext2_follow_link
+ only use the inode info */
+
+ /* save the old dentry inode */
+ old_inode = dentry->d_inode;
+ /* set dentry inode to cache inode */
+ dentry->d_inode = cache_inode;
+
+ if (cache_inode->i_op->listxattr) {
+ rc = cache_inode->i_op->listxattr(dentry, buffer, size);
+ }
+
+ /* restore the old inode */
+ dentry->d_inode = old_inode;
+
+ iput(cache_inode);
+
+ RETURN(rc);
+
+}
+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 */
+ getxattr: clonefs_getxattr, /* get xattr */
+ listxattr: clonefs_listxattr, /* list xattr */
};
+int clonefs_mounted(struct snap_cache *cache, int index)
+{
+ struct snap_clone_info *clone_sb;
+ struct list_head *list, *end;
+
+ end = list = &cache->cache_clone_list;
+
+ list_for_each_entry(clone_sb, list, clone_list_entry) {
+ if (clone_sb->clone_index == index)
+ return 1;
+ }
+ return 0;
+}
+