- int res = 0;
-
- 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);
- 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));
- obdfs_cache_count++;
- }
-
- /* 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;
+ int err = 0;
+ ENTRY;
+
+ /* The PG_obdcache bit is cleared by obdfs_pgrq_del() BEFORE the page
+ * is written, so at worst we will write the page out twice.
+ *
+ * If the page has the PG_obdcache bit set, then the inode MUST be
+ * on the superblock dirty list so we don't need to check this.
+ * Dirty inodes are removed from the superblock list ONLY when they
+ * don't have any more cached pages. It is possible to have an inode
+ * with no dirty pages on the superblock list, but not possible to
+ * have an inode with dirty pages NOT on the superblock dirty list.
+ */
+ if (!OBDAddCachePage(page)) {
+ struct obdfs_pgrq *pgrq;
+ pgrq = kmem_cache_alloc(obdfs_pgrq_cachep, SLAB_KERNEL);
+ if (!pgrq) {
+ OBDClearCachePage(page);
+ EXIT;
+ return -ENOMEM;
+ }
+ /* not really necessary since we set all pgrq fields here
+ memset(pgrq, 0, sizeof(*pgrq));
+ */
+
+ pgrq->rq_page = page;
+ pgrq->rq_jiffies = jiffies;
+ get_page(pgrq->rq_page);
+
+ obd_down(&obdfs_i2sbi(inode)->osi_list_mutex);
+ list_add(&pgrq->rq_plist, obdfs_iplist(inode));
+ obdfs_cache_count++;
+
+ /* If inode isn't already on superblock inodes list, add it.
+ *
+ * We increment the reference count on the inode to keep it
+ * from being freed from memory. This _should_ be an iget()
+ * with an iput() in both flush_reqs() and put_inode(), but
+ * since put_inode() is called from iput() we can't call iput()
+ * again there. Instead we just increment/decrement i_count,
+ * which is mostly what iget/iput do for an inode in memory.
+ */
+ if ( list_empty(obdfs_islist(inode)) ) {
+ atomic_inc(&inode->i_count);
+ CDEBUG(D_INFO,
+ "adding inode %ld to superblock list %p\n",
+ inode->i_ino, obdfs_slist(inode));
+ list_add(obdfs_islist(inode), obdfs_slist(inode));
+ }
+ obd_up(&obdfs_i2sbi(inode)->osi_list_mutex);
+ }
+
+ /* XXX For testing purposes, we can write out the page here.
+ err = obdfs_flush_reqs(obdfs_slist(inode), ~0UL);
+ */
+
+ EXIT;
+ return err;