X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=lustre%2Fobdfs%2Frw.c;h=558cfedf6ee3661592171e7558e065154fc62c60;hb=86ada49822948e9cf3a8488b3297f111bcaef72e;hp=1d6399f6de928de3046c25b452e6eed5d73f0b8c;hpb=dd8ece265f41df5851d9978de979490e42237666;p=fs%2Flustre-release.git diff --git a/lustre/obdfs/rw.c b/lustre/obdfs/rw.c index 1d6399f..558cfed 100644 --- a/lustre/obdfs/rw.c +++ b/lustre/obdfs/rw.c @@ -29,7 +29,7 @@ #include #include -#include +#include #include int console_loglevel; @@ -44,14 +44,13 @@ int obdfs_brw(struct inode *dir, int rw, struct page *page, int 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 inode *inode = file->f_dentry->d_inode; - int rc; + struct inode *inode = dentry->d_inode; + struct obdfs_wreq *wreq; + int rc = 0; ENTRY; - - /* XXX flush stuff */ PDEBUG(page, "READ"); rc = iops(inode)->o_brw(READ, iid(inode),inode, page, 0); if (rc == PAGE_SIZE ) { @@ -61,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; } /* @@ -92,9 +222,8 @@ int obdfs_write_one_page(struct file *file, struct page *page, unsigned long off status = -EFAULT; if (bytes) { - lock_kernel(); - status = obdfs_writepage(file, page); + status = obdfs_writepage(file->f_dentry, page); unlock_kernel(); } EXIT; @@ -107,23 +236,6 @@ 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 inode *inode = file->f_dentry->d_inode; - int rc; - - ENTRY; - PDEBUG(page, "WRITEPAGE"); - /* XXX flush stuff */ - - rc = iops(inode)->o_brw(WRITE, iid(inode), inode, page, 1); - - SetPageUptodate(page); - PDEBUG(page,"WRITEPAGE"); - return rc; -} - void report_inode(struct page * page) { struct inode *inode = (struct inode *)0; @@ -160,27 +272,7 @@ struct page *obdfs_getpage(struct inode *inode, unsigned long offset, int create CDEBUG(D_INODE, "page_cache %p\n", page_cache); hash = page_hash(&inode->i_data, offset); - repeat: - CDEBUG(D_INODE, "Finding page\n"); - IDEBUG(inode); - - page = __find_lock_page(&inode->i_data, offset, hash); - if ( page ) { - CDEBUG(D_INODE, "Page found freeing\n"); - page_cache_free(page_cache); - } else { - page = page_cache; - if ( page->buffers ) { - PDEBUG(page, "GETPAGE: buffers bug\n"); - UnlockPage(page); - return NULL; - } - if (add_to_page_cache_unique(page, &inode->i_data, offset, hash)) { - page_cache_release(page); - CDEBUG(D_INODE, "Someone raced: try again\n"); - goto repeat; - } - } + 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 */ @@ -195,9 +287,7 @@ struct page *obdfs_getpage(struct inode *inode, unsigned long offset, int create if (! page) { printk("get_page_map says no dice ...\n"); return 0; - } - - + } rc = iops(inode)->o_brw(READ, iid(inode), inode, page, create); if ( rc != PAGE_SIZE ) { @@ -215,42 +305,3 @@ struct page *obdfs_getpage(struct inode *inode, unsigned long offset, int create } -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 */ -};