From: braam Date: Wed, 13 Oct 1999 03:29:34 +0000 (+0000) Subject: Numerous fixes, including the attach code, better page locking etc. X-Git-Tag: v1_7_100~6185 X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=commitdiff_plain;h=9937b22dc3b00aa886cb9e0c7c7a2b71083f03af Numerous fixes, including the attach code, better page locking etc. --- diff --git a/lustre/include/linux/obd_class.h b/lustre/include/linux/obd_class.h index f7d6f22..200e45b 100644 --- a/lustre/include/linux/obd_class.h +++ b/lustre/include/linux/obd_class.h @@ -14,10 +14,6 @@ extern struct obd_device obd_dev[MAX_OBD_DEVICES]; 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 { @@ -27,9 +23,14 @@ 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; @@ -37,34 +38,35 @@ struct obd_device { } 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; @@ -78,6 +80,13 @@ struct obd_prealloc_inode { /* * 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 @@ -119,8 +128,9 @@ struct oic_partition { #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 ) diff --git a/lustre/include/linux/obd_support.h b/lustre/include/linux/obd_support.h index 2c6e664..4e2c6e5 100644 --- a/lustre/include/linux/obd_support.h +++ b/lustre/include/linux/obd_support.h @@ -50,16 +50,19 @@ extern int obd_print_entry; #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);\ } @@ -94,4 +97,45 @@ do { \ } \ } 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 diff --git a/lustre/include/linux/obdfs.h b/lustre/include/linux/obdfs.h index cee9b7b..109c706 100644 --- a/lustre/include/linux/obdfs.h +++ b/lustre/include/linux/obdfs.h @@ -18,13 +18,20 @@ ssize_t obdfs_file_write(struct file *file, const char *buf, size_t count, loff_ /* 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); @@ -40,8 +47,17 @@ void obdfs_sysctl_clean(void); 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 diff --git a/lustre/obdclass/class_obd.c b/lustre/obdclass/class_obd.c index 56cf3f3..bb76677 100644 --- a/lustre/obdclass/class_obd.c +++ b/lustre/obdclass/class_obd.c @@ -122,6 +122,28 @@ static struct obd_type *obd_nm_to_type(char *nm) 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) @@ -132,72 +154,206 @@ static int obd_class_ioctl (struct inode * inode, struct file * filp, 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; @@ -207,7 +363,13 @@ static int obd_class_ioctl (struct inode * inode, struct file * filp, { 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, @@ -215,6 +377,10 @@ static int obd_class_ioctl (struct inode * inode, struct file * filp, } 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); @@ -224,6 +390,10 @@ static int obd_class_ioctl (struct inode * inode, struct file * filp, /* 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; @@ -238,6 +408,12 @@ static int obd_class_ioctl (struct inode * inode, struct file * filp, 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); @@ -257,6 +433,12 @@ static int obd_class_ioctl (struct inode * inode, struct file * filp, 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) @@ -272,6 +454,11 @@ static int obd_class_ioctl (struct inode * inode, struct file * filp, 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) @@ -280,8 +467,9 @@ static int obd_class_ioctl (struct inode * inode, struct file * filp, 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: @@ -292,6 +480,7 @@ static int obd_class_ioctl (struct inode * inode, struct file * filp, unsigned long ino; } foo; struct iattr iattr; + struct inode holder; copy_from_user(&foo, (int *)arg, sizeof(struct tmp)); if ( !obddev->obd_type || @@ -299,9 +488,10 @@ static int obd_class_ioctl (struct inode * inode, struct file * filp, 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; } @@ -310,6 +500,10 @@ static int obd_class_ioctl (struct inode * inode, struct file * filp, { 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; @@ -336,6 +530,10 @@ static int obd_class_ioctl (struct inode * inode, struct file * filp, 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 ) @@ -362,6 +560,10 @@ static int obd_class_ioctl (struct inode * inode, struct file * filp, 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"); @@ -382,6 +584,11 @@ static int obd_class_ioctl (struct inode * inode, struct file * filp, 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)); @@ -408,6 +615,10 @@ static int obd_class_ioctl (struct inode * inode, struct file * filp, 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 || @@ -422,7 +633,7 @@ static int obd_class_ioctl (struct inode * inode, struct file * filp, } default: - printk("invalid ioctl: cmd = %u, arg = %lu\n", cmd, arg); + printk("invalid ioctl: cmd = %x, arg = %lx\n", cmd, arg); return -ENOTTY; } } diff --git a/lustre/obdclass/obdcontrol b/lustre/obdclass/obdcontrol index da661fb..1928220 100755 --- a/lustre/obdclass/obdcontrol +++ b/lustre/obdclass/obdcontrol @@ -37,8 +37,6 @@ eval 'sub OBD_IOC_GETATTR () { &_IOC(2, ord(\'f\'), 10, 4);}' unless 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 @@ -49,6 +47,14 @@ eval 'sub OBD_IOC_STATFS () { &_IOC(3, ord(\'f\'), 15, 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); @@ -88,6 +94,9 @@ my $arg; 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"}, @@ -173,10 +182,88 @@ sub execute_line { 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) { @@ -203,29 +290,17 @@ sub Cleanup { 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"; diff --git a/lustre/obdfs/dir.c b/lustre/obdfs/dir.c index 7e87052..0c0fe1c 100644 --- a/lustre/obdfs/dir.c +++ b/lustre/obdfs/dir.c @@ -89,13 +89,15 @@ int obdfs_readdir(struct file * filp, void * dirent, filldir_t filldir) 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", @@ -170,7 +172,9 @@ revalidate: filp->f_pos += le16_to_cpu(de->rec_len); } offset = 0; - } + page_cache_release(page); + } UPDATE_ATIME(inode); + EXIT; return 0; } diff --git a/lustre/obdfs/namei.c b/lustre/obdfs/namei.c index b6ba9c9..9738874 100644 --- a/lustre/obdfs/namei.c +++ b/lustre/obdfs/namei.c @@ -34,6 +34,8 @@ #include #include #include + +#include #include "obdfs.h" /* @@ -86,7 +88,9 @@ struct page * obdfs_find_entry (struct inode * dir, 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; @@ -119,6 +123,7 @@ struct page * obdfs_find_entry (struct inode * dir, } failure: + page_cache_release(page); return NULL; } @@ -146,7 +151,6 @@ struct dentry *obdfs_lookup(struct inode * dir, struct dentry *dentry) } -#if 0 /* * ext2_add_entry() * @@ -156,15 +160,17 @@ struct dentry *obdfs_lookup(struct inode * dir, struct dentry *dentry) * 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; @@ -184,19 +190,19 @@ static struct buffer_head * ext2_add_entry (struct inode * dir, *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) { @@ -206,28 +212,31 @@ static struct buffer_head * ext2_add_entry (struct inode * dir, 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) || @@ -260,15 +269,19 @@ static struct buffer_head * ext2_add_entry (struct inode * dir, 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; } @@ -276,19 +289,21 @@ static struct buffer_head * ext2_add_entry (struct inode * dir, * 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 = @@ -305,6 +320,7 @@ static int ext2_delete_entry (struct ext2_dir_entry_2 * dir, return -ENOENT; } + static inline void ext2_set_de_type(struct super_block *sb, struct ext2_dir_entry_2 *de, umode_t mode) { @@ -332,25 +348,33 @@ static inline void ext2_set_de_type(struct super_block *sb, * 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); @@ -359,43 +383,64 @@ int ext2_create (struct inode * dir, struct dentry * dentry, int mode) 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; @@ -407,114 +452,140 @@ out_no_entry: 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", @@ -523,34 +594,40 @@ static int empty_dir (struct inode * inode) 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; @@ -564,15 +641,19 @@ int ext2_rmdir (struct inode * dir, struct dentry *dentry) 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)", @@ -588,20 +669,25 @@ int ext2_rmdir (struct inode * dir, struct dentry *dentry) 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; @@ -617,15 +703,19 @@ int ext2_unlink(struct inode * dir, struct dentry *dentry) 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); @@ -636,24 +726,37 @@ int ext2_unlink(struct inode * dir, struct dentry *dentry) 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++) ; @@ -661,14 +764,14 @@ int ext2_symlink (struct inode * dir, struct dentry *dentry, const char * symnam 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; @@ -679,25 +782,31 @@ int ext2_symlink (struct inode * dir, struct dentry *dentry, const char * symnam 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: @@ -710,13 +819,17 @@ out_no_entry: 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; @@ -724,19 +837,24 @@ int ext2_link (struct dentry * old_dentry, 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); @@ -753,17 +871,21 @@ int ext2_link (struct dentry * old_dentry, * 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 @@ -772,16 +894,16 @@ int ext2_rename (struct inode * old_dir, struct dentry *old_dentry, */ 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); } @@ -793,21 +915,21 @@ int ext2_rename (struct inode * old_dir, struct dentry *old_dentry, 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; @@ -820,7 +942,7 @@ int ext2_rename (struct inode * old_dir, struct dentry *old_dentry, 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) { @@ -831,9 +953,10 @@ int ext2_rename (struct inode * old_dir, struct dentry *old_dentry, 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) { @@ -845,23 +968,31 @@ int ext2_rename (struct inode * old_dir, struct dentry *old_dentry, 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 diff --git a/lustre/obdfs/rw.c b/lustre/obdfs/rw.c index 389058c..ff06852 100644 --- a/lustre/obdfs/rw.c +++ b/lustre/obdfs/rw.c @@ -45,14 +45,14 @@ int obdfs_readpage(struct file *file, struct page *page) /* 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; @@ -71,10 +71,22 @@ int obdfs_readpage(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) { 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); @@ -92,19 +104,17 @@ int obdfs_write_one_page(struct file *file, struct page *page, unsigned long off /* 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; } @@ -113,7 +123,7 @@ int obdfs_writepage(struct file *file, struct page *page) 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; @@ -125,9 +135,11 @@ struct page *obdfs_getpage(struct inode *inode, unsigned long offset) 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; } @@ -143,13 +155,16 @@ struct page *obdfs_getpage(struct inode *inode, unsigned long offset) /* 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; } /* @@ -157,13 +172,13 @@ struct page *obdfs_getpage(struct inode *inode, unsigned long offset) * 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 */ @@ -181,16 +196,16 @@ struct file_operations obdfs_file_operations = { }; 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 */ diff --git a/lustre/obdfs/super.c b/lustre/obdfs/super.c index c40122b..0072f36 100644 --- a/lustre/obdfs/super.c +++ b/lustre/obdfs/super.c @@ -67,6 +67,11 @@ static struct super_block * obdfs_read_super(struct super_block *sb, 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; @@ -82,7 +87,7 @@ static struct super_block * obdfs_read_super(struct super_block *sb, 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; @@ -90,15 +95,44 @@ static struct super_block * obdfs_read_super(struct super_block *sb, 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; @@ -155,47 +189,29 @@ extern struct inode_operations obdfs_inode_ops; /* 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; @@ -224,19 +240,21 @@ static void obdfs_delete_inode(struct inode *inode) 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; @@ -276,7 +294,7 @@ int init_obdfs(void) obdfs_sysctl_init(); obd_sbi = &obdfs_super_info; - obd_fso = &obdfs_file_operations; + obd_fso = &obdfs_file_ops; return register_filesystem(&obdfs_fs_type); }