All of lore.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.