linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Hugh Dickins <hugh@veritas.com>
To: Andrew Morton <akpm@digeo.com>
Cc: Christoph Rohland <cr@sap.com>, <linux-kernel@vger.kernel.org>
Subject: [PATCH] tmpfs 4/9 shmem_getpage locked
Date: Tue, 1 Oct 2002 22:48:45 +0100 (BST)	[thread overview]
Message-ID: <Pine.LNX.4.44.0210012247520.2602-100000@localhost.localdomain> (raw)
In-Reply-To: <Pine.LNX.4.44.0210012240470.2602-100000@localhost.localdomain>

The distinction between shmem_getpage and shmem_getpage_locked is
not helpful, particularly now info->sem is gone; and shmem_getpage
confusingly tailored to shmem_nopage's expectations.  Put the code
of shmem_getpage_locked into the frame of shmem_getpage, leaving
its callers to unlock_page afterwards.

--- tmpfs3/mm/shmem.c	Tue Oct  1 19:49:04 2002
+++ tmpfs4/mm/shmem.c	Tue Oct  1 19:49:09 2002
@@ -495,10 +495,6 @@
 
 /*
  * Move the page from the page cache to the swap cache.
- *
- * The page lock prevents multiple occurences of shmem_writepage at
- * once.  We still need to guard against racing with
- * shmem_getpage_locked().  
  */
 static int shmem_writepage(struct page * page)
 {
@@ -560,19 +556,16 @@
 }
 
 /*
- * shmem_getpage_locked - either get the page from swap or allocate a new one
+ * shmem_getpage - either get the page from swap or allocate a new one
  *
  * If we allocate a new one we do not mark it dirty. That's up to the
  * vm. If we swap it in we mark it dirty since we also free the swap
  * entry since a page cannot live in both the swap and page cache
- *
- * Called with the inode locked, so it cannot race with itself, but we
- * still need to guard against racing with shm_writepage(), which might
- * be trying to move the page to the swap cache as we run.
  */
-static struct page * shmem_getpage_locked(struct shmem_inode_info *info, struct inode * inode, unsigned long idx)
+static int shmem_getpage(struct inode *inode, unsigned long idx, struct page **pagep)
 {
 	struct address_space *mapping = inode->i_mapping;
+	struct shmem_inode_info *info = SHMEM_I(inode);
 	struct shmem_sb_info *sbinfo;
 	struct page *page;
 	swp_entry_t *entry;
@@ -580,7 +573,7 @@
 	int error = 0;
 
 	if (idx >= SHMEM_MAX_INDEX)
-		return ERR_PTR(-EFBIG);
+		return -EFBIG;
 
 	/*
 	 * When writing, i_sem is held against truncation and other
@@ -595,15 +588,17 @@
 
 repeat:
 	page = find_lock_page(mapping, idx);
-	if (page)
-		return page;
+	if (page) {
+		*pagep = page;
+		return 0;
+	}
 
 	spin_lock(&info->lock);
 	shmem_recalc_inode(inode);
 	entry = shmem_swp_alloc(info, idx);
 	if (IS_ERR(entry)) {
 		spin_unlock(&info->lock);
-		return (void *)entry;
+		return PTR_ERR(entry);
 	}
 	swap = *entry;
 
@@ -623,7 +618,7 @@
 					error = -ENOMEM;
 				spin_unlock(&info->lock);
 				if (error)
-					return ERR_PTR(error);
+					return error;
 				goto repeat;
 			}
 			wait_on_page_locked(page);
@@ -652,7 +647,7 @@
 			spin_unlock(&info->lock);
 			unlock_page(page);
 			page_cache_release(page);
-			return ERR_PTR(error);
+			return error;
 		}
 
 		*entry = (swp_entry_t) {0};
@@ -665,7 +660,7 @@
 		spin_lock(&sbinfo->stat_lock);
 		if (sbinfo->free_blocks == 0) {
 			spin_unlock(&sbinfo->stat_lock);
-			return ERR_PTR(-ENOSPC);
+			return -ENOSPC;
 		}
 		sbinfo->free_blocks--;
 		spin_unlock(&sbinfo->stat_lock);
@@ -675,7 +670,7 @@
 			spin_lock(&sbinfo->stat_lock);
 			sbinfo->free_blocks++;
 			spin_unlock(&sbinfo->stat_lock);
-			return ERR_PTR(-ENOMEM);
+			return -ENOMEM;
 		}
 
 		spin_lock(&info->lock);
@@ -690,7 +685,7 @@
 			sbinfo->free_blocks++;
 			spin_unlock(&sbinfo->stat_lock);
 			if (error)
-				return ERR_PTR(error);
+				return error;
 			goto repeat;
 		}
 		spin_unlock(&info->lock);
@@ -700,30 +695,8 @@
 
 	/* We have the page */
 	SetPageUptodate(page);
-	return page;
-}
-
-static int shmem_getpage(struct inode * inode, unsigned long idx, struct page **ptr)
-{
-	struct shmem_inode_info *info = SHMEM_I(inode);
-	int error;
-
-	*ptr = ERR_PTR(-EFAULT);
-	if (inode->i_size <= (loff_t) idx * PAGE_CACHE_SIZE)
-		goto failed;
-
-	*ptr = shmem_getpage_locked(info, inode, idx);
-	if (IS_ERR (*ptr))
-		goto failed;
-
-	unlock_page(*ptr);
+	*pagep = page;
 	return 0;
-failed:
-	error = PTR_ERR(*ptr);
-	*ptr = NOPAGE_SIGBUS;
-	if (error == -ENOMEM)
-		*ptr = NOPAGE_OOM;
-	return error;
 }
 
 static struct page *shmem_holdpage(struct inode *inode, unsigned long idx)
@@ -747,26 +720,32 @@
 	}
 	spin_unlock(&info->lock);
 	if (swap.val) {
-		if (shmem_getpage(inode, idx, &page) < 0)
-			page = NULL;
+		if (shmem_getpage(inode, idx, &page) == 0)
+			unlock_page(page);
 	}
 	return page;
 }
 
-struct page * shmem_nopage(struct vm_area_struct * vma, unsigned long address, int unused)
+struct page *shmem_nopage(struct vm_area_struct *vma, unsigned long address, int unused)
 {
-	struct page * page;
-	unsigned int idx;
-	struct inode * inode = vma->vm_file->f_dentry->d_inode;
+	struct inode *inode = vma->vm_file->f_dentry->d_inode;
+	struct page *page;
+	unsigned long idx;
+	int error;
 
 	idx = (address - vma->vm_start) >> PAGE_CACHE_SHIFT;
 	idx += vma->vm_pgoff;
 
-	if (shmem_getpage(inode, idx, &page))
-		return page;
+	if (((loff_t) idx << PAGE_CACHE_SHIFT) >= inode->i_size)
+		return NOPAGE_SIGBUS;
 
+	error = shmem_getpage(inode, idx, &page);
+	if (error)
+		return (error == -ENOMEM)? NOPAGE_OOM: NOPAGE_SIGBUS;
+
+	unlock_page(page);
 	flush_page_to_ram(page);
-	return(page);
+	return page;
 }
 
 void shmem_lock(struct file * file, int lock)
@@ -882,7 +861,6 @@
 shmem_file_write(struct file *file,const char *buf,size_t count,loff_t *ppos)
 {
 	struct inode	*inode = file->f_dentry->d_inode; 
-	struct shmem_inode_info *info;
 	unsigned long	limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
 	loff_t		pos;
 	struct page	*page;
@@ -973,11 +951,8 @@
 			__get_user(dummy, buf+bytes-1);
 		}
 
-		info = SHMEM_I(inode);
-		page = shmem_getpage_locked(info, inode, index);
-
-		status = PTR_ERR(page);
-		if (IS_ERR(page))
+		status = shmem_getpage(inode, index, &page);
+		if (status)
 			break;
 
 		/* We have exclusive IO access to the page.. */
@@ -1064,10 +1039,12 @@
 		if (index == end_index) {
 			nr = inode->i_size & ~PAGE_CACHE_MASK;
 			if (nr <= offset) {
+				unlock_page(page);
 				page_cache_release(page);
 				break;
 			}
 		}
+		unlock_page(page);
 		nr -= offset;
 
 		if (!list_empty(&mapping->i_mmap_shared))
@@ -1271,6 +1248,7 @@
 
 static int shmem_symlink(struct inode * dir, struct dentry *dentry, const char * symname)
 {
+	int error;
 	int len;
 	struct inode *inode;
 	struct page *page;
@@ -1296,11 +1274,11 @@
 			iput(inode);
 			return -ENOMEM;
 		}
-		page = shmem_getpage_locked(info, inode, 0);
-		if (IS_ERR(page)) {
+		error = shmem_getpage(inode, 0, &page);
+		if (error) {
 			vm_unacct_memory(VM_ACCT(1));
 			iput(inode);
-			return PTR_ERR(page);
+			return error;
 		}
 		inode->i_op = &shmem_symlink_inode_operations;
 		spin_lock (&shmem_ilock);
@@ -1332,27 +1310,26 @@
 
 static int shmem_readlink(struct dentry *dentry, char *buffer, int buflen)
 {
-	struct page * page;
+	struct page *page;
 	int res = shmem_getpage(dentry->d_inode, 0, &page);
-
 	if (res)
 		return res;
-
-	res = vfs_readlink(dentry,buffer,buflen, kmap(page));
+	res = vfs_readlink(dentry, buffer, buflen, kmap(page));
 	kunmap(page);
+	unlock_page(page);
 	page_cache_release(page);
 	return res;
 }
 
 static int shmem_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
-	struct page * page;
+	struct page *page;
 	int res = shmem_getpage(dentry->d_inode, 0, &page);
 	if (res)
 		return res;
-
 	res = vfs_follow_link(nd, kmap(page));
 	kunmap(page);
+	unlock_page(page);
 	page_cache_release(page);
 	return res;
 }


  parent reply	other threads:[~2002-10-01 21:42 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2002-10-01 21:44 [PATCH] tmpfs 1/9 shmem_vm_writeback Hugh Dickins
2002-10-01 21:46 ` [PATCH] tmpfs 2/9 partial shmem_holdpage Hugh Dickins
2002-10-01 21:47 ` [PATCH] tmpfs 3/9 remove info->sem Hugh Dickins
2002-10-01 21:48 ` Hugh Dickins [this message]
2002-10-01 21:50 ` [PATCH] tmpfs 5/9 shmem_free_block alloced Hugh Dickins
2002-10-01 21:51 ` [PATCH] tmpfs 6/9 highmem metadata Hugh Dickins
2002-10-01 21:53 ` [PATCH] tmpfs 7/9 shmem_swp_set nr_swapped Hugh Dickins
2002-10-01 21:54 ` [PATCH] tmpfs 8/9 misc trivia Hugh Dickins
2002-10-01 21:55 ` [PATCH] tmpfs 9/9 whitespace only Hugh Dickins

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=Pine.LNX.4.44.0210012247520.2602-100000@localhost.localdomain \
    --to=hugh@veritas.com \
    --cc=akpm@digeo.com \
    --cc=cr@sap.com \
    --cc=linux-kernel@vger.kernel.org \
    /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;
as well as URLs for NNTP newsgroup(s).