aboutsummaryrefslogtreecommitdiffstats
path: root/fs/namei.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/namei.c')
-rw-r--r--fs/namei.c34
1 files changed, 26 insertions, 8 deletions
diff --git a/fs/namei.c b/fs/namei.c
index 51cfc9c3ed00..98dc2e134362 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -104,7 +104,7 @@
*/
/*
* [Sep 2001 AV] Single-semaphore locking scheme (kudos to David Holland)
- * implemented. Let's see if raised priority of ->s_vfs_rename_sem gives
+ * implemented. Let's see if raised priority of ->s_vfs_rename_mutex gives
* any extra contention...
*/
@@ -1423,7 +1423,7 @@ struct dentry *lock_rename(struct dentry *p1, struct dentry *p2)
return NULL;
}
- down(&p1->d_inode->i_sb->s_vfs_rename_sem);
+ mutex_lock(&p1->d_inode->i_sb->s_vfs_rename_mutex);
for (p = p1; p->d_parent != p; p = p->d_parent) {
if (p->d_parent == p2) {
@@ -1451,7 +1451,7 @@ void unlock_rename(struct dentry *p1, struct dentry *p2)
mutex_unlock(&p1->d_inode->i_mutex);
if (p1 != p2) {
mutex_unlock(&p2->d_inode->i_mutex);
- up(&p1->d_inode->i_sb->s_vfs_rename_sem);
+ mutex_unlock(&p1->d_inode->i_sb->s_vfs_rename_mutex);
}
}
@@ -1629,6 +1629,12 @@ do_last:
goto exit;
}
+ if (IS_ERR(nd->intent.open.file)) {
+ mutex_unlock(&dir->d_inode->i_mutex);
+ error = PTR_ERR(nd->intent.open.file);
+ goto exit_dput;
+ }
+
/* Negative dentry, just create the file */
if (!path.dentry->d_inode) {
if (!IS_POSIXACL(dir->d_inode))
@@ -2278,17 +2284,17 @@ asmlinkage long sys_link(const char __user *oldname, const char __user *newname)
* a) we can get into loop creation. Check is done in is_subdir().
* b) race potential - two innocent renames can create a loop together.
* That's where 4.4 screws up. Current fix: serialization on
- * sb->s_vfs_rename_sem. We might be more accurate, but that's another
+ * sb->s_vfs_rename_mutex. We might be more accurate, but that's another
* story.
* c) we have to lock _three_ objects - parents and victim (if it exists).
* And that - after we got ->i_mutex on parents (until then we don't know
* whether the target exists). Solution: try to be smart with locking
* order for inodes. We rely on the fact that tree topology may change
- * only under ->s_vfs_rename_sem _and_ that parent of the object we
+ * only under ->s_vfs_rename_mutex _and_ that parent of the object we
* move will be locked. Thus we can rank directories by the tree
* (ancestors first) and rank all non-directories after them.
* That works since everybody except rename does "lock parent, lookup,
- * lock child" and rename is under ->s_vfs_rename_sem.
+ * lock child" and rename is under ->s_vfs_rename_mutex.
* HOWEVER, it relies on the assumption that any object with ->lookup()
* has no more than 1 dentry. If "hybrid" objects will ever appear,
* we'd better make sure that there's no link(2) for them.
@@ -2622,16 +2628,27 @@ int __page_symlink(struct inode *inode, const char *symname, int len,
int err = -ENOMEM;
char *kaddr;
+retry:
page = find_or_create_page(mapping, 0, gfp_mask);
if (!page)
goto fail;
err = mapping->a_ops->prepare_write(NULL, page, 0, len-1);
+ if (err == AOP_TRUNCATED_PAGE) {
+ page_cache_release(page);
+ goto retry;
+ }
if (err)
goto fail_map;
kaddr = kmap_atomic(page, KM_USER0);
memcpy(kaddr, symname, len-1);
kunmap_atomic(kaddr, KM_USER0);
- mapping->a_ops->commit_write(NULL, page, 0, len-1);
+ err = mapping->a_ops->commit_write(NULL, page, 0, len-1);
+ if (err == AOP_TRUNCATED_PAGE) {
+ page_cache_release(page);
+ goto retry;
+ }
+ if (err)
+ goto fail_map;
/*
* Notice that we are _not_ going to block here - end of page is
* unmapped, so this will only try to map the rest of page, see
@@ -2641,7 +2658,8 @@ int __page_symlink(struct inode *inode, const char *symname, int len,
*/
if (!PageUptodate(page)) {
err = mapping->a_ops->readpage(NULL, page);
- wait_on_page_locked(page);
+ if (err != AOP_TRUNCATED_PAGE)
+ wait_on_page_locked(page);
} else {
unlock_page(page);
}