struct obd_conn_info {
unsigned int conn_id; /* handle */
- unsigned long conn_ino; /* root inode number */
- /* XXX do we really need this */
- unsigned long conn_blocksize;
- unsigned char conn_blocksize_bits;
};
struct obd_type {
int typ_refcnt;
};
+#define OBD_ATTACHED 0x1
+#define OBD_SET_UP 0x2
+
/* corresponds to one of the obdx */
struct obd_device {
struct obd_type *obd_type;
+ int obd_minor;
+ int obd_flags;
int obd_refcnt;
union {
struct sim_obd sim;
} u;
};
-#define OBD_FL_SETUP 0x1
-
struct obd_ops {
- int (*o_format)(void);
- int (*o_partition)(int partition, unsigned int size);
- int (*o_connect)(int minor, struct obd_conn_info *info);
+ int (*o_attach)(struct obd_device *, int len, void *);
+ int (*o_format)(struct obd_device *, int len, void *);
+ int (*o_partition)(struct obd_device *, int len, void *);
+ int (*o_connect)(struct obd_device *, struct obd_conn_info *info);
int (*o_disconnect)(unsigned int conn_id);
- int (*o_setup) (struct obd_device *dev, void *data);
+ int (*o_setup) (struct obd_device *dev, int len, void *data);
int (*o_cleanup)(struct obd_device *dev);
- int (*o_setattr)(unsigned int conn_id, unsigned long id, struct iattr *iattr);
- int (*o_getattr)(unsigned int conn_id, unsigned long id, struct iattr *iattr);
+ 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_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 (*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_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);
};
int obd_register_type(struct obd_ops *ops, char *nm);
-
+int obd_unregister_type(char *nm);
struct obd_client {
struct list_head cli_chain;
- kdev_t minor;
+ struct obd_device *cli_obd;
unsigned int cli_id;
unsigned long cli_prealloc_quota;
struct list_head cli_prealloc_inodes;
/*
* ioctl commands
*/
+struct oic_attach {
+ int att_typelen;
+ void *att_type;
+ int att_datalen;
+ void *att_data;
+};
+
struct oic_prealloc_s {
unsigned long cli_id;
unsigned long alloc; /* user sets it to the number of inodes requesting
#define OBD_IOC_STATFS _IOWR('f', 15, long)
#define OBD_IOC_SYNC _IOR ('f', 16, long)
#define OBD_IOC_READ2 _IOWR('f', 17, long)
-#define OBD_IOC_FORMAT _IO('f', 17, long)
-#define OBD_IOC_READ2 _IOWR('f', 17, long)
+#define OBD_IOC_FORMAT _IOWR('f', 18, long)
+#define OBD_IOC_PARTITION _IOWR('f', 19, long)
+#define OBD_IOC_ATTACH _IOWR('f', 20, long)
#define OBD_IOC_DEC_FS_USE_COUNT _IO ('f', 32 )
#endif /* SIM_OBD_DEBUG */
+
+#define CMD(cmd) (( cmd == READ ) ? "read" : "write")
+
#define PDEBUG(page,cmd) {\
- char *command = ( cmd == READ ) ? "read" : "write";\
char *uptodate = (Page_Uptodate(page)) ? "yes" : "no";\
char *locked = (PageLocked(page)) ? "yes" : "no";\
int count = page->count.counter;\
long ino = (page->inode) ? page->inode->i_ino : -1;\
+ long offset = page->offset / PAGE_SIZE;\
\
- CDEBUG(D_IOCTL, " ** %s, cmd: %s, ino: %ld, uptodate: %s, "\
+ CDEBUG(D_IOCTL, " ** %s, cmd: %s, ino: %ld, off %ld, uptodate: %s, "\
"locked: %s, cnt %d ** \n", __FUNCTION__,\
- command, ino, uptodate, locked, count);\
+ cmd, ino, offset, uptodate, locked, count);\
}
} \
} while (0)
+
+
+static inline void inode_to_iattr(struct inode *inode, struct iattr *tmp)
+{
+ tmp->ia_mode = inode->i_mode;
+ tmp->ia_uid = inode->i_uid;
+ tmp->ia_gid = inode->i_gid;
+ tmp->ia_size = inode->i_size;
+ tmp->ia_atime = inode->i_atime;
+ tmp->ia_mtime = inode->i_mtime;
+ tmp->ia_ctime = inode->i_ctime;
+ tmp->ia_attr_flags = inode->i_flags;
+
+ tmp->ia_valid = ~0;
+}
+
+static inline void inode_cpy(struct inode *dest, struct inode *src)
+{
+ dest->i_mode = src->i_mode;
+ dest->i_uid = src->i_uid;
+ dest->i_gid = src->i_gid;
+ dest->i_size = src->i_size;
+ dest->i_atime = src->i_atime;
+ dest->i_mtime = src->i_mtime;
+ dest->i_ctime = src->i_ctime;
+ dest->i_attr_flags = src->i_flags;
+ /* allocation of space */
+ dest->i_blocks = src->i_blocks;
+
+ memcpy(&dest->u, &src->u, sizeof(src->u));
+}
+
+
+
+
+
+
+
+
+
+
#endif
/* rw.c */
-struct page *obdfs_getpage(struct inode *inode, unsigned long offset);
+struct page *obdfs_getpage(struct inode *inode, unsigned long offset, int create, int locked);
int obdfs_writepage(struct file *file, struct page *page);
int obdfs_write_one_page(struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char * buf);
/* namei.c */
struct dentry *obdfs_lookup(struct inode * dir, struct dentry *dentry);
-
+int obdfs_create (struct inode * dir, struct dentry * dentry, int mode);
+int obdfs_mkdir(struct inode *dir, struct dentry *dentry, int mode);
+int obdfs_rmdir(struct inode *dir, struct dentry *dentry);
+int obdfs_unlink(struct inode *dir, struct dentry *dentry);
+int obdfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rdev);
+int obdfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname);
+int obdfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry);
+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);
struct obdfs_inode_info;
-extern struct file_operations obdfs_file_operations;
-extern struct inode_perations obdfs_inode_operations;
+extern struct file_operations obdfs_file_ops;
+extern struct inode_operations obdfs_inode_ops;
+
+static inline struct obd_ops *iops(struct inode *i)
+{
+ struct obdfs_sb_info *sbi = (struct obdfs_sb_info *) i->i_sb->u.generic_sbp;
+ return sbi->osi_ops;
+}
+
+#define NOLOCK 0
+#define LOCKED 1
#define OBDFS_SUPER_MAGIC 0x4711
return NULL;
}
+
+static int getdata(int len, void **data)
+{
+ void *tmp = NULL;
+
+ if (!len)
+ return 0;
+
+ OBD_ALLOC(tmp, void *, len);
+ if ( !tmp )
+ return -ENOMEM;
+
+ memset(tmp, 0, len);
+ if ( copy_from_user(tmp, *data, len)) {
+ OBD_FREE(tmp,len);
+ return -EFAULT;
+ }
+ *data = tmp;
+
+ return 0;
+}
+
/* to control /dev/obdNNN */
static int obd_class_ioctl (struct inode * inode, struct file * filp,
unsigned int cmd, unsigned long arg)
long int cli_id; /* connect, disconnect */
struct oic_prealloc_s prealloc; /* preallocate */
+
if (!inode)
return -EINVAL;
+
dev = MINOR(inode->i_rdev);
if (dev > MAX_OBD_DEVICES)
return -ENODEV;
-
obddev = &obd_dev[dev];
- /* has this minor been registered? */
- if (cmd != OBD_IOC_SETUP_OBDDEV && !obd_dev[dev].obd_type)
- return -ENODEV;
-
switch (cmd) {
- case OBD_IOC_SETUP_OBDDEV: {
+ case OBD_IOC_ATTACH: {
struct obd_type *type;
+ struct oic_attach input;
- struct setup {
- int setup_data;
- char setup_type[24];
- } input;
-
- if ( obddev->obd_type ) {
- CDEBUG(D_IOCTL, "Device %d already setup (type %s)\n",
- dev, obddev->obd_type->typ_name);
- return -1;
+ /* have we attached a type to this device */
+ if ( obddev->obd_type || (obddev->obd_flags & OBD_ATTACHED) ){
+ CDEBUG(D_IOCTL, "OBD Device %d already attached to type %s.\n", dev, obddev->obd_type->typ_name);
+ return -EINVAL;
}
/* get data structures */
- err= copy_from_user(&input, (void *) arg, sizeof(input));
+ err = copy_from_user(&input, (void *) arg, sizeof(input));
if (err)
return err;
- type = obd_nm_to_type(input.setup_type);
+ if ( (err = getdata(input.att_typelen + 1, &input.att_type)) )
+ return err;
+
+ /* find the type */
+ err = -EINVAL;
+ type = obd_nm_to_type(input.att_type);
+ OBD_FREE(input.att_type, input.att_typelen + 1);
if ( !type ) {
- printk("Trying to register non existent type %s\n",
- input.setup_type);
- return -1;
+ printk("Unknown obd type dev %d\n", dev);
+ return err;
}
obddev->obd_type = type;
+
+ /* get the attach data */
+ if ( (err = getdata(input.att_datalen, &input.att_data)) ) {
+ return err;
+ }
+
+ 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 ) {
+ obddev->obd_flags |= OBD_ATTACHED;
+ type->typ_refcnt++;
+ MOD_INC_USE_COUNT;
+ return 0;
+ }
- CDEBUG(D_IOCTL, "Setup %d, type %s\n", dev, input.setup_type);
- if ( obddev->obd_type->typ_ops->o_setup(obddev,
- &input.setup_data)){
+ /* do the attach */
+ err = obddev->obd_type->typ_ops->o_attach
+ (obddev, input.att_datalen, &input.att_data);
+ OBD_FREE(input.att_data, input.att_datalen);
+
+ if ( err ) {
+ obddev->obd_flags &= ~OBD_ATTACHED;
obddev->obd_type = NULL;
- return -1;
} else {
+ obddev->obd_flags |= OBD_ATTACHED;
type->typ_refcnt++;
MOD_INC_USE_COUNT;
- return 0;
}
+ return err;
+ }
+ case OBD_IOC_FORMAT: {
+ struct ioc_format {
+ int format_datalen;
+ void *format_data;
+ } input;
+
+ /* have we attached a type to this device */
+ if ( !obddev->obd_type ) {
+ CDEBUG(D_IOCTL, "OBD Device %d has no type.\n", dev);
+ return -EINVAL;
+ }
+
+ /* get main structure */
+ err = copy_from_user(&input, (void *) arg, sizeof(input));
+ if (err)
+ return err;
+
+ err = getdata(input.format_datalen, &input.format_data);
+ if (err)
+ return err;
+
+ if (!obddev->obd_type->typ_ops ||
+ !obddev->obd_type->typ_ops->o_format )
+ return -EOPNOTSUPP;
+
+ /* do the format */
+ CDEBUG(D_IOCTL, "Format %d, type %s\n", dev,
+ obddev->obd_type->typ_name);
+ err = obddev->obd_type->typ_ops->o_format
+ (obddev, input.format_datalen, input.format_data);
+
+ OBD_FREE(input.format_data, input.format_datalen);
+ return err;
+ }
+ case OBD_IOC_PARTITION: {
+ struct ioc_part {
+ int part_datalen;
+ void *part_data;
+ } input;
+
+ /* have we attached a type to this device */
+ if ( !obddev->obd_type ) {
+ CDEBUG(D_IOCTL, "OBD Device %d has no type.\n", dev);
+ return -EINVAL;
+ }
+
+ /* get main structure */
+ err = copy_from_user(&input, (void *) arg, sizeof(input));
+ if (err)
+ return err;
+
+ err = getdata(input.part_datalen, &input.part_data);
+ if (err)
+ return err;
+
+ if (!obddev->obd_type->typ_ops ||
+ !obddev->obd_type->typ_ops->o_partition )
+ return -EOPNOTSUPP;
+
+ /* do the partition */
+ CDEBUG(D_IOCTL, "Partition %d, type %s\n", dev,
+ obddev->obd_type->typ_name);
+ err = obddev->obd_type->typ_ops->o_partition
+ (obddev, input.part_datalen, input.part_data);
+
+ OBD_FREE(input.part_data, input.part_datalen);
+ return err;
+ }
+ case OBD_IOC_SETUP_OBDDEV: {
+ struct ioc_setup {
+ int setup_datalen;
+ void *setup_data;
+ } input;
+
+ /* have we attached a type to this device */
+ if (!(obddev->obd_flags & OBD_ATTACHED)) {
+ CDEBUG(D_IOCTL, "OBD Device %d has no type.\n", dev);
+ return -EINVAL;
+ }
+
+ /* has this been done already? */
+ if ( obddev->obd_flags & OBD_SET_UP ) {
+ CDEBUG(D_IOCTL, "Device %d already setup (type %s)\n",
+ dev, obddev->obd_type->typ_name);
+ return -EINVAL;
+ }
+
+ /* get main structure */
+ err = copy_from_user(&input, (void *) arg, sizeof(input));
+ if (err)
+ return err;
+
+ err = getdata(input.setup_datalen, &input.setup_data);
+ if (err)
+ return err;
+
+ /* do the setup */
+ 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;
+
+ err = obddev->obd_type->typ_ops->o_setup
+ (obddev, input.setup_datalen, input.setup_data);
+
+ if ( err )
+ obddev->obd_flags &= ~OBD_SET_UP;
+ else
+ obddev->obd_flags |= OBD_SET_UP;
+ return err;
}
case OBD_IOC_CLEANUP_OBDDEV: {
int rc;
+ /* has this minor been registered? */
+ if (!obddev->obd_type)
+ return -ENODEV;
+
if ( !obddev->obd_type->typ_refcnt )
printk("OBD_CLEANUP: refcount wrap!\n");
if ( !obddev->obd_type->typ_ops->o_cleanup )
- goto out;
+ goto cleanup_out;
/* cleanup has no argument */
rc = obddev->obd_type->typ_ops->o_cleanup(obddev);
if ( rc )
return rc;
- out:
+ cleanup_out:
+ obddev->obd_flags = 0;
obddev->obd_type->typ_refcnt--;
obddev->obd_type = NULL;
MOD_DEC_USE_COUNT;
{
struct obd_conn_info conninfo;
- if (obddev->obd_type->typ_ops->o_connect(dev, &conninfo))
+ if ( (!(obddev->obd_flags & OBD_SET_UP)) ||
+ (!(obddev->obd_flags & OBD_ATTACHED))) {
+ CDEBUG(D_IOCTL, "Device not attached or set up\n");
+ return -EINVAL;
+ }
+
+ if (obddev->obd_type->typ_ops->o_connect(obddev, &conninfo))
return -EINVAL;
return copy_to_user((int *)arg, &conninfo,
}
case OBD_IOC_DISCONNECT:
/* frees data structures */
+ /* has this minor been registered? */
+ if (!obddev->obd_type)
+ return -ENODEV;
+
get_user(cli_id, (int *) arg);
obddev->obd_type->typ_ops->o_disconnect(cli_id);
/* 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. */
+ /* has this minor been registered? */
+ if (!obddev->obd_type)
+ return -ENODEV;
+
if (!obddev->u.sim.sim_sb || !obddev->u.sim.sim_sb->s_dev) {
CDEBUG(D_IOCTL, "fatal: device not initialized.\n");
err = -EINVAL;
case OBD_IOC_CREATE:
/* similarly, create doesn't need a connection ID for
* the same reasons. */
+
+ /* has this minor been registered? */
+ if (!obddev->obd_type)
+ return -ENODEV;
+
+
if (!obddev->u.sim.sim_sb) {
CDEBUG(D_IOCTL, "fatal: device not initialized.\n");
return put_user(-EINVAL, (int *) arg);
unsigned int conn_id;
unsigned int ino;
} destroy;
+
+ /* has this minor been registered? */
+ if (!obddev->obd_type)
+ return -ENODEV;
+
+
copy_from_user(&destroy, (int *)arg, sizeof(struct destroy_s));
if ( !obddev->obd_type ||
!obddev->obd_type->typ_ops->o_destroy)
unsigned long ino;
struct iattr iattr;
} 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));
if (err)
if ( !obddev->obd_type ||
!obddev->obd_type->typ_ops->o_setattr)
return -EINVAL;
-
- return obddev->obd_type->typ_ops->o_setattr(foo.conn_id, foo.ino, &foo.iattr);
+
+ inode_setattr(&holder, &foo.iattr);
+ return obddev->obd_type->typ_ops->o_setattr(foo.conn_id, foo.ino, &holder);
}
case OBD_IOC_GETATTR:
unsigned long ino;
} foo;
struct iattr iattr;
+ struct inode holder;
copy_from_user(&foo, (int *)arg, sizeof(struct tmp));
if ( !obddev->obd_type ||
return -EINVAL;
if (obddev->obd_type->typ_ops->o_getattr(foo.conn_id,
- foo.ino, &iattr))
+ foo.ino, &holder))
return -EINVAL;
+ inode_to_iattr(&holder, &iattr);
err = copy_to_user((int *)arg, &iattr, sizeof(iattr));
return err;
}
{
int err;
+ /* has this minor been registered? */
+ if (!obddev->obd_type)
+ return -ENODEV;
+
err = copy_from_user(&rw_s, (int *)arg, sizeof(struct oic_rw_s));
if ( err )
return err;
case OBD_IOC_READ:
{
int err;
+ /* has this minor been registered? */
+ if (!obddev->obd_type)
+ return -ENODEV;
+
err = copy_from_user(&rw_s, (int *)arg, sizeof(struct oic_rw_s));
if ( err )
case OBD_IOC_WRITE:
{
int err;
+ /* has this minor been registered? */
+ if (!obddev->obd_type)
+ return -ENODEV;
+
copy_from_user(&rw_s, (int *)arg, sizeof(struct oic_rw_s));
CDEBUG(D_IOCTL, "\n");
return err;
}
case OBD_IOC_PREALLOCATE:
+ /* has this minor been registered? */
+ if (!obddev->obd_type)
+ return -ENODEV;
+
+
copy_from_user(&prealloc, (int *)arg,
sizeof(struct oic_prealloc_s));
struct statfs buf;
int rc;
+ /* has this minor been registered? */
+ if (!obddev->obd_type)
+ return -ENODEV;
+
tmp = (void *)arg + sizeof(unsigned int);
get_user(conn_id, (int *) arg);
if ( !obddev->obd_type ||
}
default:
- printk("invalid ioctl: cmd = %u, arg = %lu\n", cmd, arg);
+ printk("invalid ioctl: cmd = %x, arg = %lx\n", cmd, arg);
return -ENOTTY;
}
}
defined(&OBD_IOC_GETATTR);
eval 'sub OBD_IOC_READ () { &_IOC(3, ord(\'f\'), 11, 4);}' unless
defined(&OBD_IOC_READ);
-eval 'sub OBD_IOC_READ2 () { &_IOC(3, ord(\'f\'), 17, 4);}' unless
- defined(&OBD_IOC_READ2);
eval 'sub OBD_IOC_WRITE () { &_IOC(3, ord(\'f\'), 12, 4);}' unless
defined(&OBD_IOC_WRITE);
eval 'sub OBD_IOC_CONNECT () { &_IOC(2, ord(\'f\'), 13, 4);}' unless
defined(&OBD_IOC_STATFS);
eval 'sub OBD_IOC_SYNC () { &_IOC(2, ord(\'f\'), 16, 4);}' unless
defined(&OBD_IOC_SYNC);
+eval 'sub OBD_IOC_READ2 () { &_IOC(3, ord(\'f\'), 17, 4);}' unless
+ defined(&OBD_IOC_READ2);
+eval 'sub OBD_IOC_FORMATOBD () { &_IOC(3, ord(\'f\'), 18, 4);}' unless
+ defined(&OBD_IOC_FORMATOBD);
+eval 'sub OBD_IOC_PARTITION () { &_IOC(3, ord(\'f\'), 19, 4);}' unless
+ defined(&OBD_IOC_PARTITION);
+eval 'sub OBD_IOC_ATTACH () { &_IOC(3, ord(\'f\'), 20, 4);}' unless
+ defined(&OBD_IOC_ATTACH);
eval 'sub ATTR_MODE () {1;}' unless defined(&ATTR_MODE);
eval 'sub ATTR_UID () {2;}' unless defined(&ATTR_UID);
my %commands =
('create' => {func => "Create", doc => "create: creates a new inode"},
+ 'attach' => {func => "Attach", doc => "format type [adapter bus tid lun]"},
+ 'format' => {func => "Format", doc => "format type adapter bus tid lun size"},
+ 'partition' => {func => "Partition", doc => "partition type adapter bus tid lun partition size"},
'setup' => {func => "Setup", doc => "setup: link the ext2 partition (default /dev/loop0) to this obddev"},
'connect' => {func => "Connect", doc => "connect: allocates client ID for this session"},
'disconnect' => {func => "Disconnect", doc => "disconnect [id]: frees client resources"},
return (&{$commands{$cmd}->{func}}(@arg));
}
+
+sub Attach {
+ my $err = 0;
+ my $type = shift;
+ my $data;
+ my $datalen = 0;
+
+ if ($type eq "obdscsi" ) {
+ my $adapter = shift;
+ my $bus = shift;
+ my $tid = shift;
+ my $lun = shift;
+ $data = pack("iiiii", $adapter, $bus, $tid, $lun, $size);
+ $datalen = 4 * 4;
+ }
+
+ my $packed = pack("ipip", length($type), $type, $datalen, $data);
+
+ my $rc = ioctl(DEV_OBD, &OBD_IOC_ATTACH, $packed);
+
+ if (!defined $rc) {
+ print STDERR "ioctl failed: $!\n";
+ } elsif ($rc eq "0 but true") {
+ print "Finished (success)\n";
+ } else {
+ print "ioctl returned error code $rc.\n";
+ }
+}
+
+sub Format {
+ my $err = 0;
+ my $size = shift;
+ my $data = pack("i", $size);
+ my $datalen = 4;
+
+ my $packed = pack("ip", $datalen, $data);
+ my $rc = ioctl(DEV_OBD, &OBD_IOC_FORMATOBD, $packed);
+
+ if (!defined $rc) {
+ print STDERR "ioctl failed: $!\n";
+ } elsif ($rc eq "0 but true") {
+ print "Finished (success)\n";
+ } else {
+ print "ioctl returned error code $rc.\n";
+ }
+}
+
+sub Partition {
+ my $err = 0;
+ my $partno = shift;
+ my $size = shift;
+ my $data = pack("ii", $partno, $size);
+ my $datalen = 2 * 4;
+
+ my $packed = pack("ip", $datalen, $data);
+ my $rc = ioctl(DEV_OBD, &OBD_IOC_PARTITION, $packed);
+
+ if (!defined $rc) {
+ print STDERR "ioctl failed: $!\n";
+ } elsif ($rc eq "0 but true") {
+ print "Finished (success)\n";
+ } else {
+ print "ioctl returned error code $rc.\n";
+ }
+}
+
sub Setup {
my $err = 0;
+ my $type = shift;
+ my $data;
+ my $datalen = 0;
- my $packed = pack("La24", $::st->rdev(), "sim_obd");
+ $type = "sim_obd" unless $type;
+
+ if ( $type eq "sim_obd" ) {
+ my $dev = shift;
+ $dev = $::st->rdev() unless $dev;
+ $data = pack("i", $dev);
+ $datalen = 4;
+ }
+
+ my $packed = pack("ip", $datalen, $data);
my $rc = ioctl(DEV_OBD, &OBD_IOC_SETUP_OBDDEV, $packed);
if (!defined $rc) {
sub Connect {
- my $id = 0;
- my $ino = 0;
- my $bs = 0;
- my $bs_b = 0;
my $rc;
- # unsigned int conn_id;
- # unsigned long conn_ino;
- # unsigned long conn_blocksize;
- # unsigned char conn_blocksize_bits;
-
- my $packed = pack("ILLC", $id, $ino, $bs, $bs_b);
+ my $packed = "";
$rc = ioctl(DEV_OBD, &OBD_IOC_CONNECT, $packed);
- ($id, $ino, $bs, $bs_b) = unpack("ILLC", $packed);
+ $id = unpack("I", $packed);
if (!defined $rc) {
print STDERR "ioctl failed: $!\n";
} elsif ($rc eq "0 but true") {
$::client_id = $id;
print "Client ID : $id\n";
- print "Root inode : $ino\n";
- print "Blocksize : $bs\n";
- print "Blocksize bits: $bs_b\n";
print "Finished (success)\n";
} else {
print "ioctl returned error code $rc.\n";
struct page *page;
struct inode *inode = filp->f_dentry->d_inode;
+ ENTRY;
+
sb = inode->i_sb;
stored = 0;
offset = filp->f_pos & (PAGE_SIZE - 1);
while (!error && !stored && filp->f_pos < inode->i_size) {
- page = obdfs_getpage(inode, offset);
+ page = obdfs_getpage(inode, offset, 0, NOLOCK);
if (!page) {
ext2_error (sb, "ext2_readdir",
"directory #%lu contains a hole at offset %lu",
filp->f_pos += le16_to_cpu(de->rec_len);
}
offset = 0;
- }
+ page_cache_release(page);
+ }
UPDATE_ATIME(inode);
+ EXIT;
return 0;
}
#include <linux/locks.h>
#include <linux/quotaops.h>
#include <linux/iobuf.h>
+
+#include <linux/obd_support.h>
#include "obdfs.h"
/*
struct ext2_dir_entry_2 * de;
char * dlimit;
- page = obdfs_getpage(dir, offset);
+ page = obdfs_getpage(dir, offset, 0, NOLOCK);
+ if ( !page )
+ return NULL;
de = (struct ext2_dir_entry_2 *) page_address(page);
dlimit = (char *)page_address(page) + PAGE_SIZE;
}
failure:
+ page_cache_release(page);
return NULL;
}
}
-#if 0
/*
* ext2_add_entry()
*
* NOTE!! The inode part of 'de' is left at 0 - which means you
* may not sleep between calling this and putting something into
* the entry, as someone else might have used it while you slept.
+
+ * returns a locked page
*/
-static struct buffer_head * ext2_add_entry (struct inode * dir,
- const char * name, int namelen,
- struct ext2_dir_entry_2 ** res_dir,
- int *err)
+static struct page *obdfs_add_entry (struct inode * dir,
+ const char * name, int namelen,
+ struct ext2_dir_entry_2 ** res_dir,
+ int *err)
{
unsigned long offset;
unsigned short rec_len;
- struct buffer_head * bh;
+ struct page *page;
struct ext2_dir_entry_2 * de, * de1;
struct super_block * sb;
*err = -ENOENT;
return NULL;
}
- bh = ext2_bread (dir, 0, 0, err);
- if (!bh)
+ page = obdfs_getpage(dir, 0, 0, LOCKED);
+ if (!page)
return NULL;
rec_len = EXT2_DIR_REC_LEN(namelen);
offset = 0;
- de = (struct ext2_dir_entry_2 *) bh->b_data;
+ de = (struct ext2_dir_entry_2 *) page_address(page);
*err = -ENOSPC;
while (1) {
- if ((char *)de >= sb->s_blocksize + bh->b_data) {
- brelse (bh);
- bh = NULL;
- bh = ext2_bread (dir, offset >> EXT2_BLOCK_SIZE_BITS(sb), 1, err);
- if (!bh)
+ if ((char *)de >= PAGE_SIZE + (char *)page_address(page)) {
+ UnlockPage(page);
+ page_cache_release(page);
+ page = obdfs_getpage(dir, offset, 1, LOCKED);
+ if (page)
return NULL;
if (dir->i_size <= offset) {
if (dir->i_size == 0) {
ext2_debug ("creating next block\n");
- de = (struct ext2_dir_entry_2 *) bh->b_data;
+ de = (struct ext2_dir_entry_2 *) page_address(page);
de->inode = 0;
de->rec_len = le16_to_cpu(sb->s_blocksize);
- dir->i_size = offset + sb->s_blocksize;
+ dir->i_size = offset + PAGE_SIZE;
dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
mark_inode_dirty(dir);
} else {
ext2_debug ("skipping to next block\n");
- de = (struct ext2_dir_entry_2 *) bh->b_data;
+ de = (struct ext2_dir_entry_2 *) page_address(page);
}
}
+#if 0
if (!ext2_check_dir_entry ("ext2_add_entry", dir, de, bh,
offset)) {
*err = -ENOENT;
brelse (bh);
return NULL;
}
+#endif
if (ext2_match (namelen, name, de)) {
*err = -EEXIST;
- brelse (bh);
+ UnlockPage(page);
+ page_cache_release(page);
return NULL;
}
if ((le32_to_cpu(de->inode) == 0 && le16_to_cpu(de->rec_len) >= rec_len) ||
dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
mark_inode_dirty(dir);
dir->i_version = ++event;
- mark_buffer_dirty(bh, 1);
*res_dir = de;
*err = 0;
- return bh;
+ PDEBUG(page, "addentry");
+ return page;
}
offset += le16_to_cpu(de->rec_len);
de = (struct ext2_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len));
}
- brelse (bh);
+
+ UnlockPage(page);
+ page_cache_release(page);
+ PDEBUG(page, "addentry");
+ EXIT;
return NULL;
}
* ext2_delete_entry deletes a directory entry by merging it with the
* previous entry
*/
-static int ext2_delete_entry (struct ext2_dir_entry_2 * dir,
- struct buffer_head * bh)
+static int obdfs_delete_entry (struct ext2_dir_entry_2 * dir,
+ struct page * page)
{
struct ext2_dir_entry_2 * de, * pde;
int i;
i = 0;
pde = NULL;
- de = (struct ext2_dir_entry_2 *) bh->b_data;
- while (i < bh->b_size) {
+ 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))
return -EIO;
+#endif
if (de == dir) {
if (pde)
pde->rec_len =
return -ENOENT;
}
+
static inline void ext2_set_de_type(struct super_block *sb,
struct ext2_dir_entry_2 *de,
umode_t mode) {
* If the create succeeds, we fill in the inode information
* with d_instantiate().
*/
-int ext2_create (struct inode * dir, struct dentry * dentry, int mode)
+int obdfs_create (struct inode * dir, struct dentry * dentry, int mode)
{
struct inode * inode;
- struct buffer_head * bh;
+ struct page *page;
struct ext2_dir_entry_2 * de;
int err = -EIO;
+ struct obdfs_sb_info *sbi;
+ ino_t ino;
+ ENTRY;
+
+ sbi = dir->i_sb->u.generic_sbp;
/*
* N.B. Several error exits in ext2_new_inode don't set err.
*/
- inode = ext2_new_inode (dir, mode, &err);
+ ino = sbi->osi_ops->o_create(sbi->osi_obd, 0, &err);
+ if ( ino == -1 )
+ return -1;
+ inode = iget(dir->i_sb, ino);
if (!inode)
return err;
- inode->i_op = &ext2_file_inode_operations;
+ inode->i_op = &obdfs_inode_ops;
inode->i_mode = mode;
mark_inode_dirty(inode);
- bh = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
- if (!bh) {
+ page = obdfs_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
+ if (!page) {
inode->i_nlink--;
mark_inode_dirty(inode);
iput (inode);
de->inode = cpu_to_le32(inode->i_ino);
ext2_set_de_type(dir->i_sb, de, S_IFREG);
dir->i_version = ++event;
- mark_buffer_dirty(bh, 1);
+ sbi->osi_ops->o_brw(WRITE, sbi->osi_conn_info.conn_id,
+ dir->i_ino, page, 0);
+ UnlockPage(page);
+#if 0
if (IS_SYNC(dir)) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
}
- brelse (bh);
+#endif
+ page_cache_release(page);
d_instantiate(dentry, inode);
return 0;
}
-int ext2_mknod (struct inode * dir, struct dentry *dentry, int mode, int rdev)
+int obdfs_mknod (struct inode * dir, struct dentry *dentry, int mode, int rdev)
{
struct inode * inode;
- struct buffer_head * bh;
+ struct page *page;
struct ext2_dir_entry_2 * de;
int err = -EIO;
+ struct obdfs_sb_info *sbi;
- inode = ext2_new_inode (dir, mode, &err);
+ ino_t ino;
+
+ ENTRY;
+
+ sbi = dir->i_sb->u.generic_sbp;
+ /*
+ * N.B. Several error exits in ext2_new_inode don't set err.
+ */
+ ino = sbi->osi_ops->o_create(sbi->osi_obd, 0, &err);
+ if ( ino == -1 )
+ return -1;
+ inode = iget(dir->i_sb, ino);
if (!inode)
- goto out;
+ return err;
inode->i_uid = current->fsuid;
init_special_inode(inode, mode, rdev);
- bh = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
- if (!bh)
+ page = obdfs_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
+ if (!page)
goto out_no_entry;
de->inode = cpu_to_le32(inode->i_ino);
dir->i_version = ++event;
ext2_set_de_type(dir->i_sb, de, inode->i_mode);
mark_inode_dirty(inode);
- mark_buffer_dirty(bh, 1);
+ sbi->osi_ops->o_brw(WRITE, sbi->osi_conn_info.conn_id,
+ dir->i_ino, page, 0);
+ UnlockPage(page);
+
+#if 0
if (IS_SYNC(dir)) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
}
+#endif
d_instantiate(dentry, inode);
- brelse(bh);
+ page_cache_release(page);
err = 0;
out:
return err;
goto out;
}
-int ext2_mkdir(struct inode * dir, struct dentry * dentry, int mode)
+int obdfs_mkdir(struct inode * dir, struct dentry * dentry, int mode)
{
- struct inode * inode;
- struct buffer_head * bh, * dir_block;
+ struct inode * child;
+ struct page *page, *child_page;
struct ext2_dir_entry_2 * de;
+ struct obdfs_sb_info *sbi;
int err;
+ ino_t ino;
+
+ ENTRY;
+ sbi = dir->i_sb->u.generic_sbp;
err = -EMLINK;
if (dir->i_nlink >= EXT2_LINK_MAX)
goto out;
err = -EIO;
- inode = ext2_new_inode (dir, S_IFDIR, &err);
- if (!inode)
- goto out;
+ ino = iops(dir)->o_create(sbi->osi_obd, 0, &err);
+ if ( ino == -1 )
+ return -1;
+ child = iget(dir->i_sb, ino);
+ if (!child)
+ return err;
- inode->i_op = &ext2_dir_inode_operations;
- inode->i_size = inode->i_sb->s_blocksize;
- inode->i_blocks = 0;
- dir_block = ext2_bread (inode, 0, 1, &err);
- if (!dir_block) {
- inode->i_nlink--; /* is this nlink == 0? */
- mark_inode_dirty(inode);
- iput (inode);
+
+ child->i_op = &obdfs_inode_ops;
+ child->i_size = PAGE_SIZE;
+ child->i_blocks = 0;
+ child_page = obdfs_getpage(child, 0, 1, LOCKED);
+ if (!child_page) {
+ child->i_nlink--; /* is this nlink == 0? */
+ mark_inode_dirty(child);
+ iput (child);
return err;
}
- de = (struct ext2_dir_entry_2 *) dir_block->b_data;
- de->inode = cpu_to_le32(inode->i_ino);
+ child->i_blocks = PAGE_SIZE/child->i_sb->s_blocksize;
+
+ /* create . and .. */
+ de = (struct ext2_dir_entry_2 *) page_address(child_page);
+ de->inode = cpu_to_le32(child->i_ino);
de->name_len = 1;
de->rec_len = cpu_to_le16(EXT2_DIR_REC_LEN(de->name_len));
strcpy (de->name, ".");
ext2_set_de_type(dir->i_sb, de, S_IFDIR);
+
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(inode->i_sb->s_blocksize - EXT2_DIR_REC_LEN(1));
+ de->rec_len = cpu_to_le16(child->i_sb->s_blocksize - EXT2_DIR_REC_LEN(1));
de->name_len = 2;
strcpy (de->name, "..");
ext2_set_de_type(dir->i_sb, de, S_IFDIR);
- inode->i_nlink = 2;
- mark_buffer_dirty(dir_block, 1);
- brelse (dir_block);
- inode->i_mode = S_IFDIR | mode;
+
+ iops(dir)->o_brw(WRITE, sbi->osi_conn_info.conn_id, child->i_ino, child_page, 1);
+ UnlockPage(child_page);
+ page_cache_release(child_page);
+
+ child->i_nlink = 2;
+ child->i_mode = S_IFDIR | mode;
if (dir->i_mode & S_ISGID)
- inode->i_mode |= S_ISGID;
- mark_inode_dirty(inode);
- bh = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
- if (!bh)
+ child->i_mode |= S_ISGID;
+ mark_inode_dirty(child);
+
+ /* now deal with the parent */
+ page = obdfs_add_entry(dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
+ if (!page) {
goto out_no_entry;
- de->inode = cpu_to_le32(inode->i_ino);
+ }
+
+ de->inode = cpu_to_le32(child->i_ino);
ext2_set_de_type(dir->i_sb, de, S_IFDIR);
dir->i_version = ++event;
- mark_buffer_dirty(bh, 1);
+
+#if 0
if (IS_SYNC(dir)) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
}
+#endif
dir->i_nlink++;
dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
mark_inode_dirty(dir);
- d_instantiate(dentry, inode);
- brelse (bh);
+ iops(dir)->o_brw(WRITE, sbi->osi_conn_info.conn_id, dir->i_ino, page, 1);
+ UnlockPage(page);
+ page_cache_release(page);
+ d_instantiate(dentry, child);
err = 0;
out:
+ EXIT;
return err;
out_no_entry:
- inode->i_nlink = 0;
- mark_inode_dirty(inode);
- iput (inode);
+ child->i_nlink = 0;
+ mark_inode_dirty(child);
+ iput (child);
goto out;
}
+
/*
* routine to check that the specified directory is empty (for rmdir)
*/
static int empty_dir (struct inode * inode)
{
unsigned long offset;
- struct buffer_head * bh;
+ struct page *page;
struct ext2_dir_entry_2 * de, * de1;
struct super_block * sb;
- int err;
sb = inode->i_sb;
if (inode->i_size < EXT2_DIR_REC_LEN(1) + EXT2_DIR_REC_LEN(2) ||
- !(bh = ext2_bread (inode, 0, 0, &err))) {
+ !(page = obdfs_getpage (inode, 0, 0, NOLOCK))) {
ext2_warning (inode->i_sb, "empty_dir",
"bad directory (dir #%lu) - no data block",
inode->i_ino);
return 1;
}
- de = (struct ext2_dir_entry_2 *) bh->b_data;
+ de = (struct ext2_dir_entry_2 *) page_address(page);
de1 = (struct ext2_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len));
if (le32_to_cpu(de->inode) != inode->i_ino || !le32_to_cpu(de1->inode) ||
strcmp (".", de->name) || strcmp ("..", de1->name)) {
ext2_warning (inode->i_sb, "empty_dir",
"bad directory (dir #%lu) - no `.' or `..'",
inode->i_ino);
- brelse (bh);
+ page_cache_release(page);
return 1;
}
offset = le16_to_cpu(de->rec_len) + le16_to_cpu(de1->rec_len);
de = (struct ext2_dir_entry_2 *) ((char *) de1 + le16_to_cpu(de1->rec_len));
while (offset < inode->i_size ) {
- if (!bh || (void *) de >= (void *) (bh->b_data + sb->s_blocksize)) {
- brelse (bh);
- bh = ext2_bread (inode, offset >> EXT2_BLOCK_SIZE_BITS(sb), 0, &err);
- if (!bh) {
+ if (!page || (void *) de >= (void *) (page_address(page) + PAGE_SIZE)) {
+ if (page)
+ page_cache_release(page);
+ page = obdfs_getpage(inode, offset, 0, NOLOCK);
+ if (!page) {
#if 0
ext2_error (sb, "empty_dir",
"directory #%lu contains a hole at offset %lu",
offset += sb->s_blocksize;
continue;
}
- de = (struct ext2_dir_entry_2 *) bh->b_data;
+ de = (struct ext2_dir_entry_2 *) page_address(page);
}
+#if 0
if (!ext2_check_dir_entry ("empty_dir", inode, de, bh,
offset)) {
brelse (bh);
return 1;
}
+#endif
if (le32_to_cpu(de->inode)) {
- brelse (bh);
+ page_cache_release(page);
return 0;
}
offset += le16_to_cpu(de->rec_len);
de = (struct ext2_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len));
}
- brelse (bh);
+ page_cache_release(page);
return 1;
}
-int ext2_rmdir (struct inode * dir, struct dentry *dentry)
+int obdfs_rmdir (struct inode * dir, struct dentry *dentry)
{
int retval;
struct inode * inode;
- struct buffer_head * bh;
+ struct page *page;
struct ext2_dir_entry_2 * de;
+ struct obdfs_sb_info *sbi;
+
+ ENTRY;
+ sbi = dir->i_sb->u.generic_sbp;
retval = -ENOENT;
- bh = ext2_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de);
- if (!bh)
+ page = obdfs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de);
+ if (!page)
goto end_rmdir;
inode = dentry->d_inode;
if (!empty_dir (inode))
goto end_rmdir;
- retval = ext2_delete_entry (de, bh);
+ retval = obdfs_delete_entry (de, page);
dir->i_version = ++event;
if (retval)
goto end_rmdir;
- mark_buffer_dirty(bh, 1);
+ sbi->osi_ops->o_brw(WRITE, sbi->osi_conn_info.conn_id,
+ dir->i_ino, page, 0);
+ UnlockPage(page);
+#if 0
if (IS_SYNC(dir)) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
}
+#endif
if (inode->i_nlink != 2)
ext2_warning (inode->i_sb, "ext2_rmdir",
"empty directory has nlink!=2 (%d)",
d_delete(dentry);
end_rmdir:
- brelse (bh);
+ if ( page )
+ page_cache_release(page);
return retval;
}
-int ext2_unlink(struct inode * dir, struct dentry *dentry)
+int obdfs_unlink(struct inode * dir, struct dentry *dentry)
{
int retval;
struct inode * inode;
- struct buffer_head * bh;
+ struct page *page;
struct ext2_dir_entry_2 * de;
+ struct obdfs_sb_info *sbi;
+
+ ENTRY;
+ sbi = dir->i_sb->u.generic_sbp;
retval = -ENOENT;
- bh = ext2_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de);
- if (!bh)
+ page = obdfs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de);
+ if (!page)
goto end_unlink;
inode = dentry->d_inode;
inode->i_ino, inode->i_nlink);
inode->i_nlink = 1;
}
- retval = ext2_delete_entry (de, bh);
+ retval = obdfs_delete_entry (de, page);
if (retval)
goto end_unlink;
dir->i_version = ++event;
- mark_buffer_dirty(bh, 1);
+ sbi->osi_ops->o_brw(WRITE, sbi->osi_conn_info.conn_id,
+ dir->i_ino, page, 0);
+ UnlockPage(page);
+#if 0
if (IS_SYNC(dir)) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
}
+#endif
dir->i_ctime = dir->i_mtime = CURRENT_TIME;
dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
mark_inode_dirty(dir);
d_delete(dentry); /* This also frees the inode */
end_unlink:
- brelse (bh);
+ if (page)
+ page_cache_release(page);
return retval;
}
-int ext2_symlink (struct inode * dir, struct dentry *dentry, const char * symname)
+int obdfs_symlink (struct inode * dir, struct dentry *dentry, const char * symname)
{
struct ext2_dir_entry_2 * de;
struct inode * inode;
- struct buffer_head * bh = NULL, * name_block = NULL;
+ struct page* page = NULL, * name_page = NULL;
char * link;
int i, l, err = -EIO;
char c;
+ struct obdfs_sb_info *sbi;
+ ino_t ino;
+
+ ENTRY;
- if (!(inode = ext2_new_inode (dir, S_IFLNK, &err))) {
+ sbi = dir->i_sb->u.generic_sbp;
+ /*
+ * N.B. Several error exits in ext2_new_inode don't set err.
+ */
+ ino = sbi->osi_ops->o_create(sbi->osi_obd, 0, &err);
+ if ( ino == -1 )
+ return -1;
+ inode = iget(dir->i_sb, ino);
+ if (!inode)
return err;
- }
+
inode->i_mode = S_IFLNK | S_IRWXUGO;
- inode->i_op = &ext2_symlink_inode_operations;
+ inode->i_op = &obdfs_inode_ops;
for (l = 0; l < inode->i_sb->s_blocksize - 1 &&
symname [l]; l++)
;
ext2_debug ("l=%d, normal symlink\n", l);
- name_block = ext2_bread (inode, 0, 1, &err);
- if (!name_block) {
+ name_page = obdfs_getpage(inode, 0, 1, LOCKED);
+ if (!name_page) {
inode->i_nlink--;
mark_inode_dirty(inode);
iput (inode);
return err;
}
- link = name_block->b_data;
+ link = (char *)page_address(name_page);
} else {
link = (char *) inode->u.ext2_i.i_data;
while (i < inode->i_sb->s_blocksize - 1 && (c = *(symname++)))
link[i++] = c;
link[i] = 0;
- if (name_block) {
- mark_buffer_dirty(name_block, 1);
- brelse (name_block);
+ if (name_page) {
+ sbi->osi_ops->o_brw(WRITE, sbi->osi_conn_info.conn_id,
+ inode->i_ino, name_page, 1);
+ PDEBUG(name_page, "symlink");
+ UnlockPage(name_page);
+ page_cache_release(name_page);
}
inode->i_size = i;
mark_inode_dirty(inode);
- bh = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
- if (!bh)
+ page = obdfs_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
+ if (!page)
goto out_no_entry;
de->inode = cpu_to_le32(inode->i_ino);
ext2_set_de_type(dir->i_sb, de, S_IFLNK);
dir->i_version = ++event;
- mark_buffer_dirty(bh, 1);
+ sbi->osi_ops->o_brw(WRITE, sbi->osi_conn_info.conn_id,
+ dir->i_ino, page, 1);
+ UnlockPage(page);
+#if 0
if (IS_SYNC(dir)) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
}
- brelse (bh);
+#endif
d_instantiate(dentry, inode);
err = 0;
out:
goto out;
}
-int ext2_link (struct dentry * old_dentry,
+int obdfs_link (struct dentry * old_dentry,
struct inode * dir, struct dentry *dentry)
{
struct inode *inode = old_dentry->d_inode;
struct ext2_dir_entry_2 * de;
- struct buffer_head * bh;
+ struct page *page;
int err;
+ struct obdfs_sb_info *sbi;
+
+ ENTRY;
+ sbi = dir->i_sb->u.generic_sbp;
if (S_ISDIR(inode->i_mode))
return -EPERM;
if (inode->i_nlink >= EXT2_LINK_MAX)
return -EMLINK;
- bh = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
- if (!bh)
+ page = obdfs_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
+ if (!page)
return err;
de->inode = cpu_to_le32(inode->i_ino);
ext2_set_de_type(dir->i_sb, de, inode->i_mode);
dir->i_version = ++event;
- mark_buffer_dirty(bh, 1);
+ sbi->osi_ops->o_brw(WRITE, sbi->osi_conn_info.conn_id,
+ dir->i_ino, page, 0);
+ UnlockPage(page);
+
+#if 0
if (IS_SYNC(dir)) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
}
- brelse (bh);
+#endif
+ page_cache_release(page);
inode->i_nlink++;
inode->i_ctime = CURRENT_TIME;
mark_inode_dirty(inode);
* Anybody can rename anything with this: the permission checks are left to the
* higher-level routines.
*/
-int ext2_rename (struct inode * old_dir, struct dentry *old_dentry,
+int obdfs_rename (struct inode * old_dir, struct dentry *old_dentry,
struct inode * new_dir,struct dentry *new_dentry)
{
struct inode * old_inode, * new_inode;
- struct buffer_head * old_bh, * new_bh, * dir_bh;
+ struct page * old_page, * new_page, * dir_page;
struct ext2_dir_entry_2 * old_de, * new_de;
int retval;
+ struct obdfs_sb_info *sbi;
+
+ ENTRY;
+ sbi = old_dir->i_sb->u.generic_sbp;
- old_bh = new_bh = dir_bh = NULL;
+ new_page = dir_page = NULL;
- old_bh = ext2_find_entry (old_dir, old_dentry->d_name.name, old_dentry->d_name.len, &old_de);
+ old_page = obdfs_find_entry (old_dir, old_dentry->d_name.name, old_dentry->d_name.len, &old_de);
/*
* Check for inode number is _not_ due to possible IO errors.
* We might rmdir the source, keep it as pwd of some process
*/
old_inode = old_dentry->d_inode;
retval = -ENOENT;
- if (!old_bh || le32_to_cpu(old_de->inode) != old_inode->i_ino)
+ if (!old_page || le32_to_cpu(old_de->inode) != old_inode->i_ino)
goto end_rename;
new_inode = new_dentry->d_inode;
- new_bh = ext2_find_entry (new_dir, new_dentry->d_name.name,
+ new_page = obdfs_find_entry (new_dir, new_dentry->d_name.name,
new_dentry->d_name.len, &new_de);
- if (new_bh) {
+ if (new_page) {
if (!new_inode) {
- brelse (new_bh);
- new_bh = NULL;
+ page_cache_release(new_page);
+ new_page = NULL;
} else {
DQUOT_INIT(new_inode);
}
goto end_rename;
}
retval = -EIO;
- dir_bh = ext2_bread (old_inode, 0, 0, &retval);
- if (!dir_bh)
+ dir_page= obdfs_getpage (old_inode, 0, 0, LOCKED);
+ if (!dir_page)
goto end_rename;
- if (le32_to_cpu(PARENT_INO(dir_bh->b_data)) != old_dir->i_ino)
+ if (le32_to_cpu(PARENT_INO(page_address(dir_page))) != old_dir->i_ino)
goto end_rename;
retval = -EMLINK;
if (!new_inode && new_dir!=old_dir &&
new_dir->i_nlink >= EXT2_LINK_MAX)
goto end_rename;
}
- if (!new_bh) {
- new_bh = ext2_add_entry (new_dir, new_dentry->d_name.name,
+ if (!new_page) {
+ new_page = obdfs_add_entry (new_dir, new_dentry->d_name.name,
new_dentry->d_name.len, &new_de,
&retval);
- if (!new_bh)
+ if (!new_page)
goto end_rename;
}
new_dir->i_version = ++event;
EXT2_FEATURE_INCOMPAT_FILETYPE))
new_de->file_type = old_de->file_type;
- ext2_delete_entry (old_de, old_bh);
+ obdfs_delete_entry (old_de, old_page);
old_dir->i_version = ++event;
if (new_inode) {
old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
old_dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
mark_inode_dirty(old_dir);
- if (dir_bh) {
- PARENT_INO(dir_bh->b_data) = le32_to_cpu(new_dir->i_ino);
- mark_buffer_dirty(dir_bh, 1);
+ 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_dir->i_nlink--;
mark_inode_dirty(old_dir);
if (new_inode) {
mark_inode_dirty(new_dir);
}
}
- mark_buffer_dirty(old_bh, 1);
+ sbi->osi_ops->o_brw(WRITE, sbi->osi_conn_info.conn_id,
+ old_inode->i_ino, old_page, 0);
+#if 0
if (IS_SYNC(old_dir)) {
ll_rw_block (WRITE, 1, &old_bh);
wait_on_buffer (old_bh);
}
- mark_buffer_dirty(new_bh, 1);
+#endif
+ sbi->osi_ops->o_brw(WRITE, sbi->osi_conn_info.conn_id,
+ new_inode->i_ino, new_page, 0);
+#if 0
if (IS_SYNC(new_dir)) {
ll_rw_block (WRITE, 1, &new_bh);
wait_on_buffer (new_bh);
}
+#endif
retval = 0;
end_rename:
- brelse (dir_bh);
- brelse (old_bh);
- brelse (new_bh);
+ if (old_page)
+ page_cache_release(old_page);
+ if (new_page)
+ page_cache_release(new_page);
+ if (dir_page)
+ page_cache_release(dir_page);
return retval;
}
-#endif
/* XXX flush stuff */
sbi = sb->u.generic_sbp;
- PDEBUG(page, READ);
+ PDEBUG(page, "READ");
rc = sbi->osi_ops->o_brw(READ, sbi->osi_conn_info.conn_id,
- file->f_dentry->d_inode->i_ino, page);
+ file->f_dentry->d_inode->i_ino, page, 0);
if (rc == PAGE_SIZE ) {
SetPageUptodate(page);
UnlockPage(page);
}
- PDEBUG(page, READ);
+ PDEBUG(page, "READ");
if ( rc == PAGE_SIZE )
rc = 0;
return rc;
int obdfs_write_one_page(struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char * buf)
{
long status;
-
+ struct obdfs_sb_info *sbi = file->f_dentry->d_inode->i_sb->u.generic_sbp;
+
+ if ( !Page_Uptodate(page) ) {
+ status = sbi->osi_ops->o_brw(READ,
+ sbi->osi_conn_info.conn_id,
+ file->f_dentry->d_inode->i_ino,
+ page, 1);
+ if (status == PAGE_SIZE ) {
+ SetPageUptodate(page);
+ } else {
+ return status;
+ }
+ }
bytes -= copy_from_user((u8*)page_address(page) + offset, buf, bytes);
status = -EFAULT;
- CDEBUG(D_INODE, "page offset %ld, bytes %ld, offset %ld, page addr %lx, writing: %s, beg of page %s\n", page->offset, bytes, offset, page_address(page), ((char *) page_address(page)) + offset, (char *)page_address(page));
+
if (bytes) {
lock_kernel();
status = obdfs_writepage(file, page);
/* returns the page unlocked, but with a reference */
int obdfs_writepage(struct file *file, struct page *page)
{
- struct obdfs_sb_info *sbi;
- struct super_block *sb = file->f_dentry->d_inode->i_sb;
+ struct obdfs_sb_info *sbi = file->f_dentry->d_inode->i_sb->u.generic_sbp;
int rc;
ENTRY;
- PDEBUG(page,WRITE);
+ PDEBUG(page, "WRITEPAGE");
/* XXX flush stuff */
- sbi = sb->u.generic_sbp;
rc = sbi->osi_ops->o_brw(WRITE, sbi->osi_conn_info.conn_id,
- file->f_dentry->d_inode->i_ino, page);
+ file->f_dentry->d_inode->i_ino, page, 1);
SetPageUptodate(page);
- PDEBUG(page,WRITE);
+ PDEBUG(page,"WRITEPAGE");
return rc;
}
page is returned unlocked, with the up to date flag set,
and held, i.e. caller must do a page_put
*/
-struct page *obdfs_getpage(struct inode *inode, unsigned long offset)
+struct page *obdfs_getpage(struct inode *inode, unsigned long offset, int create, int locked)
{
unsigned long new_page;
struct page ** hash;
sbi = sb->u.generic_sbp;
- page = find_get_page(inode, offset);
+ page = find_lock_page(inode, offset);
if (page && Page_Uptodate(page)) {
- PDEBUG(page,READ);
+ PDEBUG(page,"GETPAGE");
+ if (!locked)
+ UnlockPage(page);
return page;
}
/* 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,READ);
+ PDEBUG(page,"GETPAGE");
sbi->osi_ops->o_brw(READ, sbi->osi_conn_info.conn_id,
- inode->i_ino, page);
- UnlockPage(page);
+ inode->i_ino, page, create);
+ if ( !locked )
+ UnlockPage(page);
SetPageUptodate(page);
+ PDEBUG(page,"GETPAGE");
return page;
}
/*
* raced with us and added our page to the cache first.
*/
CDEBUG(D_INODE, "Page not found. Someone raced us.\n");
- PDEBUG(page,READ);
+ PDEBUG(page,"GETPAGE");
return page;
}
-struct file_operations obdfs_file_operations = {
+struct file_operations obdfs_file_ops = {
NULL, /* lseek - default */
generic_file_read, /* read */
obdfs_file_write, /* write - bad */
};
struct inode_operations obdfs_inode_ops = {
- &obdfs_file_operations, /* default directory file-ops */
- NULL, /* create */
+ &obdfs_file_ops, /* default directory file-ops */
+ obdfs_create, /* create */
obdfs_lookup, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
+ obdfs_link, /* link */
+ obdfs_unlink, /* unlink */
+ obdfs_symlink, /* symlink */
+ obdfs_mkdir, /* mkdir */
+ obdfs_rmdir, /* rmdir */
+ obdfs_mknod, /* mknod */
+ obdfs_rename, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* get_block */
struct inode *root = 0;
struct obdfs_sb_info *sbi = NULL;
int error = 0;
+ unsigned long blocksize;
+ unsigned long blocksize_bits;
+ unsigned long root_ino;
+ int scratch;
+
ENTRY;
MOD_INC_USE_COUNT;
sbi->osi_obd = &obd_dev[obd_minor];
sbi->osi_ops = sbi->osi_obd->obd_type->typ_ops;
- error = sbi->osi_ops->o_connect(obd_minor, &sbi->osi_conn_info);
+ error = sbi->osi_ops->o_connect(sbi->osi_obd, &sbi->osi_conn_info);
if ( error ) {
printk("OBDFS: cannot connect to 0x%x.\n", obd_minor);
goto error;
sbi->osi_super = sb;
+ error = sbi->osi_ops->o_get_info(sbi->osi_conn_info.conn_id,
+ strlen("blocksize"),
+ "blocksize",
+ &scratch, (void *)&blocksize);
+ if ( error ) {
+ printk("Getinfo call to drive failed (blocksize)\n");
+ goto error;
+ }
+
+ error = sbi->osi_ops->o_get_info(sbi->osi_conn_info.conn_id,
+ strlen("blocksize_bits"),
+ "blocksize_bits",
+ &scratch, (void *)&blocksize_bits);
+ if ( error ) {
+ printk("Getinfo call to drive failed (blocksize_bits)\n");
+ goto error;
+ }
+
+ error = sbi->osi_ops->o_get_info(sbi->osi_conn_info.conn_id,
+ strlen("root_ino"),
+ "root_ino",
+ &scratch, (void *)&root_ino);
+ if ( error ) {
+ printk("Getinfo call to drive failed (root_ino)\n");
+ goto error;
+ }
+
+
lock_super(sb);
sb->u.generic_sbp = sbi;
- sb->s_blocksize = sbi->osi_conn_info.conn_blocksize;
- sb->s_blocksize_bits = sbi->osi_conn_info.conn_blocksize_bits;
+
+ sb->s_blocksize = blocksize;
+ sb->s_blocksize_bits = (unsigned char)blocksize_bits;
sb->s_magic = OBDFS_SUPER_MAGIC;
sb->s_op = &obdfs_super_operations;
/* make root inode */
- root = iget(sb, sbi->osi_conn_info.conn_ino);
+ root = iget(sb, root_ino);
if (!root || is_bad_inode(root)) {
printk("OBDFS: bad iget for root\n");
sb->s_dev = 0;
/* all filling in of inodes postponed until lookup */
static void obdfs_read_inode(struct inode *inode)
{
- struct iattr attr;
int error;
struct obdfs_sb_info *sbi = inode->i_sb->u.generic_sbp;
ENTRY;
error = sbi->osi_ops->o_getattr(sbi->osi_conn_info.conn_id,
- inode->i_ino, &attr);
+ inode->i_ino, inode);
if (error) {
printk("obdfs_read_inode: ibd_getattr fails (%d)\n", error);
return;
}
- inode_setattr(inode, &attr);
inode->i_op = &obdfs_inode_ops;
return;
}
-static void inode_to_iattr(struct inode *inode, struct iattr *tmp)
-{
- tmp->ia_mode = inode->i_mode;
- tmp->ia_uid = inode->i_uid;
- tmp->ia_gid = inode->i_gid;
- tmp->ia_size = inode->i_size;
- tmp->ia_atime = inode->i_atime;
- tmp->ia_mtime = inode->i_mtime;
- tmp->ia_ctime = inode->i_ctime;
- tmp->ia_attr_flags = inode->i_flags;
-
- tmp->ia_valid = ~0;
-}
-
static void obdfs_write_inode(struct inode *inode)
{
struct obdfs_sb_info *sbi;
- struct iattr attr;
int error;
- inode_to_iattr(inode, &attr);
sbi = inode->i_sb->u.generic_sbp;
error = sbi->osi_ops->o_setattr(sbi->osi_conn_info.conn_id,
- inode->i_ino, &attr);
+ inode->i_ino, inode);
if (error) {
printk("obdfs_write_inode: ibd_setattr fails (%d)\n", error);
return;
static int obdfs_notify_change(struct dentry *de, struct iattr *iattr)
{
struct inode *inode = de->d_inode;
+ struct iattr saved_copy;
struct obdfs_sb_info * sbi;
int error;
ENTRY;
+ inode_to_iattr(inode, &saved_copy);
sbi = inode->i_sb->u.generic_sbp;
+ inode_setattr(inode, iattr);
error = sbi->osi_ops->o_setattr(sbi->osi_conn_info.conn_id,
- inode->i_ino, iattr);
+ inode->i_ino, inode);
if ( error ) {
+ inode_setattr(inode, &saved_copy);
printk("obdfs_notify_change: obd_setattr fails (%d)\n", error);
return error;
- } else {
- inode_setattr(inode, iattr);
}
EXIT;
return error;
obdfs_sysctl_init();
obd_sbi = &obdfs_super_info;
- obd_fso = &obdfs_file_operations;
+ obd_fso = &obdfs_file_ops;
return register_filesystem(&obdfs_fs_type);
}