*
* Author: Peter J. Braam <braam@mountainviewdata.com>
*/
-#define DEBUG_SUBSYSTEM S_SNAP
+#define DEBUG_SUBSYSTEM S_SM
+#include <linux/config.h>
#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/mm.h>
+#include <linux/utime.h>
+#include <linux/file.h>
+#include <linux/slab.h>
#include <linux/loop.h>
#include <linux/errno.h>
#include "smfs_internal.h"
}
return pos;
}
-static int get_fd(struct file *filp)
+static int close_fd(int fd)
{
struct files_struct *files = current->files;
- int fd = 0;
-
+
write_lock(&files->file_lock);
- for (fd = 0; fd < files->max_fds; fd++) {
- if(files->fd[fd] == filp) {
- write_unlock(&files->file_lock);
- return fd;
- }
- }
+
+ files->fd[fd] = NULL;
+ __put_unused_fd(files, fd);
+
write_unlock(&files->file_lock);
- RETURN(-1);
+ return 0;
+}
+static int set_loop_fd(char *dev_path, char *loop_dev)
+{
+ struct loop_info loopinfo;
+ struct nameidata nd;
+ struct dentry *dentry;
+ struct block_device_operations *bd_ops;
+ struct file *filp;
+ int fd = 0, error = 0;
+
+ fd = get_unused_fd();
+
+ if (!fd) RETURN(-EINVAL);
+
+ filp = filp_open(dev_path, FMODE_WRITE, 0);
+ if (!filp || !S_ISREG(filp->f_dentry->d_inode->i_mode))
+ RETURN(-EINVAL);
+
+ fd_install(fd, filp);
+
+ if (path_init(loop_dev, LOOKUP_FOLLOW, &nd)) {
+ error = path_walk(loop_dev, &nd);
+ if (error) {
+ path_release(&nd);
+ filp_close(filp, current->files);
+ RETURN(-EINVAL);
+ }
+ } else {
+ path_release(&nd);
+ filp_close(filp, current->files);
+ RETURN(-EINVAL);
+ }
+ dentry = nd.dentry;
+ bd_ops = get_blkfops(LOOP_MAJOR);
+
+ error = bd_ops->ioctl(dentry->d_inode, filp, LOOP_SET_FD,
+ (unsigned long)fd);
+ if (error) {
+ path_release(&nd);
+ filp_close(filp, current->files);
+ RETURN(-EINVAL);
+ }
+ memset(&loopinfo, 0, sizeof(struct loop_info));
+
+ error = bd_ops->ioctl(dentry->d_inode, filp, LOOP_SET_STATUS,
+ (unsigned long)(&loopinfo));
+ path_release(&nd);
+ RETURN(error);
}
+
+#define SIZE(a) (sizeof(a)/sizeof(a[0]))
+static char *find_unused_and_set_loop_device(char *dev_path)
+{
+ char *loop_formats[] = { "/dev/loop/%d", "/dev/loop%d"};
+ struct loop_info loopinfo;
+ struct nameidata nd;
+ struct dentry *dentry;
+ char *dev = NULL;
+ int i, j, error;
+
+ for (j = 0; j < SIZE(loop_formats); j++) {
+ SM_ALLOC(dev, strlen(loop_formats[i]) + 1);
+ for(i = 0; i < 256; i++) {
+ struct block_device_operations *bd_ops;
+
+ sprintf(dev, loop_formats[j], i);
+
+ if (path_init(dev, LOOKUP_FOLLOW, &nd)) {
+ error = path_walk(dev, &nd);
+ if (error && error != -ENOENT) {
+ path_release(&nd);
+ SM_FREE(dev, strlen(loop_formats[i]) + 1);
+ RETURN(NULL);
+ }
+ } else {
+ SM_FREE(dev, strlen(loop_formats[i]) + 1);
+ RETURN(NULL);
+ }
+ dentry = nd.dentry;
+ bd_ops = get_blkfops(LOOP_MAJOR);
+ error = bd_ops->ioctl(dentry->d_inode, NULL, LOOP_GET_STATUS,
+ (unsigned long)&loopinfo);
+ path_release(&nd);
+
+ if (error == -ENXIO) {
+ /*find unused loop and set dev_path to loopdev*/
+ error = set_loop_fd(dev_path, dev);
+ if (error) {
+ SM_FREE(dev, strlen(loop_formats[i]) + 1);
+ dev = NULL;
+ }
+ return dev;/* probably free */
+ }
+ }
+ SM_FREE(dev, strlen(loop_formats[i]) + 1);
+ }
+ RETURN(NULL);
+}
+
#define MAX_LOOP_DEVICES 256
static char *parse_path2dev(struct super_block *sb, char *dev_path)
{
- struct file *filp;
- int i = 0, fd = 0, error = 0;
+ struct dentry *dentry;
+ struct nameidata nd;
char *name = NULL;
-
- filp = filp_open(dev_path, 0, 0);
- if (!filp)
- RETURN(NULL);
+ int error = 0;
- if (S_ISREG(filp->f_dentry->d_inode->i_mode)) {
- /*here we must walk through all the snap cache to
- *find the loop device */
- for (i = 0; i < MAX_LOOP_DEVICES; i++) {
- fd = get_fd(filp);
- error = sb->s_bdev->bd_op->ioctl(filp->f_dentry->d_inode,
- filp, LOOP_SET_FD,
- (unsigned long)&fd);
- if (!error) {
- filp_close(filp, current->files);
- /*FIXME later, the loop file should
- *be different for different system*/
- SM_ALLOC(name, strlen("/dev/loop/") + 2);
- sprintf(name, "dev/loop/%d", i);
- RETURN(name);
- }
+ if (path_init(dev_path, LOOKUP_FOLLOW, &nd)) {
+ error = path_walk(dev_path, &nd);
+ if (error) {
+ path_release(&nd);
+ RETURN(NULL);
}
+ } else {
+ RETURN(NULL);
+ }
+ dentry = nd.dentry;
+
+ if (!dentry->d_inode || is_bad_inode(dentry->d_inode) ||
+ (!S_ISBLK(dentry->d_inode->i_mode) &&
+ !S_ISREG(dentry->d_inode->i_mode))){
+ path_release(&nd);
+ RETURN(NULL);
+ }
+
+ if (S_ISREG(dentry->d_inode->i_mode)) {
+ name = find_unused_and_set_loop_device(dev_path);
+ path_release(&nd);
+ RETURN(name);
}
SM_ALLOC(name, strlen(dev_path) + 1);
memcpy(name, dev_path, strlen(dev_path) + 1);
- filp_close(filp, current->files);
RETURN(name);
}
+static void duplicate_sb(struct super_block *csb,
+ struct super_block *sb)
+{
+ sb->s_blocksize = csb->s_blocksize;
+ sb->s_magic = csb->s_magic;
+ sb->s_blocksize_bits = csb->s_blocksize_bits;
+ sb->s_maxbytes = csb->s_maxbytes;
+}
extern struct super_operations smfs_super_ops;
static int sm_mount_cache(struct super_block *sb,
free_page(page);
if (IS_ERR(mnt)) {
- CERROR("do_kern_mount failed: rc = %d\n", err);
- GOTO(err_out, 0);
+ CERROR("do_kern_mount failed: rc = %d\n", PTR_ERR(mnt));
+ GOTO(err_out, err = PTR_ERR(mnt));
}
smb = S2SMI(sb);
smb->smsi_sb = mnt->mnt_sb;
smb->smsi_mnt = mnt;
+
+ duplicate_sb(mnt->mnt_sb, sb);
+ sm_set_sb_ops(mnt->mnt_sb, sb);
err_out:
if (dev_name)
SM_FREE(dev_name, strlen(dev_name) + 2);
return err;
}
+static int sm_umount_cache(struct super_block *sb)
+{
+ struct smfs_super_info *smb = S2SMI(sb);
+
+ mntput(smb->smsi_mnt);
+
+ return 0;
+}
+void smfs_put_super(struct super_block *sb)
+{
+ if (sb)
+ sm_umount_cache(sb);
+ return;
+}
struct super_block *
smfs_read_super(
void *data,
int silent)
{
- struct smfs_inode_info *smi;
- struct dentry *bottom_root;
struct inode *root_inode = NULL;
char *devstr = NULL, *typestr = NULL;
char *cache_data;
CERROR("Can not mount %s as %s\n", devstr, typestr);
GOTO(out_err, 0);
}
- /* set up the super block */
- sb->s_op = &smfs_super_ops;
-
- bottom_root = dget(S2SMI(sb)->smsi_sb->s_root);
- if (!bottom_root) {
- CERROR("bottom not mounted\n");
- GOTO(out_err, err=-ENOENT);
- }
-
- root_ino = bottom_root->d_inode->i_ino;
- smi = I2SMI(root_inode);
- /*FIXME Intialize smi here*/
-
+ dget(S2CSB(sb)->s_root);
+ root_ino = S2CSB(sb)->s_root->d_inode->i_ino;
+ root_inode = iget(sb, root_ino);
+
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(bottom_root->d_inode);
+ sb->s_root = d_alloc_root(root_inode);
if (!sb->s_root) {
GOTO(out_err, err=-EINVAL);
}
-
+
CDEBUG(D_SUPER, "sb %lx, &sb->u.generic_sbp: %lx\n",
(ulong) sb, (ulong) &sb->u.generic_sbp);
- out_err:
+out_err:
cleanup_option();
if (err)
return NULL;
int init_smfs(void)
{
- int err;
+ int err = 0;
err = register_filesystem(&smfs_type);
if (err) {
CERROR("smfs: failed in register Storage Management filesystem!\n");
}
+ init_smfs_cache();
return err;
}
int cleanup_smfs(void)
{
- int err;
+ int err = 0;
ENTRY;
err = unregister_filesystem(&smfs_type);
if (err) {
CERROR("smfs: failed to unregister Storage Management filesystem!\n");
}
+ cleanup_smfs_cache();
return 0;
}