int (*o_write)(struct obd_conn *conn, struct obdo *oa, char *buf,
obd_size *count, obd_off offset);
int (*o_brw)(int rw, struct obd_conn *conn, struct obdo *oa,
- char *buf, obd_size count, obd_off offset, obd_flag flags);
+ char *buf, obd_size *count, obd_off offset, obd_flag flags);
int (*o_punch)(struct obd_conn *conn, struct obdo *tgt, obd_size count,
obd_off offset);
int (*o_sync)(struct obd_conn *conn, struct obdo *tgt, obd_size count,
static __inline__ void obdo_from_inode(struct obdo *dst, struct inode *src)
{
- CDEBUG(D_INODE, "flags %x\n", dst->o_valid);
+ CDEBUG(D_INODE, "flags 0x%08x\n", dst->o_valid);
if ( dst->o_valid & OBD_MD_FLID )
dst->o_id = src->i_ino;
if ( dst->o_valid & OBD_MD_FLATIME )
static __inline__ void obdo_to_inode(struct inode *dst, struct obdo *src)
{
- CDEBUG(D_INODE, "flags %x\n", src->o_valid);
+ CDEBUG(D_INODE, "flags 0x%08x\n", src->o_valid);
if ( src->o_valid & OBD_MD_FLID )
dst->i_ino = src->o_id;
if ( src->o_valid & OBD_MD_FLATIME )
/* for copy, migrate */
struct ioc_mv_s {
- unsigned int src_conn_id;
+ uint32_t src_conn_id;
struct obdo src;
- unsigned int dst_conn_id;
+ uint32_t dst_conn_id;
struct obdo dst;
};
#define CMD(cmd) (( cmd == READ ) ? "read" : "write")
-#define IDEBUG(inode) { \
+/* Inode common information printed out */
+#define ICDEBUG(inode) { \
printk("]]%s line %d[[ ino %ld, blocks %ld, size %Ld, atm %ld, ctm %ld, mtm %ld, mode %o, uid %d, gid %d\n", \
__FUNCTION__ , __LINE__, \
inode->i_ino, inode->i_blocks, inode->i_size,\
inode->i_atime, inode->i_ctime, inode->i_mtime,\
inode->i_mode, inode->i_uid, inode->i_gid);\
- printk("blk: %d %d %d %d %d %d %d %d %d %d\n",\
+ }
+
+/* Ext2 inode information */
+#define EXDEBUG(inode) { \
+ ICDEBUG(inode);\
+ printk("data: 0x%08x 0x%08x 0x%08x 0x%08x\n",\
+ inode->u.ext2_i.i_data[0], inode->u.ext2_i.i_data[1],\
+ inode->u.ext2_i.i_data[2], inode->u.ext2_i.i_data[3]);\
+ }
+
+/* OBDFS inode information */
+/* Should print these with oi_flags and oi_list.prev, next instead of i_data */
+#define OIDEBUG(inode) { \
+ ICDEBUG(inode);\
+ printk("oinfo: flags 0x%08x next 0x%08x prev 0x%08x\n",\
inode->u.ext2_i.i_data[0], inode->u.ext2_i.i_data[1],\
- inode->u.ext2_i.i_data[2], inode->u.ext2_i.i_data[3],\
- inode->u.ext2_i.i_data[4], inode->u.ext2_i.i_data[5],\
- inode->u.ext2_i.i_data[6], inode->u.ext2_i.i_data[7],\
- inode->u.ext2_i.i_data[8], inode->u.ext2_i.i_data[9]);\
+ inode->u.ext2_i.i_data[2]);\
}
#define ODEBUG(obdo) { \
int obd_init_obdo_cache(void)
{
ENTRY;
- if (obdo_cachep != NULL) {
- printk(KERN_INFO "obdo_cache already exists\n");
- EXIT;
- /* XXX maybe this shoul be an error return? */
- return 0;
- }
-
- obdo_cachep = kmem_cache_create("obdo_cache", sizeof(struct obdo),
- 0, SLAB_HWCACHE_ALIGN, NULL, NULL);
if (obdo_cachep == NULL) {
- EXIT;
- return -ENOMEM;
+ obdo_cachep = kmem_cache_create("obdo_cache",
+ sizeof(struct obdo),
+ 0, SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if (obdo_cachep == NULL) {
+ EXIT;
+ return -ENOMEM;
+ }
}
EXIT;
return 0;
void obd_cleanup_obdo_cache(void)
{
ENTRY;
- if (obdo_cachep != NULL)
- kmem_cache_destroy(obdo_cachep);
+ if (obdo_cachep != NULL) {
+ if (kmem_cache_shrink(obdo_cachep))
+ printk(KERN_INFO "obd_cleanup_obdo_cache: unable to free all of cache\n");
+ } else
+ printk(KERN_INFO "obd_cleanup_obdo_cache: called with NULL cache pointer\n");
- obdo_cachep = NULL;
EXIT;
}
CDEBUG(D_INODE, "Read page %ld ...\n", page->index);
rc = OBP(dst_conn->oc_dev, brw)
- (WRITE, dst_conn, dst, (char *)page_address(page),
+ (WRITE, dst_conn, dst, (char *)page_address(page),
PAGE_SIZE, (page->index) << PAGE_SHIFT, 1);
if ( rc != PAGE_SIZE)
break;
offset = filp->f_pos & (PAGE_SIZE - 1);
while (!error && !stored && filp->f_pos < inode->i_size) {
- IDEBUG(inode);
+ OIDEBUG(inode);
page = obdfs_getpage(inode, offset, 0, LOCKED);
PDEBUG(page, "readdir");
if (!page) {
}
/*
- * ext2_find_entry()
+ * obdfs_find_entry()
*
* finds an entry in the specified directory with the wanted name. It
* returns the cache buffer in which the entry was found, and the entry
- * itself (as a parameter - res_dir). It does NOT read the inode of the
+ * itself (as a parameter - res_dir). It does NOT read the inode of the
* entry - you'll have to do that yourself if you want to.
*/
static struct page * obdfs_find_entry (struct inode * dir,
- const char * const name, int namelen,
- struct ext2_dir_entry_2 ** res_dir, int lock)
+ const char * const name, int namelen,
+ struct ext2_dir_entry_2 ** res_dir,
+ int lock)
{
struct super_block * sb;
unsigned long offset;
}
EXIT;
return NULL;
-}
+} /* obdfs_find_entry */
struct dentry *obdfs_lookup(struct inode * dir, struct dentry *dentry)
{
d_add(dentry, inode);
EXIT;
return NULL;
-}
+} /* obdfs_lookup */
/*
- * ext2_add_entry()
+ * obdfs_add_entry()
*
* adds a file entry to the specified directory, using the same
* semantics as ext2_find_entry(). It returns NULL if it failed.
}
rec_len = EXT2_DIR_REC_LEN(namelen);
CDEBUG(D_INODE, "reclen: %d\n", rec_len);
+ PDEBUG(page, "starting search");
offset = 0;
de = (struct ext2_dir_entry_2 *) page_address(page);
*err = -ENOSPC;
EXIT;
return NULL;
}
+ PDEBUG(page, "new directory page");
if (dir->i_size <= offset) {
if (dir->i_size == 0) {
*err = -ENOENT;
PDEBUG(page, "addentry");
EXIT;
return NULL;
-}
+} /* obdfs_add_entry */
/*
* obdfs_delete_entry deletes a directory entry by merging it with the
de = (struct ext2_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len));
}
return -ENOENT;
-}
+} /* obdfs_delete_entry */
static inline void ext2_set_de_type(struct super_block *sb,
dentry->d_name.name, dentry->d_count,
unhashed);
}
-}
+} /* show_dentry */
#endif
struct inode *obdfs_new_inode(struct inode *dir)
{
- struct obdo *obdo;
+ struct obdo *oa;
struct inode *inode;
- struct obdfs_inode_info *oinfo;
- ino_t ino;
int err;
ENTRY;
- obdo = obdo_alloc();
- if (!obdo) {
+ oa = obdo_alloc();
+ if (!oa) {
EXIT;
return ERR_PTR(-ENOMEM);
}
- err = IOPS(dir, create)(IID(dir), obdo);
- ino = (ino_t)obdo->o_id;
- obdo_free(obdo);
+ err = IOPS(dir, create)(IID(dir), oa);
if ( err ) {
+ obdo_free(oa);
EXIT;
return ERR_PTR(err);
}
- inode = iget(dir->i_sb, ino);
+ inode = iget(dir->i_sb, (ino_t)oa->o_id);
if (!inode) {
+ IOPS(dir, destroy)(IID(dir), oa);
+ obdo_free(oa);
EXIT;
return ERR_PTR(-EIO);
}
if (!list_empty(&inode->i_dentry)) {
CDEBUG(D_INODE, "New inode (%ld) has aliases!\n", inode->i_ino);
+ IOPS(dir, destroy)(IID(dir), oa);
+ obdo_free(oa);
iput(inode);
EXIT;
return ERR_PTR(-EIO);
}
- oinfo = OBD_INFO(inode);
- INIT_LIST_HEAD(&oinfo->oi_list);
+ INIT_LIST_HEAD(&OBD_LIST(inode));
+
EXIT;
return inode;
-}
+} /* obdfs_new_inode */
/*
d_instantiate(dentry, inode);
EXIT;
return err;
-}
+} /* obdfs_create */
int obdfs_mknod (struct inode * dir, struct dentry *dentry, int mode, int rdev)
{
mark_inode_dirty(inode);
iput(inode);
goto out;
-}
+} /* obdfs_mknod */
int obdfs_mkdir(struct inode * dir, struct dentry * dentry, int mode)
{
iput (inode);
EXIT;
goto out;
-}
+} /* obdfs_mkdir */
/*
UnlockPage(page);
page_cache_release(page);
return 1;
-}
+} /* empty_dir */
int obdfs_rmdir (struct inode * dir, struct dentry *dentry)
{
page_cache_release(page);
EXIT;
return retval;
-}
+} /* obdfs_rmdir */
int obdfs_unlink(struct inode * dir, struct dentry *dentry)
{
page_cache_release(page);
EXIT;
return retval;
-}
+} /* obdfs_unlink */
int obdfs_symlink (struct inode * dir, struct dentry *dentry, const char * symname)
{
de->inode = cpu_to_le32(inode->i_ino);
ext2_set_de_type(dir->i_sb, de, S_IFLNK);
dir->i_version = ++event;
- obdfs_do_writepage(dir, page, IS_SYNC(dir));
+ err = obdfs_do_writepage(dir, page, IS_SYNC(dir));
UnlockPage(page);
d_instantiate(dentry, inode);
- err = 0;
out:
EXIT;
return err;
mark_inode_dirty(inode);
iput (inode);
goto out;
-}
+} /* obdfs_symlink */
int obdfs_link (struct dentry * old_dentry,
struct inode * dir, struct dentry *dentry)
ext2_set_de_type(dir->i_sb, de, inode->i_mode);
dir->i_version = ++event;
- obdfs_do_writepage(dir, page, IS_SYNC(dir));
+ err = obdfs_do_writepage(dir, page, IS_SYNC(dir));
UnlockPage(page);
page_cache_release(page);
mark_inode_dirty(inode);
inode->i_count++;
d_instantiate(dentry, inode);
- return 0;
-}
+ return err;
+} /* obdfs_link */
#define PARENT_INO(buffer) \
((struct ext2_dir_entry_2 *) ((char *) buffer + \
struct inode * old_inode, * new_inode;
struct page * old_page, * new_page, * dir_page;
struct ext2_dir_entry_2 * old_de, * new_de;
- int retval;
+ int err;
ENTRY;
* same name. Goodbye sticky bit ;-<
*/
old_inode = old_dentry->d_inode;
- retval = -ENOENT;
+ err = -ENOENT;
if (!old_page || le32_to_cpu(old_de->inode) != old_inode->i_ino)
goto end_rename;
if (S_ISDIR(old_inode->i_mode)) {
/* can only rename into empty new directory */
if (new_inode) {
- retval = -ENOTEMPTY;
+ err = -ENOTEMPTY;
if (!empty_dir (new_inode))
goto end_rename;
}
- retval = -EIO;
+ err = -EIO;
dir_page= obdfs_getpage (old_inode, 0, 0, LOCKED);
PDEBUG(dir_page, "rename dir page");
goto end_rename;
if (le32_to_cpu(PARENT_INO(page_address(dir_page))) != old_dir->i_ino)
goto end_rename;
- retval = -EMLINK;
+ err = -EMLINK;
if (!new_inode && new_dir!=old_dir &&
new_dir->i_nlink >= EXT2_LINK_MAX)
goto end_rename;
if (!new_page) {
new_page = obdfs_add_entry (new_dir, new_dentry->d_name.name,
new_dentry->d_name.len, &new_de,
- &retval);
+ &err);
PDEBUG(new_page, "rename new page");
if (!new_page)
goto end_rename;
mark_inode_dirty(old_dir);
if (dir_page) {
PARENT_INO(page_address(dir_page)) = le32_to_cpu(new_dir->i_ino);
- obdfs_do_writepage(old_inode, dir_page, IS_SYNC(old_inode));
+ /* XXX handle err */
+ err = obdfs_do_writepage(old_inode, dir_page, IS_SYNC(old_inode));
old_dir->i_nlink--;
mark_inode_dirty(old_dir);
if (new_inode) {
page_cache_release(old_page);
old_page = obdfs_getpage(old_dir, index >> PAGE_SHIFT, 0, LOCKED);
CDEBUG(D_INODE, "old_page at %p\n", old_page);
- obdfs_do_writepage(old_dir, old_page, IS_SYNC(old_dir));
+ /* XXX handle err */
+ err = obdfs_do_writepage(old_dir, old_page, IS_SYNC(old_dir));
}
- obdfs_do_writepage(new_dir, new_page, IS_SYNC(new_dir));
-
- retval = 0;
+ err = obdfs_do_writepage(new_dir, new_page, IS_SYNC(new_dir));
end_rename:
if (old_page && PageLocked(old_page) )
page_cache_release(dir_page);
- return retval;
-}
+ return err;
+} /* obdfs_rename */
int console_loglevel;
/* SYNCHRONOUS I/O for an inode */
-int obdfs_brw(int rw, struct inode *inode, struct page *page, int create)
+static int obdfs_brw(int rw, struct inode *inode, struct page *page, int create)
{
struct obdo *obdo;
- int res;
+ obd_size count = PAGE_SIZE;
+ int err;
+ ENTRY;
obdo = obdo_alloc();
if ( ! obdo ) {
EXIT;
obdo->o_id = inode->i_ino;
- res = IOPS(inode, brw)(rw, IID(inode), obdo,
- (char *)page_address(page),
- PAGE_SIZE,
- (page->index) >> PAGE_SHIFT,
- create);
+ err = IOPS(inode, brw)(rw, IID(inode), obdo, (char *)page_address(page),
+ &count, (page->index) >> PAGE_SHIFT, create);
obdo_to_inode(inode, obdo); /* copy o_blocks to i_blocks */
obdo_free(obdo);
- if ( res == PAGE_SIZE )
- res = 0;
- return res;
-}
+ EXIT;
+ return err;
+} /* obdfs_brw */
/* returns the page unlocked, but with a reference */
int obdfs_readpage(struct dentry *dentry, struct page *page)
ENTRY;
PDEBUG(page, "READ");
- rc = obdfs_brw(READ, inode, page, 0);
- if (!rc) {
+ rc = obdfs_brw(READ, inode, page, 0);
+ if ( !rc ) {
SetPageUptodate(page);
UnlockPage(page);
}
PDEBUG(page, "READ");
EXIT;
return rc;
-}
+} /* obdfs_readpage */
-static kmem_cache_t *obdfs_wreq_cachep;
+static kmem_cache_t *obdfs_wreq_cachep = NULL;
int obdfs_init_wreqcache(void)
{
- /* XXX need to free this somewhere? */
ENTRY;
- obdfs_wreq_cachep = kmem_cache_create("obdfs_wreq",
- sizeof(struct obdfs_wreq),
- 0, SLAB_HWCACHE_ALIGN,
- NULL, NULL);
+
if (obdfs_wreq_cachep == NULL) {
- EXIT;
- return -ENOMEM;
+ obdfs_wreq_cachep = kmem_cache_create("obdfs_wreq",
+ sizeof(struct obdfs_wreq),
+ 0, SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if (obdfs_wreq_cachep == NULL) {
+ EXIT;
+ return -ENOMEM;
+ }
}
EXIT;
return 0;
-}
+} /* obdfs_init_wreqcache */
void obdfs_cleanup_wreqcache(void)
{
- if (obdfs_wreq_cachep != NULL)
- kmem_cache_destroy(obdfs_wreq_cachep);
+ ENTRY;
+ if (obdfs_wreq_cachep != NULL) {
+ if (kmem_cache_shrink(obdfs_wreq_cachep))
+ printk(KERN_INFO "obdfs_cleanup_wreqcache: unable to free all of cache\n");
+ } else
+ printk(KERN_ERR "obdfs_cleanup_wreqcache: called with NULL cache pointer\n");
- obdfs_wreq_cachep = NULL;
-}
+ EXIT;
+} /* obdfs_cleanup_wreqcache */
/*
* Find a specific page in the page cache. If it is found, we return
* the write request struct associated with it, if not found return NULL.
*/
-static struct obdfs_wreq *
-obdfs_find_in_page_cache(struct inode *inode, struct page *page)
+static struct obdfs_wreq *obdfs_find_in_page_cache(struct inode *inode,
+ struct page *page)
{
struct list_head *list_head = &OBD_LIST(inode);
struct obdfs_wreq *head, *wreq;
EXIT;
return NULL;
-}
+} /* obdfs_find_in_page_cache */
/*
* Remove a writeback request from a list
*/
-static inline int
-obdfs_remove_from_page_cache(struct obdfs_wreq *wreq)
+static inline int obdfs_remove_from_page_cache(struct obdfs_wreq *wreq)
{
struct inode *inode = wreq->wb_inode;
struct page *page = wreq->wb_page;
int rc;
ENTRY;
- CDEBUG(D_INODE, "removing inode %ld page %p, wreq: %p\n",
- inode->i_ino, page, wreq);
+ CDEBUG(D_INODE, "removing inode %ld, wreq: %p\n",
+ inode->i_ino, wreq);
+ PDEBUG(page, "REM_CACHE");
rc = obdfs_brw(WRITE, inode, page, 1);
/* XXX probably should handle error here somehow. I think that
* ext2 also does the same thing - discard write even if error?
EXIT;
return rc;
-}
+} /* obdfs_remove_from_page_cache */
/*
* Add a page to the write request cache list for later writing
*/
-static int
-obdfs_add_to_page_cache(struct inode *inode, struct page *page)
+static int obdfs_add_to_page_cache(struct inode *inode, struct page *page)
{
struct obdfs_wreq *wreq;
wreq->wb_page = page;
wreq->wb_inode = inode;
- CDEBUG(D_INODE, "getting page %p\n", wreq->wb_page);
get_page(wreq->wb_page);
- CDEBUG(D_INODE, "adding wreq %p to inode %p\n", wreq, inode);
- { struct obdfs_inode_info *oinfo = OBD_INFO(inode);
- CDEBUG(D_INODE, "generic is %p\n", inode->u.generic_ip);
- CDEBUG(D_INODE, "oinfo is %p\n", oinfo);
- }
- CDEBUG(D_INODE, "wreq_list %p\n", &wreq->wb_list);
- return -EIO;
- CDEBUG(D_INODE, "inode_list: next %p, prev %p\n", OBD_LIST(inode).next,
- OBD_LIST(inode).prev);
- CDEBUG(D_INODE, "inode_list_addr: %p\n", &OBD_LIST(inode));
-
list_add(&wreq->wb_list, &OBD_LIST(inode));
/* For testing purposes, we write out the page here.
* In the future, a flush daemon will write out the page.
+ return 0;
*/
printk(KERN_INFO "finding page in cache for write\n");
wreq = obdfs_find_in_page_cache(inode, page);
EXIT;
return obdfs_remove_from_page_cache(wreq);
-}
+} /* obdfs_add_to_page_cache */
int obdfs_do_writepage(struct inode *inode, struct page *page, int sync)
{
- int rc;
+ int err;
ENTRY;
PDEBUG(page, "WRITEPAGE");
- if ( sync ) {
- rc = obdfs_brw(WRITE, inode, page, 1);
- } else {
- /* XXX flush stuff */
- rc = obdfs_add_to_page_cache(inode, page);
- }
+ if ( sync )
+ err = obdfs_brw(WRITE, inode, page, 1);
+ else
+ err = obdfs_add_to_page_cache(inode, page);
- if (!rc)
+ if ( !err )
SetPageUptodate(page);
PDEBUG(page,"WRITEPAGE");
- return rc;
-}
+ return err;
+} /* obdfs_do_writepage */
/* returns the page unlocked, but with a reference */
int obdfs_writepage(struct dentry *dentry, struct page *page)
* If the writer ends up delaying the write, the writer needs to
* increment the page use counts until he is done with the page.
*/
-int obdfs_write_one_page(struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char * buf)
+int obdfs_write_one_page(struct file *file, struct page *page,
+ unsigned long offset, unsigned long bytes,
+ const char * buf)
{
- long status;
struct inode *inode = file->f_dentry->d_inode;
+ int err;
ENTRY;
if ( !Page_Uptodate(page) ) {
- status = obdfs_brw(READ, inode, page, 1);
- if (!status) {
+ err = obdfs_brw(READ, inode, page, 1);
+ if ( !err )
SetPageUptodate(page);
- } else {
- return status;
- }
+ else
+ return err;
}
bytes -= copy_from_user((u8*)page_address(page) + offset, buf, bytes);
- status = -EFAULT;
+ err = -EFAULT;
if (bytes) {
lock_kernel();
- status = obdfs_writepage(file->f_dentry, page);
+ err = obdfs_writepage(file->f_dentry, page);
unlock_kernel();
}
- EXIT;
- if ( status != PAGE_SIZE )
- return status;
- else
- return bytes;
-}
+
+ return err;
+} /* obdfs_write_one_page */
/*
return an up to date page:
struct page *page_cache;
struct page ** hash;
struct page * page;
- int rc;
+ int err;
ENTRY;
page = NULL;
page_cache = page_cache_alloc();
- if ( ! page_cache )
+ if ( ! page_cache ) {
+ EXIT;
return NULL;
+ }
CDEBUG(D_INODE, "page_cache %p\n", page_cache);
hash = page_hash(&inode->i_data, offset);
/* Yuck, no page */
if (! page) {
printk("grab_cache_page says no dice ...\n");
+ EXIT;
return 0;
}
return page;
}
- rc = obdfs_brw(READ, inode, page, create);
+ err = obdfs_brw(READ, inode, page, create);
- if ( rc != PAGE_SIZE ) {
+ if ( err ) {
SetPageError(page);
UnlockPage(page);
+ EXIT;
return page;
}
PDEBUG(page,"GETPAGE - after reading");
EXIT;
return page;
-}
+} /* obdfs_getpage */
ODEBUG(oa);
obdfs_to_inode(inode, oa);
+ INIT_LIST_HEAD(&OBD_LIST(inode));
+
obdo_free(oa);
- IDEBUG(inode);
+ OIDEBUG(inode);
if (S_ISREG(inode->i_mode))
inode->i_op = &obdfs_file_inode_operations;
else
/* XXX what do we pass here??? */
init_special_inode(inode, inode->i_mode, 0 /* XXX XXX */ );
+
+ EXIT;
return;
}
obdfs_cleanup_wreqcache();
obdfs_sysctl_clean();
unregister_filesystem(&obdfs_fs_type);
+
+ EXIT;
}
#endif
ENTRY;
link = (char *) inode->u.ext2_i.i_data;
if (inode->i_blocks) {
- IDEBUG(inode);
+ OIDEBUG(inode);
page = obdfs_getpage(inode, 0, 0, 0);
PDEBUG(page, "follow_link");
if (!page) {
link = (char *) inode->u.ext2_i.i_data;
if (inode->i_blocks) {
- IDEBUG(inode);
+ OIDEBUG(inode);
page = obdfs_getpage(inode, 0, 0, 0);
PDEBUG(page, "readlink");
if (!page) {