summary refs log tree commit diff
path: root/fs/f2fs
diff options
context:
space:
mode:
authorJaegeuk Kim <jaegeuk@kernel.org>2015-04-15 13:49:55 -0700
committerJaegeuk Kim <jaegeuk@kernel.org>2015-04-16 09:45:40 -0700
commitfeb7cbb079e63ebb7c0bd7022d2ba9c1dd15c69b (patch)
tree279b5dcd63730d042ef2cda231d115f703fa14e9 /fs/f2fs
parentd0cae97cb600d84a7e00df6f83ab3b2f60d8d7f7 (diff)
downloadlinux-feb7cbb079e63ebb7c0bd7022d2ba9c1dd15c69b.tar.gz
f2fs: avoid abnormal behavior on broken symlink
When f2fs_symlink was triggered and checkpoint was done before syncing its
link path, f2fs can get broken symlink like "xxx -> \0\0\0".
This incurs abnormal path_walk by VFS.

Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Diffstat (limited to 'fs/f2fs')
-rw-r--r--fs/f2fs/namei.c20
1 files changed, 19 insertions, 1 deletions
diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c
index 9f0eec4677fe..407dde3d7a92 100644
--- a/fs/f2fs/namei.c
+++ b/fs/f2fs/namei.c
@@ -14,6 +14,7 @@
 #include <linux/sched.h>
 #include <linux/ctype.h>
 #include <linux/dcache.h>
+#include <linux/namei.h>
 
 #include "f2fs.h"
 #include "node.h"
@@ -295,6 +296,23 @@ fail:
 	return err;
 }
 
+static void *f2fs_follow_link(struct dentry *dentry, struct nameidata *nd)
+{
+	struct page *page;
+
+	page = page_follow_link_light(dentry, nd);
+	if (IS_ERR(page))
+		return page;
+
+	/* this is broken symlink case */
+	if (*nd_get_link(nd) == 0) {
+		kunmap(page);
+		page_cache_release(page);
+		return ERR_PTR(-ENOENT);
+	}
+	return page;
+}
+
 static int f2fs_symlink(struct inode *dir, struct dentry *dentry,
 					const char *symname)
 {
@@ -790,7 +808,7 @@ const struct inode_operations f2fs_dir_inode_operations = {
 
 const struct inode_operations f2fs_symlink_inode_operations = {
 	.readlink       = generic_readlink,
-	.follow_link    = page_follow_link_light,
+	.follow_link    = f2fs_follow_link,
 	.put_link       = page_put_link,
 	.getattr	= f2fs_getattr,
 	.setattr	= f2fs_setattr,