/* Copyright (c) 2008-2012 Red Hat, Inc. This file is part of GlusterFS. This file is licensed to you under your choice of the GNU Lesser General Public License, version 3 or any later version (LGPLv3 or later), or the GNU General Public License, version 2 (GPLv2), in all cases as published by the Free Software Foundation. */ #include "io-cache.h" #include "ioc-mem-types.h" extern int ioc_log2_page_size; /* * str_to_ptr - convert a string to pointer * @string: string * */ void * str_to_ptr(char *string) { void *ptr = NULL; GF_VALIDATE_OR_GOTO("io-cache", string, out); ptr = (void *)strtoul(string, NULL, 16); out: return ptr; } /* * ptr_to_str - convert a pointer to string * @ptr: pointer * */ char * ptr_to_str(void *ptr) { int ret = 0; char *str = NULL; GF_VALIDATE_OR_GOTO("io-cache", ptr, out); ret = gf_asprintf(&str, "%p", ptr); if (-1 == ret) { gf_smsg("io-cache", GF_LOG_WARNING, 0, IO_CACHE_MSG_STR_COVERSION_FAILED, NULL); str = NULL; goto out; } out: return str; } void ioc_inode_wakeup(call_frame_t *frame, ioc_inode_t *ioc_inode, struct iatt *stbuf) { ioc_waitq_t *waiter = NULL, *waited = NULL; ioc_waitq_t *page_waitq = NULL; int8_t cache_still_valid = 1; ioc_local_t *local = NULL; int8_t need_fault = 0; ioc_page_t *waiter_page = NULL; GF_VALIDATE_OR_GOTO("io-cache", frame, out); local = frame->local; GF_VALIDATE_OR_GOTO(frame->this->name, local, out); if (ioc_inode == NULL) { local->op_ret = -1; local->op_errno = EINVAL; gf_smsg(frame->this->name, GF_LOG_WARNING, 0, IO_CACHE_MSG_INODE_NULL, NULL); goto out; } if (stbuf) cache_still_valid = ioc_cache_still_valid(ioc_inode, stbuf); else cache_still_valid = 0; ioc_inode_lock(ioc_inode); { waiter = ioc_inode->waitq; if (!waiter) { gf_smsg(frame->this->name, GF_LOG_WARNING, 0, IO_CACHE_MSG_PAGE_WAIT_VALIDATE, NULL); ioc_inode_unlock(ioc_inode); goto out; } while (waiter) { waiter_page = waiter->data; ioc_inode->waitq = waiter->next; page_waitq = NULL; if (waiter_page) { if (cache_still_valid) { /* cache valid, wake up page */ page_waitq = __ioc_page_wakeup(waiter_page, waiter_page->op_errno); if (page_waitq) { ioc_inode_unlock(ioc_inode); ioc_waitq_return(page_waitq); ioc_inode_lock(ioc_inode); } } else { /* cache invalid, generate page fault and set * page->ready = 0, to avoid double faults */ if (waiter_page->ready) { waiter_page->ready = 0; need_fault = 1; } else { gf_msg_trace(frame->this->name, 0, "validate " "frame(%p) is " "waiting for " "in-transit" " page = %p", frame, waiter_page); } if (need_fault) { need_fault = 0; ioc_inode_unlock(ioc_inode); ioc_page_fault(ioc_inode, frame, local->fd, waiter_page->offset); ioc_inode_lock(ioc_inode); } } } waited = waiter; waiter = ioc_inode->waitq; waited->data = NULL; GF_FREE(waited); } } ioc_inode_unlock(ioc_inode); out: return; } /* * ioc_inode_create - create a new ioc_inode_t structure and add it to * the table table. fill in the fields which are derived * from inode_t corresponding to the file * * @table: io-table structure * @inode: inode structure * * not for external reference */ ioc_inode_t * ioc_inode_create(ioc_table_t *table, inode_t *inode, uint32_t weight) { ioc_inode_t *ioc_inode = NULL; GF_VALIDATE_OR_GOTO("io-cache", table, out); ioc_inode = GF_CALLOC(1, sizeof(ioc_inode_t), gf_ioc_mt_ioc_inode_t); if (ioc_inode == NULL) { goto out; } ioc_inode->inode = inode; ioc_inode->table = table; INIT_LIST_HEAD(&ioc_inode->cache.page_lru); pthread_mutex_init(&ioc_inode->inode_lock, NULL); ioc_inode->weight = weight; ioc_table_lock(table); { table->inode_count++; list_add(&ioc_inode->inode_list, &table->inodes); list_add_tail(&ioc_inode->inode_lru, &table->inode_lru[weight]); } ioc_table_unlock(table); gf_msg_trace(table->xl->name, 0, "adding to inode_lru[%d]", weight); out: return ioc_inode; } /* * ioc_inode_destroy - destroy an ioc_inode_t object. * * @inode: inode to destroy * * to be called only from ioc_forget. */ void ioc_inode_destroy(ioc_inode_t *ioc_inode) { ioc_table_t *table = NULL; GF_VALIDATE_OR_GOTO("io-cache", ioc_inode, out); table = ioc_inode->table; ioc_table_lock(table); { table->inode_count--; list_del(&ioc_inode->inode_list); list_del(&ioc_inode->inode_lru); } ioc_table_unlock(table); ioc_inode_flush(ioc_inode); rbthash_table_destroy(ioc_inode->cache.page_table); pthread_mutex_destroy(&ioc_inode->inode_lock); GF_FREE(ioc_inode); out: return; }