public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Andrew Morton <akpm@zip.com.au>
To: Linus Torvalds <torvalds@transmeta.com>
Cc: lkml <linux-kernel@vger.kernel.org>, Hugh Dickins <hugh@veritas.com>
Subject: [patch 14/16] tmpfs bugfixes
Date: Sat, 01 Jun 2002 01:44:03 -0700	[thread overview]
Message-ID: <3CF88953.FDE854A6@zip.com.au> (raw)



A patch from Hugh Dickins which fixes a couple of error-path leaks
related to tmpfs (I think).

Also fixes a yield()-inside-spinlock bug.

It also includes code to clear the final page outside i_size on
truncate.  tmpfs should be returning zeroes when a truncated file is
later expanded and it currently is not.

Hugh is taking care of the 2.4 fix for this.



=====================================

--- 2.5.19/mm/shmem.c~hugh	Sat Jun  1 01:18:13 2002
+++ 2.5.19-akpm/mm/shmem.c	Sat Jun  1 01:18:13 2002
@@ -52,6 +52,8 @@ LIST_HEAD (shmem_inodes);
 static spinlock_t shmem_ilock = SPIN_LOCK_UNLOCKED;
 atomic_t shmem_nrpages = ATOMIC_INIT(0); /* Not used right now */
 
+static struct page *shmem_getpage_locked(struct shmem_inode_info *, struct inode *, unsigned long);
+
 #define BLOCKS_PER_PAGE (PAGE_CACHE_SIZE/512)
 
 /*
@@ -317,6 +319,7 @@ shmem_truncate_indirect(struct shmem_ino
 static void shmem_truncate (struct inode * inode)
 {
 	unsigned long index;
+	unsigned long partial;
 	unsigned long freed = 0;
 	struct shmem_inode_info * info = SHMEM_I(inode);
 
@@ -324,6 +327,28 @@ static void shmem_truncate (struct inode
 	inode->i_ctime = inode->i_mtime = CURRENT_TIME;
 	spin_lock (&info->lock);
 	index = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+	partial = inode->i_size & ~PAGE_CACHE_MASK;
+
+	if (partial) {
+		swp_entry_t *entry = shmem_swp_entry(info, index-1, 0);
+		struct page *page;
+		/*
+		 * This check is racy: it's faintly possible that page
+		 * was assigned to swap during truncate_inode_pages,
+		 * and now assigned to file; but better than nothing.
+		 */
+		if (!IS_ERR(entry) && entry->val) {
+			spin_unlock(&info->lock);
+			page = shmem_getpage_locked(info, inode, index-1);
+			if (!IS_ERR(page)) {
+				memclear_highpage_flush(page, partial,
+					PAGE_CACHE_SIZE - partial);
+				unlock_page(page);
+				page_cache_release(page);
+			}
+			spin_lock(&info->lock);
+		}
+	}
 
 	while (index < info->next_index) 
 		freed += shmem_truncate_indirect(info, index);
@@ -369,10 +394,10 @@ static int shmem_unuse_inode (struct shm
 	swp_entry_t *ptr;
 	unsigned long idx;
 	int offset;
+	struct inode *inode = NULL;
 
-	spin_lock (&info->lock);
-repeat:
 	idx = 0;
+	spin_lock (&info->lock);
 	offset = shmem_clear_swp (entry, info->i_direct, SHMEM_NR_DIRECT);
 	if (offset >= 0)
 		goto found;
@@ -389,20 +414,36 @@ repeat:
 	spin_unlock (&info->lock);
 	return 0;
 found:
-	if (!move_from_swap_cache (page, offset+idx, info->vfs_inode.i_mapping)) {
-		info->swapped--;
-		SetPageUptodate (page);
-		spin_unlock (&info->lock);
-		return 1;
+	idx += offset;
+	inode = igrab(&info->vfs_inode);
+	spin_unlock(&shmem_ilock);
+
+	while (inode && move_from_swap_cache(page, idx, inode->i_mapping)) {
+		/*
+		 * Yield for kswapd, and try again - but we're still
+		 * holding the page lock - ugh! fix this up later on.
+		 * Beware of inode being unlinked or truncated: just
+		 * leave try_to_unuse to delete_from_swap_cache if so.
+		 */
+		spin_unlock(&info->lock);
+		yield();
+		spin_lock(&info->lock);
+		ptr = shmem_swp_entry(info, idx, 0);
+		if (IS_ERR(ptr))
+			break;
 	}
 
-	/* Yield for kswapd, and try again */
-	yield();
-	goto repeat;
+	info->swapped--;
+	SetPageUptodate(page);
+	spin_unlock(&info->lock);
+	if (inode)
+		iput(inode);
+	return 1;
 }
 
 /*
- * unuse_shmem() search for an eventually swapped out shmem page.
+ * shmem_unuse() search for an eventually swapped out shmem page.
+ * Note shmem_unuse_inode drops shmem_ilock itself if successful.
  */
 void shmem_unuse(swp_entry_t entry, struct page *page)
 {
@@ -414,7 +455,7 @@ void shmem_unuse(swp_entry_t entry, stru
 		info = list_entry(p, struct shmem_inode_info, list);
 
 		if (shmem_unuse_inode(info, entry, page))
-			break;
+			return;
 	}
 	spin_unlock (&shmem_ilock);
 }
@@ -551,6 +592,7 @@ repeat:
 		error = move_from_swap_cache(page, idx, mapping);
 		if (error < 0) {
 			unlock_page(page);
+			page_cache_release(page);
 			return ERR_PTR(error);
 		}
 
@@ -576,11 +618,11 @@ repeat:
 		 * is enough to make this atomic. */
 		page = page_cache_alloc(mapping);
 		if (!page)
-			return ERR_PTR(-ENOMEM);
+			goto no_mem;
 		error = add_to_page_cache(page, mapping, idx);
 		if (error < 0) {
 			page_cache_release(page);
-			return ERR_PTR(-ENOMEM);
+			goto no_mem;
 		}
 		clear_highpage(page);
 		inode->i_blocks += BLOCKS_PER_PAGE;
@@ -589,6 +631,13 @@ repeat:
 	/* We have the page */
 	SetPageUptodate(page);
 	return page;
+
+no_mem:
+	spin_lock(&sbinfo->stat_lock);
+	sbinfo->free_blocks++;
+	spin_unlock(&sbinfo->stat_lock);
+	return ERR_PTR(-ENOMEM);
+
 no_space:
 	spin_unlock (&sbinfo->stat_lock);
 	return ERR_PTR(-ENOSPC);
@@ -1396,6 +1445,7 @@ static void destroy_inodecache(void)
 
 static struct address_space_operations shmem_aops = {
 	writepage:	shmem_writepage,
+	set_page_dirty:	__set_page_dirty_nobuffers,
 };
 
 static struct file_operations shmem_file_operations = {

-

                 reply	other threads:[~2002-06-01  8:42 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=3CF88953.FDE854A6@zip.com.au \
    --to=akpm@zip.com.au \
    --cc=hugh@veritas.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=torvalds@transmeta.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox