X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=lustre%2Fobdfs%2Frw.c;h=78bc0b0f2e05a933e04fd8976c26e0ba6ff57c95;hb=9df089d4803a1ba44299d5cb30fb4e31c83f7db2;hp=1d3e1c870cd224c99ebdd6641700f734147bb1e8;hpb=a679032a54782f700fce08e452e2603c6c15228a;p=fs%2Flustre-release.git diff --git a/lustre/obdfs/rw.c b/lustre/obdfs/rw.c index 1d3e1c8..78bc0b0 100644 --- a/lustre/obdfs/rw.c +++ b/lustre/obdfs/rw.c @@ -5,7 +5,7 @@ * Copryright (C) 1999 Stelias Computing Inc, * (author Peter J. Braam ) * Copryright (C) 1999 Seagate Technology Inc. - */ +*/ #include @@ -33,29 +33,39 @@ #include #include -int console_loglevel; + +int obdfs_flush_reqs(struct list_head *page_list, + int flush_inode, int check_time); + +void obdfs_flush_dirty_pages(int check_time); /* SYNCHRONOUS I/O for an inode */ static int obdfs_brw(int rw, struct inode *inode, struct page *page, int create) { - struct obdo *obdo; - obd_size count = PAGE_SIZE; - int err; + obd_count num_oa = 1; + obd_count oa_bufs = 1; + struct obdo *oa; + char *buf = (char *)page_address(page); + obd_size count = PAGE_SIZE; + obd_off offset = ((obd_off)page->index) << PAGE_SHIFT; + obd_flag flags = create ? OBD_BRW_CREATE : 0; + int err; ENTRY; - obdo = obdo_fromid(IID(inode), inode->i_ino); - if ( IS_ERR(obdo) ) { + oa = obdo_fromid(IID(inode), inode->i_ino, OBD_MD_FLNOTOBD); + if ( IS_ERR(oa) ) { EXIT; - return PTR_ERR(obdo); + return PTR_ERR(oa); } + obdfs_from_inode(oa, inode); - err = IOPS(inode, brw)(rw, IID(inode), obdo, (char *)page_address(page), - &count, (page->index) >> PAGE_SHIFT, create); + err = IOPS(inode, brw)(rw, IID(inode), num_oa, &oa, &oa_bufs, &buf, + &count, &offset, &flags); if ( !err ) - obdfs_to_inode(inode, obdo); /* copy o_blocks to i_blocks */ + obdfs_to_inode(inode, oa); /* copy o_blocks to i_blocks */ - obdo_free(obdo); + obdo_free(oa); EXIT; return err; @@ -80,6 +90,7 @@ int obdfs_readpage(struct dentry *dentry, struct page *page) } /* obdfs_readpage */ static kmem_cache_t *obdfs_pgrq_cachep = NULL; +static int obdfs_cache_count = 0; int obdfs_init_pgrqcache(void) { @@ -105,12 +116,20 @@ int obdfs_init_pgrqcache(void) return 0; } /* obdfs_init_wreqcache */ +inline void obdfs_pgrq_del(struct obdfs_pgrq *pgrq) +{ + obdfs_cache_count--; + CDEBUG(D_INODE, "deleting page %p from list [count %d]\n", pgrq->rq_page, obdfs_cache_count); + list_del(&pgrq->rq_plist); + kmem_cache_free(obdfs_pgrq_cachep, pgrq); +} + void obdfs_cleanup_pgrqcache(void) { ENTRY; if (obdfs_pgrq_cachep != NULL) { - CDEBUG(D_INODE, "destroying obdfs_pgrqcache at %p\n", - obdfs_pgrq_cachep); + CDEBUG(D_INODE, "destroying obdfs_pgrqcache at %p, count %d\n", + obdfs_pgrq_cachep, obdfs_cache_count); if (kmem_cache_destroy(obdfs_pgrq_cachep)) printk(KERN_INFO "obd_cleanup_pgrqcache: unable to free all of cache\n"); } else @@ -123,16 +142,19 @@ void obdfs_cleanup_pgrqcache(void) /* * 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. + * Called with the list lock held. */ static struct obdfs_pgrq * -obdfs_find_in_page_cache(struct inode *inode, struct page *page) +obdfs_find_in_page_list(struct inode *inode, struct page *page) { - struct list_head *page_list = &OBDFS_LIST(inode); + struct list_head *page_list = obdfs_iplist(inode); struct list_head *tmp; - struct obdfs_pgrq *pgrq; ENTRY; + CDEBUG(D_INODE, "looking for inode %ld page %p\n", inode->i_ino, page); + OIDEBUG(inode); + if (list_empty(page_list)) { CDEBUG(D_INODE, "empty list\n"); EXIT; @@ -140,8 +162,9 @@ obdfs_find_in_page_cache(struct inode *inode, struct page *page) } tmp = page_list; while ( (tmp = tmp->next) != page_list ) { - pgrq = list_entry(tmp, struct obdfs_pgrq, rq_list); - CDEBUG(D_INODE, "checking page %p\n", pgrq->rq_page); + struct obdfs_pgrq *pgrq; + + pgrq = list_entry(tmp, struct obdfs_pgrq, rq_plist); if (pgrq->rq_page == page) { CDEBUG(D_INODE, "found page %p in list\n", page); EXIT; @@ -151,74 +174,129 @@ obdfs_find_in_page_cache(struct inode *inode, struct page *page) EXIT; return NULL; -} /* obdfs_find_in_page_cache */ +} /* obdfs_find_in_page_list */ -/* - * Remove a writeback request from a list - */ -static inline int -obdfs_remove_from_page_cache(struct obdfs_pgrq *pgrq) +/* called with the list lock held */ +static struct page* obdfs_find_page_index(struct inode *inode, unsigned long index) { - struct inode *inode = pgrq->rq_inode; - struct page *page = pgrq->rq_page; - int err; + struct list_head *page_list = obdfs_iplist(inode); + struct list_head *tmp; + struct page *page; ENTRY; - CDEBUG(D_INODE, "writing inode %ld page %p, pgrq: %p\n", - inode->i_ino, page, pgrq); - OIDEBUG(inode); - PDEBUG(page, "REM_CACHE"); - err = 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? - */ - put_page(page); - list_del(&pgrq->rq_list); - kmem_cache_free(obdfs_pgrq_cachep, pgrq); + + CDEBUG(D_INODE, "looking for inode %ld pageindex %ld\n", + inode->i_ino, index); OIDEBUG(inode); + if (list_empty(page_list)) { + EXIT; + return NULL; + } + tmp = page_list; + while ( (tmp = tmp->next) != page_list ) { + struct obdfs_pgrq *pgrq; + + pgrq = list_entry(tmp, struct obdfs_pgrq, rq_plist); + page = pgrq->rq_page; + if (index == page->index) { + CDEBUG(D_INODE, "INDEX SEARCH found page %p in list, index %ld\n", page, index); + EXIT; + return page; + } + } + + EXIT; + return NULL; +} /* obdfs_find_page_index */ + + +/* call and free pages from Linux page cache: called with io lock on inodes */ +int obdfs_do_vec_wr(struct inode **inodes, obd_count num_io, + obd_count num_obdos, struct obdo **obdos, + obd_count *oa_bufs, struct page **pages, char **bufs, + obd_size *counts, obd_off *offsets, obd_flag *flags) +{ + struct super_block *sb = inodes[0]->i_sb; + struct obdfs_sb_info *sbi = (struct obdfs_sb_info *)&sb->u.generic_sbp; + int err; + + ENTRY; + CDEBUG(D_INODE, "writing %d page(s), %d obdo(s) in vector\n", + num_io, num_obdos); + err = OPS(sb, brw)(WRITE, &sbi->osi_conn, num_obdos, obdos, oa_bufs, + bufs, counts, offsets, flags); + + /* release the pages from the page cache */ + while ( num_io > 0 ) { + num_io--; + CDEBUG(D_INODE, "calling put_page for %p, index %ld\n", pages[num_io], pages[num_io]->index); + put_page(pages[num_io]); + } + + while ( num_obdos > 0) { + num_obdos--; + CDEBUG(D_INODE, "copy/free obdo %ld\n", + (long)obdos[num_obdos]->o_id); + obdfs_to_inode(inodes[num_obdos], obdos[num_obdos]); + obdo_free(obdos[num_obdos]); + } EXIT; return err; -} /* obdfs_remove_from_page_cache */ +} + /* * Add a page to the write request cache list for later writing * ASYNCHRONOUS write method. */ -static int obdfs_add_to_page_cache(struct inode *inode, struct page *page) +static int obdfs_add_page_to_cache(struct inode *inode, struct page *page) { - struct obdfs_pgrq *pgrq; + int res = 0; ENTRY; - pgrq = kmem_cache_alloc(obdfs_pgrq_cachep, SLAB_KERNEL); - CDEBUG(D_INODE, "adding inode %ld page %p, pgrq: %p\n", - inode->i_ino, page, pgrq); - if (!pgrq) { - EXIT; - return -ENOMEM; - } - memset(pgrq, 0, sizeof(*pgrq)); - pgrq->rq_page = page; - pgrq->rq_inode = inode; + /* If this page isn't already in the inode page list, add it */ + obd_down(&obdfs_i2sbi(inode)->osi_list_mutex); + if ( !obdfs_find_in_page_list(inode, page) ) { + struct obdfs_pgrq *pgrq; + pgrq = kmem_cache_alloc(obdfs_pgrq_cachep, SLAB_KERNEL); + CDEBUG(D_INODE, "adding inode %ld page %p, pgrq: %p, cache count [%d]\n", + inode->i_ino, page, pgrq, obdfs_cache_count); + if (!pgrq) { + EXIT; + obd_up(&obdfs_i2sbi(inode)->osi_list_mutex); + return -ENOMEM; + } + memset(pgrq, 0, sizeof(*pgrq)); + + pgrq->rq_page = page; + get_page(pgrq->rq_page); + list_add(&pgrq->rq_plist, obdfs_iplist(inode)); + } - get_page(pgrq->rq_page); - list_add(&pgrq->rq_list, &OBDFS_LIST(inode)); + /* If inode isn't already on the superblock inodes list, add it, + * and increase ref count on inode so it doesn't disappear on us. + */ + if ( list_empty(obdfs_islist(inode)) ) { + iget(inode->i_sb, inode->i_ino); + CDEBUG(D_INODE, "adding inode %ld to superblock list %p\n", + inode->i_ino, obdfs_slist(inode)); + list_add(obdfs_islist(inode), obdfs_slist(inode)); + } - /* For testing purposes, we write out the page here. - * In the future, a flush daemon will write out the page. - return 0; + /* XXX For testing purposes, we write out the page here. + * In the future, a flush daemon will write out the page. + res = obdfs_flush_reqs(obdfs_slist(inode), 0); + obdfs_flush_dirty_pages(1); */ - pgrq = obdfs_find_in_page_cache(inode, page); - if (!pgrq) { - CDEBUG(D_INODE, "XXXX Can't find page after adding it!!!\n"); - EXIT; - return -EINVAL; - } - - return obdfs_remove_from_page_cache(pgrq); -} /* obdfs_add_to_page_cache */ + obd_up(&obdfs_i2sbi(inode)->osi_list_mutex); + + EXIT; + return res; + /*return 0;*/ +} /* obdfs_add_page_to_cache */ /* select between SYNC and ASYNC I/O methods */ @@ -227,15 +305,18 @@ int obdfs_do_writepage(struct inode *inode, struct page *page, int sync) int err; ENTRY; - PDEBUG(page, "WRITEPAGE"); + /* PDEBUG(page, "WRITEPAGE"); */ if ( sync ) err = obdfs_brw(WRITE, inode, page, 1); - else - err = obdfs_add_to_page_cache(inode, page); + else { + err = obdfs_add_page_to_cache(inode, page); + CDEBUG(D_IOCTL, "DO_WR ino: %ld, page %p, err %d, uptodata %d\n", inode->i_ino, page, err, Page_Uptodate(page)); + } if ( !err ) SetPageUptodate(page); - PDEBUG(page,"WRITEPAGE"); + /* PDEBUG(page,"WRITEPAGE"); */ + EXIT; return err; } /* obdfs_do_writepage */ @@ -283,16 +364,17 @@ int obdfs_write_one_page(struct file *file, struct page *page, } /* obdfs_write_one_page */ /* - 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. -*/ + * 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) { struct page *page_cache; + int index; struct page ** hash; struct page * page; int err; @@ -300,8 +382,11 @@ struct page *obdfs_getpage(struct inode *inode, unsigned long offset, int create ENTRY; offset = offset & PAGE_CACHE_MASK; - CDEBUG(D_INODE, "\n"); - + CDEBUG(D_INODE, "ino: %ld, offset %ld, create %d, locked %d\n", + inode->i_ino, offset, create, locked); + index = offset >> PAGE_CACHE_SHIFT; + + page = NULL; page_cache = page_cache_alloc(); if ( ! page_cache ) { @@ -310,8 +395,8 @@ 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); - page = grab_cache_page(&inode->i_data, offset); + hash = page_hash(&inode->i_data, index); + page = grab_cache_page(&inode->i_data, index); /* Yuck, no page */ if (! page) { @@ -329,6 +414,11 @@ struct page *obdfs_getpage(struct inode *inode, unsigned long offset, int create return page; } + + if ( obdfs_find_page_index(inode, index) ) { + printk("OVERWRITE: found dirty page %p, index %ld\n", page, page->index); + } + err = obdfs_brw(READ, inode, page, create); if ( err ) {