--- /dev/null
+#ifndef __OBD_H
+#define __OBD_H
+
+
+struct obd_conn_info {
+ unsigned int conn_id; /* handle */
+};
+
+struct obd_type {
+ struct list_head typ_chain;
+ struct obd_ops *typ_ops;
+ char *typ_name;
+ int typ_refcnt;
+};
+
+
+
+
+#endif
-#ifndef __LINUX_SIM_OBD_H
-#define __LINUX_SIM_OBD_H
+#ifndef __LINUX_CLASS_OBD_H
+#define __LINUX_CLASS_OBD_H
#include <linux/fs.h>
#include <linux/ext2_fs.h>
+#include <linux/obd.h>
+
#include <linux/obd_sim.h>
+#include <linux/obd_snap.h>
/* #include <linux/obd_fc.h> */
+#include <linux/obd_raid1.h>
+
#define OBD_PSDEV_MAJOR 120
#define MAX_OBD_DEVICES 2
+#define MAX_MULTI 16
+
+typedef unsigned long objid;
+typedef struct inode obdattr;
extern struct obd_device obd_dev[MAX_OBD_DEVICES];
-struct obd_conn_info {
- unsigned int conn_id; /* handle */
-};
-struct obd_type {
- struct list_head typ_chain;
- struct obd_ops *typ_ops;
- char *typ_name;
- int typ_refcnt;
-};
#define OBD_ATTACHED 0x1
#define OBD_SET_UP 0x2
int obd_minor;
int obd_flags;
int obd_refcnt;
+ int obd_multi_count;
+ struct obd_device *obd_multi_dev[MAX_MULTI];
+ struct obd_conn_info obd_multi_conns[MAX_MULTI];
+ unsigned int obd_gen_last_id;
+ unsigned long obd_gen_prealloc_quota;
+ struct list_head obd_gen_clients;
union {
struct sim_obd sim;
+ struct raid1_obd raid1;
+ struct snap_obd snap;
/* struct fc_obd fc; */
} u;
};
int (*o_setattr)(unsigned int conn_id, unsigned long id, struct inode *iattr);
int (*o_getattr)(unsigned int conn_id, unsigned long id, struct inode *iattr);
int (*o_statfs)(unsigned int conn_id, struct statfs *statfs);
- int (*o_create)(struct obd_device *, int prealloc_ino, int *er);
+ int (*o_create)(int conn_id, int prealloc_ino, int *er);
int (*o_destroy)(unsigned int conn_id, unsigned long ino);
unsigned long (*o_read)(unsigned int conn_id, unsigned long ino, char *buf, unsigned long count, loff_t offset, int *err);
unsigned long (*o_read2)(unsigned int conn_id, unsigned long ino, char *buf, unsigned long count, loff_t offset, int *err);
unsigned long (*o_write)(unsigned int conn_id, unsigned long ino, char *buf, unsigned long count, loff_t offset, int *err);
int (*o_brw)(int rw, int conn, int objectid, struct page *page, int create);
long (*o_preallocate)(unsigned int conn_id, int req, long inodes[32], int *err);
- void (*o_cleanup_device)(int dev);
+ int (*o_cleanup_device)(struct obd_device *);
int (*o_get_info)(unsigned int conn_id, int keylen, void *key, int *vallen, void **val);
int (*o_set_info)(unsigned int conn_id, int keylen, void *key, int vallen, void *val);
};
+#define OBP(dev,op) dev->obd_type->typ_ops->o_ ## op
+
int obd_register_type(struct obd_ops *ops, char *nm);
int obd_unregister_type(char *nm);
unsigned long inode;
};
+/* generic operations shared by various OBD types */
+int gen_connect (struct obd_device *obddev,
+ struct obd_conn_info * conninfo);
+int gen_disconnect(unsigned int conn_id);
+int gen_multi_setup(struct obd_device *obddev, int len, void *data);
+int gen_multi_cleanup(struct obd_device *obddev);
+int gen_multi_attach(struct obd_device *obddev, int len, void *data);
+struct obd_client *gen_client(int cli_id);
+int gen_multi_cleanup_device(struct obd_device *obddev);
+int gen_cleanup(struct obd_device *obddev);
+
+
+
/*
* ioctl commands
*/
* of succesfully preallocated inodes */
long inodes[32]; /* actual inode numbers */
};
-struct oic_attr_s {
+
+struct oic_create_s {
unsigned int conn_id;
- unsigned long inode;
+ unsigned long prealloc;
+};
+struct oic_attr_s {
+ unsigned int conn_id;
+ unsigned long ino;
struct iattr iattr;
};
struct oic_rw_s {
#define OBD_IOC_CREATE _IOR ('f', 3, long)
#define OBD_IOC_SETUP_OBDDEV _IOW ('f', 4, long)
-#define OBD_IOC_CLEANUP_OBDDEV _IO ('f', 5 )
+#define OBD_IOC_CLEANUP _IO ('f', 5 )
#define OBD_IOC_DESTROY _IOW ('f', 6, long)
#define OBD_IOC_PREALLOCATE _IOWR('f', 7, long)
#define OBD_IOC_DEC_USE_COUNT _IO ('f', 8 )
extern void obd_sysctl_clean (void);
-#endif /* __LINUX_SIM_OBD_H */
+#endif /* __LINUX_CLASS_OBD_H */
--- /dev/null
+#ifndef _OBD_RAID1
+#define _OBD_RAID1
+
+#include <linux/obd_class.h>
+
+#define MAX_RAID1 16
+
+
+struct raid1_obd {
+ unsigned int raid1_count; /* how many replicas */
+ /* devices to replicate on */
+ struct obd_device *raid1_devlist[MAX_RAID1];
+ /* connections we make */
+ struct obd_conn_info raid1_connections[MAX_RAID1];
+ struct list_head raid1_clients; /* clients we have */
+};
+
+
+/* development definitions */
+extern struct obdfs_sb_info *obd_sbi;
+extern struct file_operations *obd_fso;
+
+/* obd_raid1.c */
+extern struct obd_ops raid1_obd_ops;
+inline long ext2_block_map (struct inode * inode, long block);
+
+/* balloc.c */
+int ext2_new_block (const struct inode * inode, unsigned long goal,
+ u32 * prealloc_count, u32 * prealloc_block, int * err);
+void ext2_free_blocks (const struct inode * inode, unsigned long block,
+ unsigned long count);
+unsigned long ext2_count_free_blocks (struct super_block * sb);
+int ext2_group_sparse(int group);
+struct ext2_group_desc * ext2_get_group_desc(struct super_block * sb,
+ unsigned int block_group,
+ struct buffer_head ** bh);
+
+/* bitmap.c */
+unsigned long ext2_count_free(struct buffer_head * map, unsigned int numchars);
+
+/* fsync.c */
+extern int obd_sync_file(struct file * file, struct dentry *dentry);
+
+/* ialloc.c */
+extern void ext2_free_inode (struct inode * inode);
+extern struct inode * ext2_new_inode (const struct inode * dir, int mode,
+ int * err);
+extern unsigned long ext2_count_free_inodes (struct super_block * sb);
+extern void ext2_check_inodes_bitmap (struct super_block * sb);
+extern int load_inode_bitmap (struct super_block * sb,
+ unsigned int block_group);
+
+/* inode.c */
+void obd_read_inode (struct inode * inode);
+void obd_write_inode (struct inode * inode);
+void obd_put_inode (struct inode * inode);
+void obd_delete_inode (struct inode * inode);
+void obd_discard_prealloc_blocks (struct inode * inode);
+int obd_sync_inode (struct inode *inode);
+struct buffer_head * obd_bread (struct inode * inode, int block,
+ int create, int *err);
+struct buffer_head * obd_getblk (struct inode * inode, long block,
+ int create, int * err);
+
+
+/* super.c */
+#define ext2_warning obd_warning
+#undef ext2_error
+#define ext2_error obd_warning
+#define ext2_panic obd_warning
+#ifdef EXT2FS_DEBUG
+# undef ext2_debug
+# define ext2_debug(format, a...) CDEBUG(D_EXT2, format, ## a)
+#endif
+
+#define obd_error obd_warning
+#define obd_panic obd_warning
+#define obd_warning(sb, func, format, a...) CDEBUG(D_WARNING, format, ## a)
+
+int obd_remount (struct super_block * sb, int * flags, char * data);
+struct super_block * ext2_read_super (struct super_block * sb, void * data,
+ int silent);
+
+/* truncate.c */
+void obd_truncate (struct inode * inode);
+
+/* operations */
+/* dir.c */
+extern struct inode_operations ext2_dir_inode_operations;
+
+/* file.c */
+extern struct file_operations ext2_file_operations;
+extern struct inode_operations ext2_file_inode_operations;
+
+/* super.c */
+extern struct super_operations ext2_sops;
+
+#endif
struct sim_obd {
struct super_block * sim_sb;
- unsigned int sim_last_id;
- unsigned long sim_prealloc_quota;
- struct list_head sim_clients;
};
--- /dev/null
+#ifndef _OBD_SIM
+#define _OBD_SIM
+
+#define OBD_SNAP_MAGIC 0x47224722
+
+#define SNAP_MAX 8 /* must fit in "u" area of struct inode */
+struct snap_obd_data {
+ int snap_dev; /* which device contains the data */
+ unsigned int snap_no; /* which snapshot are we accessing */
+ unsigned int snap_count; /* how many snapshots exist */
+ time_t snap_times[SNAP_MAX];
+};
+
+struct snap_obd {
+ unsigned int snap_no; /* which snapshot are we accessing */
+ unsigned int snap_count; /* how many snapshots exist */
+ time_t snap_times[SNAP_MAX];
+};
+
+struct snap_object_data {
+ int od_magic;
+ /* id of snaps of object; slot 0 has the current data */
+ unsigned long od_ids[SNAP_MAX + 1];
+}
+
+
+
+#endif
#define SIM_OBD_DEBUG
+
+#define MIN(a,b) (((a)<(b)) ? (a): (b))
+#define MAX(a,b) (((a)>(b)) ? (a): (b))
+
/*
* Debug code
*/
#define CMD(cmd) (( cmd == READ ) ? "read" : "write")
-#define PDEBUG(page,cmd) {\
+#define PDEBUG(page,cmd) {if (page){\
char *uptodate = (Page_Uptodate(page)) ? "yes" : "no";\
char *locked = (PageLocked(page)) ? "yes" : "no";\
int count = page->count.counter;\
long offset = page->offset / PAGE_SIZE;\
\
CDEBUG(D_IOCTL, " ** %s, cmd: %s, ino: %ld, off %ld, uptodate: %s, "\
- "locked: %s, cnt %d ** \n", __FUNCTION__,\
- cmd, ino, offset, uptodate, locked, count);\
- }
+ "locked: %s, cnt %d page %p ** \n", __FUNCTION__,\
+ cmd, ino, offset, uptodate, locked, count, page);\
+ } else { CDEBUG(D_IOCTL, "** %s, no page\n", __FUNCTION__); }}
#define OBD_ALLOC(ptr, cast, size) \
/* allocation of space */
dest->i_blocks = src->i_blocks;
- memcpy(&dest->u, &src->u, sizeof(src->u));
+ if ( !dest->i_blocks)
+ memcpy(&dest->u, &src->u, sizeof(src->u));
}
int obdfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry);
/* dir.c */
int obdfs_readdir(struct file * filp, void * dirent, filldir_t filldir);
+int obdfs_check_dir_entry (const char * function, struct inode * dir,
+ struct ext2_dir_entry_2 * de,
+ struct page * page,
+ unsigned long offset);
struct obdfs_sb_info {
struct obd_conn_info osi_conn_info;
CDEBUG(D_IOCTL, "Attach %d, type %s\n",
dev, obddev->obd_type->typ_name);
- if (!obddev->obd_type->typ_ops ||
- !obddev->obd_type->typ_ops->o_attach ) {
+ if (!obddev->obd_type->typ_ops || !OBP(obddev,attach)) {
obddev->obd_flags |= OBD_ATTACHED;
type->typ_refcnt++;
MOD_INC_USE_COUNT;
}
/* do the attach */
- err = obddev->obd_type->typ_ops->o_attach
- (obddev, input.att_datalen, &input.att_data);
+ err = OBP(obddev,attach)(obddev,
+ input.att_datalen, &input.att_data);
OBD_FREE(input.att_data, input.att_datalen);
if ( err ) {
CDEBUG(D_IOCTL, "Setup %d, type %s\n", dev,
obddev->obd_type->typ_name);
if ( !obddev->obd_type->typ_ops ||
- !obddev->obd_type->typ_ops->o_setup )
- return -EOPNOTSUPP;
+ !obddev->obd_type->typ_ops->o_setup ) {
+ obddev->obd_flags |= OBD_SET_UP;
+ return 0;
+ }
err = obddev->obd_type->typ_ops->o_setup
(obddev, input.setup_datalen, input.setup_data);
obddev->obd_flags |= OBD_SET_UP;
return err;
}
- case OBD_IOC_CLEANUP_OBDDEV: {
+ case OBD_IOC_CLEANUP: {
int rc;
/* has this minor been registered? */
goto cleanup_out;
/* cleanup has no argument */
- rc = obddev->obd_type->typ_ops->o_cleanup(obddev);
+ rc = OBP(obddev, cleanup)(obddev);
if ( rc )
return rc;
get_user(cli_id, (int *) arg);
- obddev->obd_type->typ_ops->o_disconnect(cli_id);
+ OBP(obddev, disconnect)(cli_id);
return 0;
- case OBD_IOC_SYNC:
+ case OBD_IOC_SYNC: {
/* sync doesn't need a connection ID, because it knows
* what device it was called on, and can thus get the
* superblock that it needs. */
}
return put_user(err, (int *) arg);
- case OBD_IOC_CREATE:
- /* similarly, create doesn't need a connection ID for
- * the same reasons. */
+ }
+ case OBD_IOC_CREATE: {
+ int err;
+ struct oic_create_s foo;
+
+ if ( copy_from_user(&foo, (const void *)arg, sizeof(foo)) )
+ return -EFAULT;
/* has this minor been registered? */
- if (!obddev->obd_type)
+ if ( !(obddev->obd_flags & OBD_ATTACHED) ||
+ !(obddev->obd_flags & OBD_SET_UP))
return -ENODEV;
return put_user(-EINVAL, (int *) arg);
}
- i_ino = obddev->obd_type->typ_ops->o_create(obddev, 0, &err);
+ i_ino = OBP(obddev, create)(foo.conn_id, foo.prealloc, &err);
if (err) {
CDEBUG(D_IOCTL, "create: obd_inode_new failure\n");
/* 0 is the only error value */
}
return put_user(i_ino, (int *) arg);
+ }
case OBD_IOC_DESTROY:
{
struct destroy_s {
case OBD_IOC_SETATTR:
{
int err;
- struct tmp {
- unsigned int conn_id;
- unsigned long ino;
- struct iattr iattr;
- } foo;
+ struct oic_attr_s foo;
struct inode holder;
+
/* has this minor been registered? */
if (!obddev->obd_type)
return -ENODEV;
- err= copy_from_user(&foo, (int *)arg, sizeof(struct tmp));
+ err= copy_from_user(&foo, (int *)arg, sizeof(foo));
if (err)
return err;
for (i = 0; i < MAX_OBD_DEVICES; i++) {
memset(&(obd_dev[i]), 0, sizeof(obd_dev[i]));
- INIT_LIST_HEAD(&obd_dev[i].u.sim.sim_clients);
+ INIT_LIST_HEAD(&obd_dev[i].obd_gen_clients);
}
obd_sysctl_init();
EXPORT_SYMBOL(obd_debug_level);
EXPORT_SYMBOL(obd_dev);
+EXPORT_SYMBOL(gen_connect);
+EXPORT_SYMBOL(gen_client);
+EXPORT_SYMBOL(gen_cleanup);
+EXPORT_SYMBOL(gen_disconnect);
+
+EXPORT_SYMBOL(gen_multi_attach);
+EXPORT_SYMBOL(gen_multi_setup);
+EXPORT_SYMBOL(gen_multi_cleanup);
+
+
#ifdef MODULE
int init_module(void)
{
struct obd_device *obddev = &obd_dev[i];
if ( obddev->obd_type &&
obddev->obd_type->typ_ops->o_cleanup_device )
- return obddev->obd_type->typ_ops->o_cleanup_device(i);
+ OBP(obddev, cleanup_device)(obddev);
}
obd_sysctl_clean();
--- /dev/null
+/*
+ * linux/fs/sim_obd/sim_obd.c
+ *
+ * These are the only exported functions; they provide the simulated object-
+ * oriented disk.
+ *
+ */
+
+#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 <linux/iobuf.h>
+#include <asm/bitops.h>
+#include <asm/byteorder.h>
+#include <linux/obd_support.h>
+#include <linux/obd_class.h>
+
+
+extern struct obd_device obd_dev[MAX_OBD_DEVICES];
+
+/* map connection to client */
+struct obd_client *gen_client(int cli_id)
+{
+ struct obd_device * obddev;
+ struct list_head * lh, * next;
+ struct obd_client * cli;
+ int a;
+
+ for (a = 0; a < MAX_OBD_DEVICES; a++) {
+ obddev = &obd_dev[a];
+
+ lh = next = &obddev->obd_gen_clients;
+ while ((lh = lh->next) != &obddev->obd_gen_clients) {
+ cli = list_entry(lh, struct obd_client, cli_chain);
+
+ if (cli->cli_id == cli_id)
+ return cli;
+ }
+ }
+
+ return NULL;
+} /* obd_client */
+
+
+
+/* a connection defines a context in which preallocation can be managed. */
+int gen_connect (struct obd_device *obddev,
+ struct obd_conn_info * conninfo)
+{
+ struct obd_client * cli;
+
+ OBD_ALLOC(cli, struct obd_client *, sizeof(struct obd_client));
+ if ( !cli ) {
+ printk("obd_connect (minor %d): no memory!\n",
+ obddev->obd_minor);
+ return -ENOMEM;
+ }
+
+ INIT_LIST_HEAD(&cli->cli_prealloc_inodes);
+ /* this should probably spinlocked? */
+ cli->cli_id = ++obddev->obd_gen_last_id;
+ cli->cli_prealloc_quota = 0;
+ cli->cli_obd = obddev;
+ list_add(&(cli->cli_chain), obddev->obd_gen_clients.prev);
+
+ CDEBUG(D_IOCTL, "connect: new ID %u\n", cli->cli_id);
+ conninfo->conn_id = cli->cli_id;
+ return 0;
+} /* gen_obd_connect */
+
+
+int gen_disconnect(unsigned int conn_id)
+{
+ struct obd_client * cli;
+
+ ENTRY;
+
+ if (!(cli = gen_client(conn_id))) {
+ CDEBUG(D_IOCTL, "disconnect: attempting to free "
+ "nonexistent client %u\n", conn_id);
+ return -EINVAL;
+ }
+
+ list_del(&(cli->cli_chain));
+ OBD_FREE(cli, sizeof(struct obd_client));
+
+ CDEBUG(D_IOCTL, "disconnect: ID %u\n", conn_id);
+
+ EXIT;
+ return 0;
+} /* gen_obd_disconnect */
+
+
+/*
+ * raid1 defines a number of connections to child devices,
+ * used to make calls to these devices.
+ * data holds nothing
+ */
+int gen_multi_setup(struct obd_device *obddev, int len, void *data)
+{
+ int i;
+ struct obd_device *rdev = obddev->obd_multi_dev[0];
+
+ for (i = 0 ; i < obddev->obd_multi_count ; i++ ) {
+ int rc;
+ struct obd_device *child = rdev + i;
+ rc = OBP(child, connect)(child, &rdev->obd_multi_conns[i]);
+
+ if ( rc != 0 ) {
+ /* XXX disconnect others */
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+int gen_multi_cleanup(struct obd_device * obddev)
+{
+ int i;
+ struct obd_device *rdev = obddev->obd_multi_dev[0];
+
+ for (i = 0 ; i < obddev->obd_multi_count ; i++ ) {
+ int rc;
+ struct obd_device *child = rdev + i;
+ rc = OBP(child, cleanup)(child);
+ *child = -1;
+
+ if ( rc != 0 ) {
+ /* XXX disconnect others */
+ return -EINVAL;
+ }
+ }
+ gen_cleanup(obddev);
+ return 0;
+} /* sim_cleanup_obddev */
+
+
+int gen_multi_attach(struct obd_device *obddev, int len, void *data)
+{
+ int i;
+ int count;
+ struct obd_device *rdev = obddev->obd_multi_dev[0];
+
+ count = len/sizeof(int);
+ obddev->obd_multi_count = count;
+ for (i=0 ; i<count ; i++) {
+ rdev = &obd_dev[*((int *)data + i)];
+ rdev = rdev + 1;
+ CDEBUG(D_IOCTL, "OBD RAID1: replicator %d is of type %s\n", i,
+ (rdev + i)->obd_type->typ_name);
+ }
+ return 0;
+}
+
+
+
+/*
+ * remove all connections to this device
+ * close all connections to lower devices
+ * needed for forced unloads of OBD client drivers
+ */
+int gen_multi_cleanup_device(struct obd_device *obddev)
+{
+ int i;
+ struct obd_device *rdev;
+
+ rdev = obddev->obd_multi_dev[0];
+ for (i = 0 ; i < obddev->obd_multi_count ; i++ ) {
+ int rc;
+ struct obd_device *child = rdev + i;
+ rc = OBP(child, disconnect)
+ (obddev->obd_multi_conns[i].conn_id);
+
+ if ( rc != 0 ) {
+ printk("OBD multi cleanup dev: disconnect failure %d\n", child->obd_minor);
+ }
+ *child = 0;
+ }
+ return 0;
+} /* gen_multi_cleanup_device */
+
+
+/*
+ * forced cleanup of the device:
+ * - remove connections from the device
+ * - cleanup the device afterwards
+ */
+int gen_cleanup(struct obd_device * obddev)
+{
+ struct list_head * lh, * tmp;
+ struct obd_client * cli;
+
+ ENTRY;
+
+ lh = tmp = &obddev->obd_gen_clients;
+ while ((tmp = tmp->next) != lh) {
+ cli = list_entry(tmp, struct obd_client, cli_chain);
+ CDEBUG(D_IOCTL, "Disconnecting obd_connection %d, at %p\n",
+ cli->cli_id, cli);
+ OBP(obddev, disconnect)(cli->cli_id);
+ }
+
+ return OBP(obddev, cleanup_device)(obddev);
+} /* sim_cleanup_device */
defined(&OBD_IOC_CREATE);
eval 'sub OBD_IOC_SETUP_OBDDEV () { &_IOC(1, ord(\'f\'), 4, 4);}' unless
defined(&OBD_IOC_SETUP_OBDDEV);
-eval 'sub OBD_IOC_CLEANUP_OBDDEV () { &_IOC(0, ord(\'f\'), 5, 0);}' unless
- defined(&OBD_IOC_CLEANUP_OBDDEV);
+eval 'sub OBD_IOC_CLEANUP () { &_IOC(0, ord(\'f\'), 5, 0);}' unless
+ defined(&OBD_IOC_CLEANUP);
eval 'sub OBD_IOC_DESTROY () { &_IOC(1, ord(\'f\'), 6, 4);}' unless
defined(&OBD_IOC_DESTROY);
eval 'sub OBD_IOC_PREALLOCATE () { &_IOC(3, ord(\'f\'), 7, 4);}' unless
use Term::ReadLine;
use IO::Handle;
-my ($device, $filesystem);
+
+my ($device, $filesystem, $file);
# startup options (I'll replace these when I have some to replace with)
-GetOptions("device=s" => \$device, "fs=s" => $filesystem) || die "Getoptions";
+GetOptions("f!" => \$file, "device=s" => \$device, "fs=s" => $filesystem) || die "Getoptions";
# genuine new simulated OBD device
-$device = "/dev/obd" unless $device;
+$device = "/dev/obd0" unless $device;
# object store in the ext2 formatted block device
$filesystem = "/dev/loop0" unless $filesystem;
-# get a console for the app
-my $term = new Term::ReadLine 'obdcontrol ';
-my $attribs = $term->Attribs;
-$term->ornaments('md,me,,'); # bold face prompt
-# make sure stdout is not buffered
-STDOUT->autoflush(1);
+
+# get a console for the app
my $line;
my $command;
#
my @jcm_cmd_list = keys %commands;
-$attribs->{attempted_completion_function} = \&completeme;
#------------------------------------------------------------------------------
# Open the device, as we need an FD for the ioctl
sysopen(DEV_OBD, $device, 0) || die "Cannot open $device";
die "Unable to stat $filesystem.\n";
}
-# Get on with the show
-process_line();
+my $term, $attribs;
+
+if ( $file ) {
+ while ( <STDIN> ) {
+ print $_;
+ execute_line($_);
+ }
+ exit 0;
+} else {
+ $term = new Term::ReadLine 'obdcontrol ';
+ $attribs = $term->Attribs;
+ $attribs->{attempted_completion_function} = \&completeme;
+ $term->ornaments('md,me,,'); # bold face prompt
+
+ # make sure stdout is not buffered
+ STDOUT->autoflush(1);
+
+ # Get on with the show
+ process_line();
+}
#------------------------------------------------------------------------------
sub completeme {
my @arg = split(' ', $line);
my $word = shift @arg;
- my $cmd = find_command($word);
+ my $cmd;
+ if ( $file ) {
+ $cmd = $word;
+ } else {
+ $cmd = find_command($word);
+ }
unless ($cmd) {
printf STDERR "$word: No such command, or not unique.\n";
return (-1);
print STDERR "ioctl failed: $!\n";
} elsif ($rc eq "0 but true") {
print "Finished (success)\n";
+ $::client_id = 0;
} else {
print "ioctl returned error code $rc.\n";
}
my $arg = shift;
my $quiet = shift;
my $rc;
+ my $prealloc = 0;
if (defined($quiet) && !($quiet eq "quiet")) {
print "syntax: create [number of objects [quiet]]\n";
return;
}
- my $packed = pack("I", $::client_id);
+ my $packed = pack("IL", $::client_id, $prealloc);
if (!defined($arg) || scalar($arg) < 2) {
print "Creating 1 object...\n";
- my $packed = pack("I", 0);
$rc = ioctl(DEV_OBD, &OBD_IOC_CREATE, $packed);
if (!defined($quiet)) {
my $ino = unpack("L", $packed);
--- /dev/null
+#! /bin/bash
+
+insmod loop
+losetup /dev/loop0 /tmp/fs
+insmod obdclass.o
+insmod obdsim.o
+insmod ../obdfs/obdfs.o
+./obdcontrol -f << EOF
+attach sim_obd
+setup
+quit
+EOF
+mount -t obdfs /dev/loop0 /mnt/obd
{
return -EISDIR;
}
+#endif
-
-int ext2_check_dir_entry (const char * function, struct inode * dir,
+int obdfs_check_dir_entry (const char * function, struct inode * dir,
struct ext2_dir_entry_2 * de,
- struct buffer_head * bh,
+ struct page * page,
unsigned long offset)
{
const char * error_msg = NULL;
+ ENTRY;
+ if ( !de ) {
+ error_msg = "null de passed";
+ return 1;
+ }
+
if (le16_to_cpu(de->rec_len) < EXT2_DIR_REC_LEN(1))
error_msg = "rec_len is smaller than minimal";
else if (le16_to_cpu(de->rec_len) % 4 != 0)
error_msg = "rec_len % 4 != 0";
else if (le16_to_cpu(de->rec_len) < EXT2_DIR_REC_LEN(de->name_len))
error_msg = "rec_len is too small for name_len";
- else if (dir && ((char *) de - bh->b_data) + le16_to_cpu(de->rec_len) >
+ else if (dir && ((char *) de - (char *)page_address(page)) + le16_to_cpu(de->rec_len) >
dir->i_sb->s_blocksize)
error_msg = "directory entry across blocks";
- else if (dir && le32_to_cpu(de->inode) > le32_to_cpu(dir->i_sb->u.ext2_sb.s_es->s_inodes_count))
- error_msg = "inode out of bounds";
+#if 0 /* this one doesn't yet work for OBDFS */
+ else
+if (dir && le32_to_cpu(de->inode) > le32_to_cpu(dir->i_sb->u.ext2_sb.s_es->s_inodes_count))
+ error_msg = "inode out of bounds";
+#endif
if (error_msg != NULL)
ext2_error (dir->i_sb, function, "bad entry in directory #%lu: %s - "
"offset=%lu, inode=%lu, rec_len=%d, name_len=%d",
dir->i_ino, error_msg, offset,
(unsigned long) le32_to_cpu(de->inode),
le16_to_cpu(de->rec_len), de->name_len);
+ EXIT;
return error_msg == NULL ? 1 : 0;
}
-#endif
int obdfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
{
while (!error && !stored && filp->f_pos < inode->i_size) {
page = obdfs_getpage(inode, offset, 0, NOLOCK);
+ PDEBUG(page, "readdir");
if (!page) {
ext2_error (sb, "ext2_readdir",
"directory #%lu contains a hole at offset %lu",
ssize_t obdfs_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
{
ssize_t retval;
- CDEBUG(D_INODE, "Writing %d bytes, offset %ld\n", count, (long)*ppos);
+ CDEBUG(D_INODE, "Writing inode %ld, %d bytes, offset %ld\n", file->f_dentry->d_inode->i_ino, count, (long)*ppos);
retval = generic_file_write(file, buf, count,
ppos, obdfs_write_one_page);
inode->i_ctime = inode->i_mtime = CURRENT_TIME;
mark_inode_dirty(inode);
}
+ EXIT;
return retval;
}
*/
struct page * obdfs_find_entry (struct inode * dir,
const char * const name, int namelen,
- struct ext2_dir_entry_2 ** res_dir)
+ struct ext2_dir_entry_2 ** res_dir, int lock)
{
struct super_block * sb;
unsigned long offset;
struct page * page;
+ ENTRY;
*res_dir = NULL;
sb = dir->i_sb;
struct ext2_dir_entry_2 * de;
char * dlimit;
- page = obdfs_getpage(dir, offset, 0, NOLOCK);
+ page = obdfs_getpage(dir, offset, 0, lock);
if ( !page )
return NULL;
ext2_match (namelen, name, de)) {
/* found a match -
just to be sure, do a full check */
-#if 0
- if (!ext2_check_dir_entry("ext2_find_entry",
- dir, de, bh, offset))
+ if (!obdfs_check_dir_entry("ext2_find_entry",
+ dir, de, page, offset))
goto failure;
-#endif
*res_dir = de;
+ EXIT;
return page;
}
/* prevent looping on a bad block */
failure:
page_cache_release(page);
+ EXIT;
return NULL;
}
struct inode * inode;
struct ext2_dir_entry_2 * de;
struct page * page;
+ ENTRY;
if (dentry->d_name.len > EXT2_NAME_LEN)
return ERR_PTR(-ENAMETOOLONG);
- page = obdfs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de);
+ page = obdfs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, NOLOCK);
inode = NULL;
+ if ( !page )
+ CDEBUG(D_INODE, "No page - negative entry.\n");
+ if ( page && !de ) {
+ CDEBUG(D_INODE, "Danger: PAGE but de.\n");
+ return ERR_PTR(-ENOENT);
+ }
if (page) {
unsigned long ino = le32_to_cpu(de->inode);
page_cache_release(page);
inode = iget(dir->i_sb, ino);
- if (!inode)
+ if (!inode) {
+ CDEBUG(D_INODE, "No inode.\n");
+ EXIT;
return ERR_PTR(-EACCES);
+ }
}
d_add(dentry, inode);
+ EXIT;
return NULL;
}
struct ext2_dir_entry_2 * de, * de1;
struct super_block * sb;
+ ENTRY;
*err = -EINVAL;
*res_dir = NULL;
if (!dir || !dir->i_nlink)
return NULL;
}
page = obdfs_getpage(dir, 0, 0, LOCKED);
- if (!page)
+ if (!page) {
+ EXIT;
return NULL;
+ }
rec_len = EXT2_DIR_REC_LEN(namelen);
offset = 0;
de = (struct ext2_dir_entry_2 *) page_address(page);
UnlockPage(page);
page_cache_release(page);
page = obdfs_getpage(dir, offset, 1, LOCKED);
- if (page)
+ if (!page)
return NULL;
if (dir->i_size <= offset) {
if (dir->i_size == 0) {
de = (struct ext2_dir_entry_2 *) page_address(page);
de->inode = 0;
- de->rec_len = le16_to_cpu(sb->s_blocksize);
+ de->rec_len = le16_to_cpu(PAGE_SIZE);
dir->i_size = offset + PAGE_SIZE;
dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
mark_inode_dirty(dir);
de = (struct ext2_dir_entry_2 *) page_address(page);
}
}
-#if 0
- if (!ext2_check_dir_entry ("ext2_add_entry", dir, de, bh,
+ CDEBUG(D_INODE, "\n");
+ if (!obdfs_check_dir_entry ("ext2_add_entry", dir, de, page,
offset)) {
*err = -ENOENT;
- brelse (bh);
+ page_cache_release(page);
+ EXIT;
return NULL;
}
-#endif
+ CDEBUG(D_INODE, "\n");
if (ext2_match (namelen, name, de)) {
*err = -EEXIST;
UnlockPage(page);
page_cache_release(page);
+ EXIT;
return NULL;
}
+ CDEBUG(D_INODE, "\n");
if ((le32_to_cpu(de->inode) == 0 && le16_to_cpu(de->rec_len) >= rec_len) ||
(le16_to_cpu(de->rec_len) >= EXT2_DIR_REC_LEN(de->name_len) + rec_len)) {
offset += le16_to_cpu(de->rec_len);
de->rec_len = cpu_to_le16(EXT2_DIR_REC_LEN(de->name_len));
de = de1;
}
+ CDEBUG(D_INODE, "\n");
de->inode = 0;
de->name_len = namelen;
de->file_type = 0;
memcpy (de->name, name, namelen);
+ CDEBUG(D_INODE, "\n");
/*
* XXX shouldn't update any times until successful
* completion of syscall, but too many callers depend
*res_dir = de;
*err = 0;
PDEBUG(page, "addentry");
+ EXIT;
return page;
}
+ CDEBUG(D_INODE, "\n");
offset += le16_to_cpu(de->rec_len);
de = (struct ext2_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len));
}
+ CDEBUG(D_INODE, "\n");
UnlockPage(page);
page_cache_release(page);
pde = NULL;
de = (struct ext2_dir_entry_2 *) page_address(page);
while (i < PAGE_SIZE) {
-#if 0
- if (!ext2_check_dir_entry ("ext2_delete_entry", NULL,
- de, bh, i))
+ if (!obdfs_check_dir_entry ("ext2_delete_entry", NULL,
+ de, page, i))
return -EIO;
-#endif
if (de == dir) {
if (pde)
pde->rec_len =
/*
* N.B. Several error exits in ext2_new_inode don't set err.
*/
- ino = sbi->osi_ops->o_create(sbi->osi_obd, 0, &err);
+ ino = sbi->osi_ops->o_create(sbi->osi_conn_info.conn_id, 0, &err);
if ( ino == -1 )
return -1;
inode = iget(dir->i_sb, ino);
- if (!inode)
+ if (!inode) {
+ CDEBUG(D_INODE, "No inode, ino %ld\n", ino);
return err;
+ }
inode->i_op = &obdfs_inode_ops;
inode->i_mode = mode;
inode->i_nlink--;
mark_inode_dirty(inode);
iput (inode);
+ EXIT;
return err;
}
de->inode = cpu_to_le32(inode->i_ino);
#endif
page_cache_release(page);
d_instantiate(dentry, inode);
+ EXIT;
return 0;
}
/*
* N.B. Several error exits in ext2_new_inode don't set err.
*/
- ino = sbi->osi_ops->o_create(sbi->osi_obd, 0, &err);
+ ino = sbi->osi_ops->o_create(sbi->osi_conn_info.conn_id, 0, &err);
if ( ino == -1 )
return -1;
inode = iget(dir->i_sb, ino);
goto out;
err = -EIO;
- ino = iops(dir)->o_create(sbi->osi_obd, 0, &err);
+ ino = iops(dir)->o_create(sbi->osi_conn_info.conn_id, 0, &err);
if ( ino == -1 )
return -1;
child = iget(dir->i_sb, ino);
de = (struct ext2_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len));
de->inode = cpu_to_le32(dir->i_ino);
- de->rec_len = cpu_to_le16(child->i_sb->s_blocksize - EXT2_DIR_REC_LEN(1));
+ de->rec_len = cpu_to_le16(PAGE_SIZE - EXT2_DIR_REC_LEN(1));
de->name_len = 2;
strcpy (de->name, "..");
ext2_set_de_type(dir->i_sb, de, S_IFDIR);
child->i_nlink = 0;
mark_inode_dirty(child);
iput (child);
+ EXIT;
goto out;
}
}
de = (struct ext2_dir_entry_2 *) page_address(page);
}
-#if 0
- if (!ext2_check_dir_entry ("empty_dir", inode, de, bh,
+ if (!obdfs_check_dir_entry ("empty_dir", inode, de, page,
offset)) {
- brelse (bh);
+ page_cache_release(page);
return 1;
}
-#endif
if (le32_to_cpu(de->inode)) {
page_cache_release(page);
return 0;
sbi = dir->i_sb->u.generic_sbp;
retval = -ENOENT;
- page = obdfs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de);
+ page = obdfs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, LOCKED);
if (!page)
goto end_rmdir;
end_rmdir:
if ( page )
page_cache_release(page);
+ EXIT;
return retval;
}
sbi = dir->i_sb->u.generic_sbp;
retval = -ENOENT;
- page = obdfs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de);
+ page = obdfs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, LOCKED);
if (!page)
goto end_unlink;
end_unlink:
if (page)
page_cache_release(page);
+ EXIT;
return retval;
}
/*
* N.B. Several error exits in ext2_new_inode don't set err.
*/
- ino = sbi->osi_ops->o_create(sbi->osi_obd, 0, &err);
+ ino = sbi->osi_ops->o_create(sbi->osi_conn_info.conn_id, 0, &err);
if ( ino == -1 )
return -1;
inode = iget(dir->i_sb, ino);
* higher-level routines.
*/
int obdfs_rename (struct inode * old_dir, struct dentry *old_dentry,
- struct inode * new_dir,struct dentry *new_dentry)
+ struct inode * new_dir, struct dentry *new_dentry)
{
struct inode * old_inode, * new_inode;
struct page * old_page, * new_page, * dir_page;
new_page = dir_page = NULL;
- old_page = obdfs_find_entry (old_dir, old_dentry->d_name.name, old_dentry->d_name.len, &old_de);
+ /* does the old entry exist? - if not get out */
+ old_page = obdfs_find_entry (old_dir, old_dentry->d_name.name, old_dentry->d_name.len, &old_de, NOLOCK);
+ PDEBUG(old_page, "rename - old page");
/*
* Check for inode number is _not_ due to possible IO errors.
* We might rmdir the source, keep it as pwd of some process
if (!old_page || le32_to_cpu(old_de->inode) != old_inode->i_ino)
goto end_rename;
+ /* find new inode */
new_inode = new_dentry->d_inode;
new_page = obdfs_find_entry (new_dir, new_dentry->d_name.name,
- new_dentry->d_name.len, &new_de);
+ new_dentry->d_name.len, &new_de, NOLOCK);
+ PDEBUG(new_page, "rename - new page ");
if (new_page) {
if (!new_inode) {
page_cache_release(new_page);
DQUOT_INIT(new_inode);
}
}
+ /* in this case we to check more ... */
if (S_ISDIR(old_inode->i_mode)) {
+ /* can only rename into empty new directory */
if (new_inode) {
retval = -ENOTEMPTY;
if (!empty_dir (new_inode))
}
retval = -EIO;
dir_page= obdfs_getpage (old_inode, 0, 0, LOCKED);
+ PDEBUG(dir_page, "rename dir page");
+
if (!dir_page)
goto end_rename;
if (le32_to_cpu(PARENT_INO(page_address(dir_page))) != old_dir->i_ino)
new_dir->i_nlink >= EXT2_LINK_MAX)
goto end_rename;
}
+ /* create the target dir entry */
if (!new_page) {
new_page = obdfs_add_entry (new_dir, new_dentry->d_name.name,
new_dentry->d_name.len, &new_de,
&retval);
+ PDEBUG(new_page, "rename new page");
if (!new_page)
goto end_rename;
}
new_dir->i_version = ++event;
/*
- * ok, that's it
+ * remove the old entry
*/
new_de->inode = le32_to_cpu(old_inode->i_ino);
if (EXT2_HAS_INCOMPAT_FEATURE(new_dir->i_sb,
if (dir_page) {
PARENT_INO(page_address(dir_page)) = le32_to_cpu(new_dir->i_ino);
sbi->osi_ops->o_brw(WRITE, sbi->osi_conn_info.conn_id,
- new_dir->i_ino, dir_page, 0);
+ old_inode->i_ino, dir_page, 0);
old_dir->i_nlink--;
mark_inode_dirty(old_dir);
if (new_inode) {
mark_inode_dirty(new_dir);
}
}
- sbi->osi_ops->o_brw(WRITE, sbi->osi_conn_info.conn_id,
- old_inode->i_ino, old_page, 0);
+ if ( old_page != new_page ) {
+ unsigned long offset = old_page->offset;
+ /* lock the old_page and release unlocked copy */
+ CDEBUG(D_INODE, "old_page at %p\n", old_page);
+ page_cache_release(old_page);
+ old_page = obdfs_getpage(old_dir, offset, 0, LOCKED);
+ CDEBUG(D_INODE, "old_page at %p\n", old_page);
+ sbi->osi_ops->o_brw(WRITE, sbi->osi_conn_info.conn_id,
+ old_dir->i_ino, old_page, 0);
+ }
#if 0
if (IS_SYNC(old_dir)) {
ll_rw_block (WRITE, 1, &old_bh);
}
#endif
sbi->osi_ops->o_brw(WRITE, sbi->osi_conn_info.conn_id,
- new_inode->i_ino, new_page, 0);
+ new_dir->i_ino, new_page, 0);
#if 0
if (IS_SYNC(new_dir)) {
ll_rw_block (WRITE, 1, &new_bh);
retval = 0;
end_rename:
+ if (old_page && PageLocked(old_page) )
+ UnlockPage(old_page);
if (old_page)
page_cache_release(old_page);
+ if (new_page && PageLocked(new_page) )
+ UnlockPage(new_page);
if (new_page)
page_cache_release(new_page);
+ if (dir_page && PageLocked(dir_page) )
+ UnlockPage(dir_page);
if (dir_page)
page_cache_release(dir_page);
+
+
return retval;
}
long status;
struct obdfs_sb_info *sbi = file->f_dentry->d_inode->i_sb->u.generic_sbp;
+ ENTRY;
if ( !Page_Uptodate(page) ) {
status = sbi->osi_ops->o_brw(READ,
sbi->osi_conn_info.conn_id,
status = obdfs_writepage(file, page);
unlock_kernel();
}
+ EXIT;
if ( status != PAGE_SIZE )
return status;
else
PDEBUG(page,"GETPAGE");
if (!locked)
UnlockPage(page);
+ EXIT;
return page;
}
CDEBUG(D_INODE, "Page found but not up to date\n");
}
- /* page_cache_alloc returns address of page */
+ /* page_cache_alloc returns the VM address of page */
new_page = page_cache_alloc();
if (!new_page)
return NULL;
/* corresponding struct page in the mmap */
hash = page_hash(inode, offset);
page = page_cache_entry(new_page);
- PDEBUG(page, "GETPAGE");
if (!add_to_page_cache_unique(page, inode, offset, hash)) {
CDEBUG(D_INODE, "Page not found. Reading it.\n");
- PDEBUG(page,"GETPAGE");
+ PDEBUG(page,"GETPAGE - before reading");
sbi->osi_ops->o_brw(READ, sbi->osi_conn_info.conn_id,
inode->i_ino, page, create);
if ( !locked )
UnlockPage(page);
SetPageUptodate(page);
- PDEBUG(page,"GETPAGE");
+ PDEBUG(page,"GETPAGE - after reading");
+ EXIT;
return page;
}
/*
*/
CDEBUG(D_INODE, "Page not found. Someone raced us.\n");
PDEBUG(page,"GETPAGE");
+ EXIT;
return page;
}
{
struct inode *root = 0;
struct obdfs_sb_info *sbi = NULL;
+ struct obd_device *obddev;
int error = 0;
unsigned long blocksize;
unsigned long blocksize_bits;
MOD_DEC_USE_COUNT;
return NULL;
}
+
+ obddev = &obd_dev[obd_minor];
+
+ if ( ! (obddev->obd_flags & OBD_ATTACHED) ||
+ ! (obddev->obd_flags & OBD_SET_UP) )
+ return NULL;
- sbi->osi_obd = &obd_dev[obd_minor];
+ sbi->osi_obd = obddev;
sbi->osi_ops = sbi->osi_obd->obd_type->typ_ops;
error = sbi->osi_ops->o_connect(sbi->osi_obd, &sbi->osi_conn_info);
--- /dev/null
+--- linux/kernel/ksyms.c.or Tue Oct 12 10:40:21 1999
++++ linux/kernel/ksyms.c Tue Oct 12 11:22:45 1999
+@@ -36,6 +36,7 @@
+ #include <linux/swap.h>
+ #include <linux/ctype.h>
+ #include <linux/file.h>
++#include <linux/iobuf.h>
+ #include <linux/console.h>
+ #include <linux/poll.h>
+ #include <linux/mm.h>
+@@ -118,6 +119,8 @@
+ EXPORT_SYMBOL(update_atime);
+ EXPORT_SYMBOL(get_super);
+ EXPORT_SYMBOL(get_fs_type);
++EXPORT_SYMBOL(get_empty_super);
++EXPORT_SYMBOL(remove_vfsmnt);
+ EXPORT_SYMBOL(getname);
+ EXPORT_SYMBOL(_fput);
+ EXPORT_SYMBOL(igrab);
+@@ -140,6 +143,9 @@
+ EXPORT_SYMBOL(d_path);
+ EXPORT_SYMBOL(__mark_buffer_dirty);
+ EXPORT_SYMBOL(__mark_inode_dirty);
++EXPORT_SYMBOL(free_kiovec);
++EXPORT_SYMBOL(brw_kiovec);
++EXPORT_SYMBOL(alloc_kiovec);
+ EXPORT_SYMBOL(get_empty_filp);
+ EXPORT_SYMBOL(init_private_file);
+ EXPORT_SYMBOL(filp_open);
+--- linux/fs/super.c.or Tue Oct 12 10:39:05 1999
++++ linux/fs/super.c Tue Oct 12 11:18:14 1999
+@@ -135,7 +135,7 @@
+ return lptr;
+ }
+
+-static void remove_vfsmnt(kdev_t dev)
++void remove_vfsmnt(kdev_t dev)
+ {
+ struct vfsmount *lptr, *tofree;
+
+@@ -508,7 +508,7 @@
+ /*
+ * Find a super_block with no device assigned.
+ */
+-static struct super_block *get_empty_super(void)
++struct super_block *get_empty_super(void)
+ {
+ struct super_block *s;
+
+--- linux/include/linux/fs.h.or Tue Oct 12 10:39:59 1999
++++ linux/include/linux/fs.h Tue Oct 12 11:32:46 1999
+@@ -934,6 +934,8 @@
+
+
+ extern struct super_block *get_super(kdev_t);
++struct super_block *get_empty_super(void);
++void remove_vfsmnt(kdev_t dev);
+ extern void put_super(kdev_t);
+ unsigned long generate_cluster(kdev_t, int b[], int);
+ unsigned long generate_cluster_swab32(kdev_t, int b[], int);