X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=lustre%2Fobdfs%2Frw.c;h=558cfedf6ee3661592171e7558e065154fc62c60;hb=86ada49822948e9cf3a8488b3297f111bcaef72e;hp=ff068524df04d55ec8fb79e6c3f7530ba970e79a;hpb=9937b22dc3b00aa886cb9e0c7c7a2b71083f03af;p=fs%2Flustre-release.git diff --git a/lustre/obdfs/rw.c b/lustre/obdfs/rw.c index ff06852..558cfed 100644 --- a/lustre/obdfs/rw.c +++ b/lustre/obdfs/rw.c @@ -28,26 +28,31 @@ #include #include -#include <../obd/linux/obd_support.h> -#include <../obd/linux/obd_sim.h> -#include +#include +#include +#include + +int console_loglevel; /* VFS super_block ops */ +#if 0 +int obdfs_brw(struct inode *dir, int rw, struct page *page, int create) +{ + return iops(dir)->o_brw(rw, iid(dir), dir, page, create); +} +#endif + /* returns the page unlocked, but with a reference */ -int obdfs_readpage(struct file *file, struct page *page) +int obdfs_readpage(struct dentry *dentry, struct page *page) { - struct obdfs_sb_info *sbi; - struct super_block *sb = file->f_dentry->d_inode->i_sb; - int rc; + struct inode *inode = dentry->d_inode; + struct obdfs_wreq *wreq; + int rc = 0; ENTRY; - - /* XXX flush stuff */ - sbi = sb->u.generic_sbp; PDEBUG(page, "READ"); - rc = sbi->osi_ops->o_brw(READ, sbi->osi_conn_info.conn_id, - file->f_dentry->d_inode->i_ino, page, 0); + rc = iops(inode)->o_brw(READ, iid(inode),inode, page, 0); if (rc == PAGE_SIZE ) { SetPageUptodate(page); UnlockPage(page); @@ -55,8 +60,139 @@ int obdfs_readpage(struct file *file, struct page *page) PDEBUG(page, "READ"); if ( rc == PAGE_SIZE ) rc = 0; + } + EXIT; return rc; +} + +static kmem_cache_t *obdfs_wreq_cachep; + +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; + } + EXIT; + return 0; +} + +/* + * 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) +{ + struct list_head *list_head = &OBD_LIST(inode); + struct obdfs_wreq *head, *wreq; + + ENTRY; + CDEBUG(D_INODE, "looking for inode %ld page %p\n", inode->i_ino, page); + if (list_empty(list_head)) { + CDEBUG(D_INODE, "empty list\n"); + EXIT; + return NULL; + } + wreq = head = WREQ(list_head->next); + do { + CDEBUG(D_INODE, "checking page %p\n", wreq->wb_page); + if (wreq->wb_page == page) { + CDEBUG(D_INODE, "found page %p in list\n", page); + EXIT; + return wreq; + } + } while ((wreq = WB_NEXT(wreq)) != head); + + EXIT; + return NULL; +} + + +/* + * Remove a writeback request from a list + */ +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); + rc = iops(inode)->o_brw(WRITE, iid(inode), inode, page, 1); + /* XXX probably should handle error here somehow. I think that + * ext2 also does the same thing - discard write even if error? + */ + put_page(page); + list_del(&wreq->wb_list); + kmem_cache_free(obdfs_wreq_cachep, wreq); + + EXIT; + return rc; +} + +/* + * 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) +{ + struct obdfs_wreq *wreq; + + ENTRY; + wreq = kmem_cache_alloc(obdfs_wreq_cachep, SLAB_KERNEL); + CDEBUG(D_INODE, "adding inode %ld page %p, wreq: %p\n", + inode->i_ino, page, wreq); + if (!wreq) { + EXIT; + return -ENOMEM; + } + memset(wreq, 0, sizeof(*wreq)); + + wreq->wb_page = page; + wreq->wb_inode = inode; + + get_page(wreq->wb_page); + 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. + */ + wreq = obdfs_find_in_page_cache(inode, page); + if (!wreq) { + CDEBUG(D_INODE, "XXXX Can't find page after adding it!!!\n"); + return -EINVAL; + } else + return obdfs_remove_from_page_cache(wreq); + + return 0; +} + + +/* returns the page unlocked, but with a reference */ +int obdfs_writepage(struct dentry *dentry, struct page *page) +{ + struct inode *inode = dentry->d_inode; + int rc; + + ENTRY; + PDEBUG(page, "WRITEPAGE"); + /* XXX flush stuff */ + rc = obdfs_add_to_page_cache(inode, page); + + if (!rc) + SetPageUptodate(page); + PDEBUG(page,"WRITEPAGE"); + return rc; } /* @@ -71,13 +207,11 @@ 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; + struct inode *inode = file->f_dentry->d_inode; + ENTRY; 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); + status = iops(inode)->o_brw(READ, iid(inode), inode, page, 1); if (status == PAGE_SIZE ) { SetPageUptodate(page); } else { @@ -89,9 +223,10 @@ int obdfs_write_one_page(struct file *file, struct page *page, unsigned long off if (bytes) { lock_kernel(); - status = obdfs_writepage(file, page); + status = obdfs_writepage(file->f_dentry, page); unlock_kernel(); } + EXIT; if ( status != PAGE_SIZE ) return status; else @@ -101,119 +236,72 @@ 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 = file->f_dentry->d_inode->i_sb->u.generic_sbp; - int rc; - ENTRY; - PDEBUG(page, "WRITEPAGE"); - /* XXX flush stuff */ - - rc = sbi->osi_ops->o_brw(WRITE, sbi->osi_conn_info.conn_id, - file->f_dentry->d_inode->i_ino, page, 1); - SetPageUptodate(page); - PDEBUG(page,"WRITEPAGE"); - return rc; +void report_inode(struct page * page) { + struct inode *inode = (struct inode *)0; + int offset = (int)&inode->i_data; + inode = (struct inode *)( (char *)page->mapping - offset); + if ( inode->i_sb->s_magic == 0x4711 ) + printk("----> ino %ld , dev %d\n", inode->i_ino, inode->i_dev); } - /* - page is returned unlocked, with the up to date flag set, - and held, i.e. caller must do a page_put + return an up to date page: + - if locked is true then is returned locked + - if create is true the corresponding disk blocks are created + - page is held, i.e. caller must release the page + + modeled on NFS code. */ struct page *obdfs_getpage(struct inode *inode, unsigned long offset, int create, int locked) { - unsigned long new_page; + struct page *page_cache; struct page ** hash; - struct page * page; - struct obdfs_sb_info *sbi; - struct super_block *sb = inode->i_sb; + struct page * page; + int rc; ENTRY; - sbi = sb->u.generic_sbp; + offset = offset & PAGE_CACHE_MASK; + CDEBUG(D_INODE, "\n"); - page = find_lock_page(inode, offset); - if (page && Page_Uptodate(page)) { - PDEBUG(page,"GETPAGE"); + page = NULL; + page_cache = page_cache_alloc(); + if ( ! page_cache ) + return NULL; + CDEBUG(D_INODE, "page_cache %p\n", page_cache); + + hash = page_hash(&inode->i_data, offset); + page = grab_cache_page(&inode->i_data, offset); + + PDEBUG(page, "GETPAGE: got page - before reading\n"); + /* now check if the data in the page is up to date */ + if ( Page_Uptodate(page)) { if (!locked) UnlockPage(page); + EXIT; return page; } - - if (page && !Page_Uptodate(page) ) { - CDEBUG(D_INODE, "Page found but not up to date\n"); + + /* it's not: read it */ + if (! page) { + printk("get_page_map says no dice ...\n"); + return 0; } - /* page_cache_alloc returns address of page */ - new_page = page_cache_alloc(); - if (!new_page) - return NULL; - - /* corresponding struct page in the mmap */ - hash = page_hash(inode, offset); - page = page_cache_entry(new_page); - PDEBUG(page, "GETPAGE"); - if (!add_to_page_cache_unique(page, inode, offset, hash)) { - CDEBUG(D_INODE, "Page not found. Reading it.\n"); - PDEBUG(page,"GETPAGE"); - sbi->osi_ops->o_brw(READ, sbi->osi_conn_info.conn_id, - inode->i_ino, page, create); - if ( !locked ) - UnlockPage(page); - SetPageUptodate(page); - PDEBUG(page,"GETPAGE"); + rc = iops(inode)->o_brw(READ, iid(inode), inode, page, create); + if ( rc != PAGE_SIZE ) { + SetPageError(page); + UnlockPage(page); return page; } - /* - * We arrive here in the unlikely event that someone - * raced with us and added our page to the cache first. - */ - CDEBUG(D_INODE, "Page not found. Someone raced us.\n"); - PDEBUG(page,"GETPAGE"); + + if ( !locked ) + UnlockPage(page); + SetPageUptodate(page); + PDEBUG(page,"GETPAGE - after reading"); + EXIT; return page; } - -struct file_operations obdfs_file_ops = { - NULL, /* lseek - default */ - generic_file_read, /* read */ - obdfs_file_write, /* write - bad */ - obdfs_readdir, /* readdir */ - NULL, /* poll - default */ - NULL, /* ioctl */ - NULL, /* mmap */ - NULL, /* no special open code */ - NULL, /* flush */ - NULL, /* no special release code */ - NULL, /* fsync */ - NULL, /* fasync */ - NULL, /* check_media_change */ - NULL /* revalidate */ -}; - -struct inode_operations obdfs_inode_ops = { - &obdfs_file_ops, /* default directory file-ops */ - obdfs_create, /* create */ - obdfs_lookup, /* lookup */ - 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 */ - obdfs_readpage, /* readpage */ - obdfs_writepage, /* writepage */ - NULL, /* flushpage */ - NULL, /* truncate */ - NULL, /* permission */ - NULL, /* smap */ - NULL /* revalidate */ -};