Page cache now per inode. Other changes to follow.
/* rw.c */
int obdfs_do_writepage(struct inode *, struct page *, int sync);
-int obdfs_init_wreqcache(void);
-void obdfs_cleanup_wreqcache(void);
+int obdfs_init_pgrqcache(void);
+void obdfs_cleanup_pgrqcache(void);
int obdfs_readpage(struct dentry *dentry, struct page *page);
int obdfs_writepage(struct dentry *dentry, struct page *page);
struct page *obdfs_getpage(struct inode *inode, unsigned long offset, int create, int locked);
int obdfs_readlink (struct dentry *, char *, int);
struct dentry *obdfs_follow_link(struct dentry *, struct dentry *, unsigned int);
+
+struct obdfs_super_info {
+ struct list_head s_wr_head;
+};
+
+
+/* list of all OBDFS super blocks */
+struct list_head obdfs_super_list;
struct obdfs_super_entry {
struct list_head sl_chain;
- struct obdfs_sb_info *sbi;
+ struct obdfs_super_info *sl_sbi;
};
-struct obdfs_wreq {
- struct list_head wb_list; /* linked list of req's */
- struct inode *wb_inode; /* dentry referenced */
- struct page *wb_page; /* page to be written */
+struct obdfs_pgrq {
+ struct list_head rq_list; /* linked list of req's */
+ unsigned long rq_jiffies;
+ struct inode *rq_inode; /* dentry referenced */
+ struct page *rq_page; /* page to be written */
};
struct obdfs_sb_info {
struct obdfs_inode_info {
int oi_flags;
- struct list_head oi_list;
+ struct list_head oi_pages;
char *oi_inline;
};
-#define OBD_INFO(inode) ((struct obdfs_inode_info *)(&(inode)->u.generic_ip))
-/* this was used when the list was in the superblock
-#define OBD_LIST(inode) (((struct obdfs_sb_info *)(&(inode)->i_sb->u.generic_sbp))->osi_list)
-*/
-#define OBD_LIST(inode) (OBD_INFO(inode)->oi_list)
-#define WB_NEXT(req) ((struct obdfs_wreq *) ((req)->wb_list.next))
-#define WREQ(entry) (list_entry(entry, struct obdfs_wreq, wb_list))
+#define OBD_LIST(inode) (((struct obdfs_inode_info *)(&(inode)->u.generic_ip))->oi_pages)
+#define WREQ(entry) (list_entry(entry, struct obdfs_pgrq, rq_list))
+#define OBD_INFO(inode) ((struct obdfs_inode_info *)(&(inode)->u.generic_ip))
void obdfs_sysctl_init(void);
void obdfs_sysctl_clean(void);
return -ENODEV;
fsync_dev(inode->i_rdev);
if (obd_dev[dev].obd_refcnt <= 0)
- printk(KERN_ALERT "obd_class_release: refcount(%d) <= 0\n",
+ printk(KERN_ALERT "presto_psdev_release: refcount(%d) <= 0\n",
obd_dev[dev].obd_refcnt);
obd_dev[dev].obd_refcnt--;
lck_page(page);
while (index < ((src->o_size + PAGE_SIZE - 1) >> PAGE_SHIFT)) {
+ obd_size count = PAGE_SIZE;
page->index = index;
rc = OBP(src_conn->oc_dev, brw)
(READ, src_conn, src, (char *)page_address(page),
- PAGE_SIZE, (page->index) << PAGE_SHIFT, 0);
+ &count, (page->index) << PAGE_SHIFT, 0);
- if ( rc != PAGE_SIZE )
+ if ( rc != 0 )
break;
CDEBUG(D_INODE, "Read page %ld ...\n", page->index);
rc = OBP(dst_conn->oc_dev, brw)
(WRITE, dst_conn, dst, (char *)page_address(page),
- PAGE_SIZE, (page->index) << PAGE_SHIFT, 1);
- if ( rc != PAGE_SIZE)
+ &count, (page->index) << PAGE_SHIFT, 1);
+ if ( rc != 0)
break;
CDEBUG(D_INODE, "Wrote page %ld ...\n", page->index);
include ../config.mk
MODULE = obdfs.o
-CFILES= file.c dir.c sysctl.c super.c rw.c namei.c symlink.c #flushd.c
+CFILES= flushd.c rw.c file.c dir.c sysctl.c super.c namei.c symlink.c
include ../make.rules
* Copryright (C) 1999 Seagate Technology Inc.
*
*/
-#include <linux/config.h>
+#define __NO_VERSION__
#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/stat.h>
-#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/malloc.h>
#include <linux/locks.h>
-#include <linux/unistd.h>
+#include <linux/errno.h>
+#include <linux/swap.h>
+#include <linux/smp_lock.h>
+#include <linux/vmalloc.h>
+#include <linux/blkdev.h>
+#include <linux/sysrq.h>
+#include <linux/file.h>
+#include <linux/init.h>
+#include <linux/quotaops.h>
+#include <linux/iobuf.h>
+#include <linux/highmem.h>
-#include <asm/system.h>
#include <asm/uaccess.h>
-
-#include <linux/fs.h>
-#include <linux/stat.h>
-#include <asm/uaccess.h>
-#include <linux/vmalloc.h>
-#include <asm/segment.h>
-#include <linux/sched.h>
+#include <asm/io.h>
+#include <asm/bitops.h>
+#include <asm/mmu_context.h>
#include <linux/obd_support.h>
#include <linux/obd_class.h>
int interval; /* jiffies delay between kupdate flushes */
int age_buffer; /* Time for normal buffer to age before we flush it */
int age_super; /* Time for superblock to age before we flush it */
-} pupd_prm = {40, 500, 64, 256, 5*HZ, 30*HZ, 5*HZ };
-
+} pupd_prm = {40, 500, 64, 256, 5*HZ, 30*HZ, 5*HZ };
-atatic void obdfs_flush_reqs(struct obdfs_super_info *sbi, int wait,
- int check_time)
+/* static void obdfs_flush_reqs(struct obdfs_super_info *sbi, int wait,
+
+*/
+static void obdfs_flush_reqs(struct obdfs_super_info *sbi, int check_time)
{
struct list_head *wr;
- struct pg_req *req;
+ struct obdfs_pgrq *req;
- wr = &si.s_wr_head;
- while ( (wr = wr->next) != &si.s_wr_head ) {
- req = list_entry(wr, struct pg_req, rq_list);
+ wr = &sbi->s_wr_head;
+ while ( (wr = wr->next) != &sbi->s_wr_head ) {
+ req = list_entry(wr, struct obdfs_pgrq, rq_list);
if (!check_time ||
- req->rq_jiffies <= (jiffies - pup_rpm.age_buffer)) {
+ req->rq_jiffies <= (jiffies - pupd_prm.age_buffer)) {
/* write request out to disk */
- obdfs_write_page(req->inode, req->page);
+ obdfs_do_writepage(req->rq_inode, req->rq_page, 1);
}
}
static void obdfs_flush_dirty_pages(int check_time)
{
struct list_head *sl;
+ struct obdfs_super_info *sbi;
sl = &obdfs_super_list;
- while ( (sl = sl->next) != &obdfs_super_listhead ) {
+ while ( (sl = sl->next) != &obdfs_super_list ) {
struct obdfs_super_entry *entry =
list_entry(sl, struct obdfs_super_entry, sl_chain);
- struct obdfs_sb_info *sbi = sl->sl_sbi;
+ struct obdfs_super_info *sbi = entry->sl_sbi;
/* walk write requests here */
- obdfs_flush_reqs(sbi, 0);
+ obdfs_flush_reqs(sbi, jiffies);
}
/* again, but now we wait for completion */
- sl = &obdfs_super_listhead;
- while ( (sl = sl->next) != &obdfs_super_listhead ) {
- struct obdfs_super_list *entry =
- list_entry(sl, struct obdfs_super_list, sl_chain);
- struct super_block *sb = sl->sl_sb;
+ sl = &obdfs_super_list;
+ while ( (sl = sl->next) != &obdfs_super_list ) {
+ struct obdfs_super_entry *entry =
+ list_entry(sl, struct obdfs_super_entry, sl_chain);
+ sbi = entry->sl_sbi;
/* walk write requests here */
- si = &sb->u.generic;
- obdfs_flush_reqs(si, 1);
+ obdfs_flush_reqs(sbi, jiffies);
}
}
-static struct task_struct *pupdatd;
+static struct task_struct *pupdated;
-static int pupdate(void)
+static int pupdate(void *unused)
{
struct task_struct * tsk = current;
int interval;
{
stop_pupdate:
tsk->state = TASK_STOPPED;
+ MOD_DEC_USE_COUNT;
schedule(); /* wait for SIGCONT */
}
/* check for sigstop */
int flushd_init(void)
{
/* kernel_thread(bdflush, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); */
+ MOD_INC_USE_COUNT;
kernel_thread(pupdate, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
return 0;
}
if (pupdated) {
/* send updated a STOP signal */
/* then let it run at least once, before continuing */
+
1;
}
+ /* not reached */
+ return 0;
+
}
return ERR_PTR(-EIO);
}
- INIT_LIST_HEAD(&OBD_LIST(inode));
-
+ obdo_free(oa);
EXIT;
return inode;
} /* obdfs_new_inode */
return rc;
} /* obdfs_readpage */
-static kmem_cache_t *obdfs_wreq_cachep = NULL;
+static kmem_cache_t *obdfs_pgrq_cachep;
-int obdfs_init_wreqcache(void)
+int obdfs_init_pgrqcache(void)
{
ENTRY;
-
- if (obdfs_wreq_cachep == NULL) {
- 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;
- }
+ obdfs_pgrq_cachep = kmem_cache_create("obdfs_pgrq",
+ sizeof(struct obdfs_pgrq),
+ 0, SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if (obdfs_pgrq_cachep == NULL) {
+ EXIT;
+ return -ENOMEM;
}
+
EXIT;
return 0;
} /* obdfs_init_wreqcache */
-void obdfs_cleanup_wreqcache(void)
+void obdfs_cleanup_pgrqcache(void)
{
- ENTRY;
- if (obdfs_wreq_cachep != NULL) {
- if (kmem_cache_shrink(obdfs_wreq_cachep))
- printk(KERN_INFO "obdfs_cleanup_wreqcache: unable to free all of cache\n");
- } else
- printk(KERN_ERR "obdfs_cleanup_wreqcache: called with NULL cache pointer\n");
-
+ if (obdfs_pgrq_cachep != NULL)
+ kmem_cache_destroy(obdfs_pgrq_cachep);
+ obdfs_pgrq_cachep = NULL;
EXIT;
} /* obdfs_cleanup_wreqcache */
* 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)
+static struct obdfs_pgrq *
+obdfs_find_in_page_cache(struct inode *inode, struct page *page)
{
- struct list_head *list_head = &OBD_LIST(inode);
- struct obdfs_wreq *head, *wreq;
+ struct list_head *page_list = &OBD_LIST(inode);
+ struct list_head *tmp;
+ struct obdfs_pgrq *pgrq;
ENTRY;
CDEBUG(D_INODE, "looking for inode %ld page %p\n", inode->i_ino, page);
- if (list_empty(list_head)) {
+ if (list_empty(page_list)) {
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) {
+ 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);
+ if (pgrq->rq_page == page) {
CDEBUG(D_INODE, "found page %p in list\n", page);
EXIT;
- return wreq;
+ return pgrq;
}
- } 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)
+static inline int
+obdfs_remove_from_page_cache(struct obdfs_pgrq *pgrq)
{
- struct inode *inode = wreq->wb_inode;
- struct page *page = wreq->wb_page;
+ struct inode *inode = pgrq->rq_inode;
+ struct page *page = pgrq->rq_page;
int rc;
ENTRY;
- CDEBUG(D_INODE, "removing inode %ld, wreq: %p\n",
- inode->i_ino, wreq);
- PDEBUG(page, "REM_CACHE");
+ CDEBUG(D_INODE, "removing inode %ld page %p, pgrq: %p\n",
+ inode->i_ino, page, pgrq);
rc = 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(&wreq->wb_list);
- kmem_cache_free(obdfs_wreq_cachep, wreq);
+ list_del(&pgrq->rq_list);
+ kmem_cache_free(obdfs_pgrq_cachep, pgrq);
EXIT;
return rc;
*/
static int obdfs_add_to_page_cache(struct inode *inode, struct page *page)
{
- struct obdfs_wreq *wreq;
+ struct obdfs_pgrq *pgrq;
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) {
+ 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(wreq, 0, sizeof(*wreq));
+ memset(pgrq, 0, sizeof(*pgrq));
- wreq->wb_page = page;
- wreq->wb_inode = inode;
+ pgrq->rq_page = page;
+ pgrq->rq_inode = inode;
- get_page(wreq->wb_page);
- list_add(&wreq->wb_list, &OBD_LIST(inode));
+ get_page(pgrq->rq_page);
+ list_add(&pgrq->rq_list, &OBD_LIST(inode));
/* For testing purposes, we write out the page here.
* In the future, a flush daemon will write out the page.
return 0;
*/
- printk(KERN_INFO "finding page in cache for write\n");
- wreq = obdfs_find_in_page_cache(inode, page);
- if (!wreq) {
+ 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;
- }
-
- EXIT;
- return obdfs_remove_from_page_cache(wreq);
+ }
+
+ return obdfs_remove_from_page_cache(pgrq);
} /* obdfs_add_to_page_cache */
{
struct obdo *oa;
int err;
+ struct obdfs_inode_info *ii;
ENTRY;
oa = obdo_alloc();
}
oa->o_valid = ~OBD_MD_FLOBDMD;
oa->o_id = inode->i_ino;
+ ii = (struct obdfs_inode_info *)(&inode->u.generic_ip);
+ INIT_LIST_HEAD(&ii->oi_pages);
+
+
err = IOPS(inode, getattr)(IID(inode), oa);
if (err) {
printk("obdfs_read_inode: obd_getattr fails (%d)\n", err);
obdfs_sysctl_init();
INIT_LIST_HEAD(&obdfs_super_list);
- err = obdfs_init_wreqcache();
+ err = obdfs_init_pgrqcache();
if (err)
return err;
- /* XXX
flushd_init();
- */
-
return register_filesystem(&obdfs_fs_type);
}
{
ENTRY;
- obdfs_cleanup_wreqcache();
obdfs_sysctl_clean();
+ obdfs_cleanup_pgrqcache();
unregister_filesystem(&obdfs_fs_type);
EXIT;