. $OBDDIR/demos/config.sh
$OBDDIR/demos/basesetup.sh
+#losetup /dev/loop0 /tmp/obdfs.tmpfile
if [ x$? != x0 ]; then
echo "Error running basesetup.sh"
"size %Ld, blocks %ld\n", __FUNCTION__ , __LINE__,\
inode->i_ino, inode->i_atime, inode->i_mtime, inode->i_ctime,\
inode->i_size, inode->i_blocks);\
- printk("]]%s line %d[[ mode %o, uid %d, gid %d, nlnk %d\n",\
+ printk("]]%s line %d[[ mode %o, uid %d, gid %d, nlnk %d, count %d\n",\
__FUNCTION__, __LINE__, inode->i_mode, inode->i_uid,\
- inode->i_gid, inode->i_nlink);\
+ inode->i_gid, inode->i_nlink, inode->i_count);\
}
/* Ext2 inode information */
#define OIDEBUG(inode) { \
ICDEBUG(inode);\
printk("oinfo: flags 0x%08x\n", OBDFS_INFO(inode)->oi_flags);\
- obdfs_print_plist(inode);\
+ /* obdfs_print_plist(inode); */\
}
#define ODEBUG(obdo) { \
ino_t osi_rootino; /* number of root inode */
int osi_minor; /* minor of /dev/obdX */
struct list_head osi_inodes; /* list of dirty inodes */
+ struct semaphore osi_list_mutex;
};
struct obdfs_inode_info {
#define OBDFS_INFO(inode) ((struct obdfs_inode_info *)(&(inode)->u.generic_ip))
+static inline struct obdfs_sb_info *obdfs_i2sbi(struct inode *inode)
+{
+ struct obdfs_sb_info *sbi;
+
+ sbi = (struct obdfs_sb_info *) &(inode->i_sb->u.generic_sbp);
+ return sbi;
+}
+
static inline struct list_head *obdfs_iplist(struct inode *inode)
{
struct obdfs_inode_info *info = (struct obdfs_inode_info *)&inode->u.generic_ip;
return &info->oi_inodes;
}
-static inline struct list_head *obdfs_slist(struct inode *inode) {
- struct obdfs_sb_info *sbi = (struct obdfs_sb_info *)(&inode->i_sb->u.generic_sbp);
+static inline struct list_head *obdfs_slist(struct inode *inode)
+{
+ struct obdfs_sb_info *sbi = obdfs_i2sbi(inode);
return &sbi->osi_inodes;
}
-static inline void obdfs_print_plist(struct inode *inode) {
+#define obd_down(mutex) {\
+ CDEBUG(D_INODE, "got lock at %s, %d\n", __FUNCTION__, __LINE__);\
+ down(mutex);\
+}
+
+#define obd_up(mutex) {\
+ up(mutex);\
+ CDEBUG(D_INODE, "free lock at %s, %d\n", __FUNCTION__, __LINE__);\
+}
+
+static inline void obdfs_print_plist(struct inode *inode)
+{
struct list_head *page_list = obdfs_iplist(inode);
struct list_head *tmp;
CDEBUG(D_INODE, "inode %ld: page", inode->i_ino);
+ /* obd_down(&obdfs_i2sbi(inode)->osi_list_mutex); */
if (list_empty(page_list)) {
printk(" list empty\n");
+ obd_up(&obdfs_i2sbi(inode)->osi_list_mutex);
return;
}
printk(" %p", pgrq->rq_page);
}
printk("\n");
+ /* obd_up(&obdfs_i2sbi(inode)->osi_list_mutex); */
}
void obdfs_sysctl_init(void);
NULL, /* readdir - bad */
NULL, /* poll - default */
NULL, /* ioctl */
- generic_file_mmap, /* mmap */
+ generic_file_mmap,
NULL, /* no special open code */
NULL, /* flush */
NULL, /* no special release code */
/* } pupd_prm = {40, 500, 64, 256, 5*HZ, 30*HZ, 5*HZ }; */
} pupd_prm = {40, 500, 64, 256, 10*HZ, 30*HZ, 5*HZ };
-#if 0
-static void obdfs_lock_page(struct page *page)
-{
- while (TryLockPage(page))
- ___wait_on_page(page);
-}
-#endif
+/* Called with the superblock list lock */
static int obdfs_enqueue_pages(struct inode *inode, struct obdo **obdo,
int nr_slots, struct page **pages, char **bufs,
obd_size *counts, obd_off *offsets,
* Note that obdfs_pgrq_del() also deletes the request.
*/
obdfs_pgrq_del(req);
- /*
- obdfs_lock_page(page);
- */
if ( !page ) {
CDEBUG(D_INODE, "no page \n");
continue;
struct list_head *tmp;
+ obd_down(&obdfs_i2sbi(inode)->osi_list_mutex);
tmp = obdfs_islist(inode);
if ( list_empty(tmp) ) {
+ obd_up(&obdfs_i2sbi(inode)->osi_list_mutex);
EXIT;
return;
}
/* now put the page away */
put_page(page);
}
-
+ iput(inode);
+ obd_up(&obdfs_i2sbi(inode)->osi_list_mutex);
}
-
/* Remove writeback requests for the superblock */
int obdfs_flush_reqs(struct list_head *inode_list, int check_time)
{
- struct list_head *tmp = inode_list;
+ struct list_head *tmp;
int total_io = 0;
obd_count num_io = 0;
obd_count num_obdos = 0;
obd_flag flags[MAX_IOVEC];
obd_count bufs_per_obdo[MAX_IOVEC];
int err = 0;
+ struct obdfs_sb_info *sbi;
+
ENTRY;
return 0;
}
+ sbi = list_entry(inode_list, struct obdfs_sb_info, osi_inodes);
+
+ obd_down(&sbi->osi_list_mutex);
if ( list_empty(inode_list)) {
CDEBUG(D_INODE, "list empty\n");
+ obd_up(&sbi->osi_list_mutex);
EXIT;
return 0;
}
- /* add each inode's outstanding pages to a write vector, and write it */
- while ( (tmp = tmp->next) != inode_list && total_io < pupd_prm.ndirty) {
+ /* add each inode's dirty pages to a write vector, and write it */
+ again:
+ tmp = inode_list;
+ while ( (tmp = tmp->next) != inode_list &&
+ total_io < pupd_prm.ndirty) {
struct obdfs_inode_info *ii;
struct inode *inode;
int res;
ii = list_entry(tmp, struct obdfs_inode_info, oi_inodes);
inode = list_entry(ii, struct inode, u);
inodes[num_obdos] = inode;
+ CDEBUG(D_INODE, "checking inode %ld pages\n", inode->i_ino);
res = 1;
&pages[num_io], &bufs[num_io],
&counts[num_io],
&offsets[num_io],
- &flags[num_obdos],1);
+ &flags[num_obdos], 1);
CDEBUG(D_INODE, "FLUSHED inode %ld, pages flushed: %d\n",
inode->i_ino, res);
if ( res < 0 ) {
+ obd_up(&sbi->osi_list_mutex);
err = res;
goto ERR;
}
num_obdos++;
if ( num_io == MAX_IOVEC ) {
+ obd_up(&sbi->osi_list_mutex);
err = obdfs_do_vec_wr(inodes, num_io, num_obdos,
obdos, bufs_per_obdo,
pages, bufs, counts,
inodes[0] = inode;
num_io = 0;
num_obdos = 0;
+ obd_down(&sbi->osi_list_mutex);
+ goto again;
}
}
+ }
- /* Remove inode from superblock dirty list when no more pages.
- * Make sure we don't point at the current inode with tmp
- * when we re-init the list on the inode, or we will loop.
- */
+ obd_up(&sbi->osi_list_mutex);
+
+ /* flush any remaining I/Os */
+ if ( num_io ) {
+ err = obdfs_do_vec_wr(inodes, num_io, num_obdos, obdos,
+ bufs_per_obdo, pages, bufs, counts,
+ offsets, flags);
+ }
+
+ /* Remove inode from superblock dirty list when no more pages.
+ * Make sure we don't point at the current inode with tmp
+ * when we re-init the list on the inode, or we will loop.
+ */
+ obd_down(&sbi->osi_list_mutex);
+ tmp = inode_list;
+ while ( (tmp = tmp->next) != inode_list ) {
+ struct obdfs_inode_info *ii;
+ struct inode *inode;
+
+ ii = list_entry(tmp, struct obdfs_inode_info, oi_inodes);
+ inode = list_entry(ii, struct inode, u);
+ CDEBUG(D_INODE, "checking inode %ld empty\n", inode->i_ino);
if (list_empty(obdfs_iplist(inode))) {
CDEBUG(D_INODE, "remove inode %ld from dirty list\n",
inode->i_ino);
tmp = tmp->prev;
list_del(obdfs_islist(inode));
+ iput(inode);
INIT_LIST_HEAD(obdfs_islist(inode));
}
}
+ obd_up(&sbi->osi_list_mutex);
- /* flush any remaining I/Os */
- if ( num_io ) {
- err = obdfs_do_vec_wr(inodes, num_io, num_obdos, obdos,
- bufs_per_obdo, pages, bufs, counts,
- offsets, flags);
- }
CDEBUG(D_INODE, "flushed %d pages in total\n", total_io);
EXIT;
ERR:
* NOTE!! The inode part of 'de' is left at 0 - which means you
* may not sleep between calling this and putting something into
* the entry, as someone else might have used it while you slept.
-
+ *
* returns a locked and held page upon success
*/
-/* We do this with a locked page: that's not necessary, since the semaphore on the inode protects this page as well. */
+/* We do this with a locked page: that's not necessary, since the semaphore
+ * on the inode protects this page as well.
+ */
static struct page *obdfs_add_entry (struct inode * dir,
const char * name, int namelen,
struct ext2_dir_entry_2 ** res_dir,
* Copryright (C) 1999 Stelias Computing Inc,
* (author Peter J. Braam <braam@stelias.com>)
* Copryright (C) 1999 Seagate Technology Inc.
- */
+*/
#include <linux/config.h>
/*
* 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_list(struct inode *inode, struct page *page)
OIDEBUG(inode);
if (list_empty(page_list)) {
+ CDEBUG(D_INODE, "empty list\n");
EXIT;
return NULL;
}
} /* obdfs_find_in_page_list */
-static struct page*
-obdfs_find_page_index(struct inode *inode, unsigned long index)
+/* called with the list lock held */
+static struct page* obdfs_find_page_index(struct inode *inode, unsigned long index)
{
struct list_head *page_list = obdfs_iplist(inode);
struct list_head *tmp;
ENTRY;
- CDEBUG(D_INODE, "looking for inode %ld pageindex %ld\n", inode->i_ino, index);
+ CDEBUG(D_INODE, "looking for inode %ld pageindex %ld\n",
+ inode->i_ino, index);
OIDEBUG(inode);
if (list_empty(page_list)) {
pgrq = list_entry(tmp, struct obdfs_pgrq, rq_plist);
page = pgrq->rq_page;
if (index == page->index) {
- CDEBUG(D_INODE, "INDEX SEARC found page %p in list, index %ld\n", 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_in_page_list */
+} /* obdfs_find_page_index */
-/* call and free pages from Linux page cache */
+/* 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,
while ( num_io > 0 ) {
num_io--;
CDEBUG(D_INODE, "calling put_page for %p, index %ld\n", pages[num_io], pages[num_io]->index);
- /*
- UnlockPage(pages[num_io]);
- */
put_page(pages[num_io]);
}
ENTRY;
/* 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);
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));
list_add(&pgrq->rq_plist, obdfs_iplist(inode));
}
- /* If inode isn't already on the superblock inodes list, add it */
+ /* 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));
}
-
/* 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);
*/
+ obd_up(&obdfs_i2sbi(inode)->osi_list_mutex);
EXIT;
return res;
} /* 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;
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 ) {
}
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) {
}
- if ( obdfs_find_page_index(inode, offset) ) {
+ if ( obdfs_find_page_index(inode, index) ) {
printk("OVERWRITE: found dirty page %p, index %ld\n", page, page->index);
}
}
INIT_LIST_HEAD(&sbi->osi_inodes);
+ sema_init(&sbi->osi_list_mutex, 1);
sbi->osi_super = sb;
INIT_LIST_HEAD(obdfs_iplist(inode)); /* list of dirty pages on inode */
INIT_LIST_HEAD(obdfs_islist(inode)); /* list of inodes in superblock */
+
obdo_free(oa);
/* OIDEBUG(inode); */