From patchwork Thu Feb 13 07:07:17 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Zheng Liu X-Patchwork-Id: 319895 Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id B38212C00B5 for ; Thu, 13 Feb 2014 18:02:25 +1100 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751831AbaBMHCY (ORCPT ); Thu, 13 Feb 2014 02:02:24 -0500 Received: from mail-pb0-f53.google.com ([209.85.160.53]:33214 "EHLO mail-pb0-f53.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751246AbaBMHCX (ORCPT ); Thu, 13 Feb 2014 02:02:23 -0500 Received: by mail-pb0-f53.google.com with SMTP id md12so10352558pbc.40 for ; Wed, 12 Feb 2014 23:02:23 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id; bh=V8Ui+keMBKGuJj+q6fkIF9d83t+aVbu0nBOHxV5QWOc=; b=Oxxvysj43cFLe1oqX9tqbCMC6tNTeYhntGQkeEqq22qijRdOn6920sbNIxEOdOQxlu fAgOf61PL52e0ynb1NI3EJMZ4QMlYsfZnbnOFsXNCWnIWibJV+09fmP4O96qikMKlK4w kw+ye4COkPUSWwYLlyEr2D+tVzgykMkjiCwk2dU/50UEYgylUcU83+0FaB3+SjbFAQva 8/Eq16CynrS1iN83lK3YNcnJgVueobiMz4cm3Ba0HyvHdWOiJQLIUU3IjTxdaaODOxiY bjt3Br6aORpr+taigtRlaXDe/xpjiIh7VIhDQ0e8RlmtgARx54Uxr6z9U7E4nOutnmJh 5yDg== X-Received: by 10.68.198.97 with SMTP id jb1mr56256182pbc.104.1392274942963; Wed, 12 Feb 2014 23:02:22 -0800 (PST) Received: from alpha.taobao.ali.com ([182.92.253.3]) by mx.google.com with ESMTPSA id lh13sm7342549pab.4.2014.02.12.23.02.17 for (version=TLSv1 cipher=RC4-SHA bits=128/128); Wed, 12 Feb 2014 23:02:21 -0800 (PST) From: Zheng Liu To: linux-ext4@vger.kernel.org Cc: Ian Nartowicz , Tao Ma , Andreas Dilger , "Theodore Ts'o" , Zheng Liu Subject: [RFC][PATCH] ext4: handle fast symlink properly with inline_data Date: Thu, 13 Feb 2014 15:07:17 +0800 Message-Id: <1392275237-6998-1-git-send-email-wenqing.lz@taobao.com> X-Mailer: git-send-email 1.7.9.7 Sender: linux-ext4-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-ext4@vger.kernel.org From: Zheng Liu This commit tries to fix a bug that we can't read fast symlink properly. The following script can hit the bug. #!/bin/bash cd ${MNT} filename=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 rm -rf test mkdir test cd test echo "hello" >$filename ln -s $filename symlinkfile cd sudo umount /mnt/sda1 sudo mount -t ext4 /dev/sda1 /mnt/sda1 readlink /mnt/sda1/test/symlinkfile The root cause is that we don't handle inline data in ext4_follow_link. In this commit it makes ext4_follow_link handle inline data properly. Reported-by: Ian Nartowicz Cc: Ian Nartowicz Cc: Tao Ma Cc: Andreas Dilger Cc: "Theodore Ts'o" Signed-off-by: Zheng Liu --- Hi all, I am not sure whether or not we need to enable inline_data for a fast symlink inode. Obviously, it brings a benefit that after enabling inline_data feature for a fast symlink we can get more space to store the path. But it seems that the original patch doesn't want to do this Another solution for fixing this bug is to disable inline_data for a fast symlink. Any comment? Thanks, - Zheng fs/ext4/ext4.h | 2 ++ fs/ext4/inline.c | 5 ++--- fs/ext4/symlink.c | 46 +++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 47 insertions(+), 6 deletions(-) diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index ece5556..d943f9c 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -2589,6 +2589,8 @@ extern int ext4_has_inline_data(struct inode *inode); extern int ext4_get_inline_size(struct inode *inode); extern int ext4_get_max_inline_size(struct inode *inode); extern int ext4_find_inline_data_nolock(struct inode *inode); +extern int ext4_read_inline_data(struct inode *inode, void *buffer, + unsigned int len, struct ext4_iloc *iloc); extern void ext4_write_inline_data(struct inode *inode, struct ext4_iloc *iloc, void *buffer, loff_t pos, diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c index 82edf5b..6dda3c4 100644 --- a/fs/ext4/inline.c +++ b/fs/ext4/inline.c @@ -165,9 +165,8 @@ out: return error; } -static int ext4_read_inline_data(struct inode *inode, void *buffer, - unsigned int len, - struct ext4_iloc *iloc) +int ext4_read_inline_data(struct inode *inode, void *buffer, + unsigned int len, struct ext4_iloc *iloc) { struct ext4_xattr_entry *entry; struct ext4_xattr_ibody_header *header; diff --git a/fs/ext4/symlink.c b/fs/ext4/symlink.c index ff37119..66b62f8 100644 --- a/fs/ext4/symlink.c +++ b/fs/ext4/symlink.c @@ -25,9 +25,48 @@ static void *ext4_follow_link(struct dentry *dentry, struct nameidata *nd) { - struct ext4_inode_info *ei = EXT4_I(dentry->d_inode); - nd_set_link(nd, (char *) ei->i_data); - return NULL; + struct inode *inode = dentry->d_inode; + struct ext4_inode_info *ei = EXT4_I(inode); + struct ext4_iloc iloc; + char *inline_data = NULL; + int ret, inline_size = 0; + int error; + + if (!ext4_has_inline_data(inode)) { + nd_set_link(nd, (char *) ei->i_data); + return NULL; + } + + error = ext4_get_inode_loc(inode, &iloc); + if (error) + return ERR_PTR(error); + + down_read(&ei->xattr_sem); + if (!ext4_has_inline_data(inode)) { + up_read(&ei->xattr_sem); + return ERR_PTR(-EAGAIN); + } + inline_size = ext4_get_inline_size(inode); + inline_data = kmalloc(inline_size + 1, GFP_NOFS); + if (!inline_data) { + up_read(&ei->xattr_sem); + return ERR_PTR(-ENOMEM); + } + + ret = ext4_read_inline_data(inode, inline_data, inline_size, &iloc); + up_read(&ei->xattr_sem); + if (ret < 0) + return ERR_PTR(-EIO); + + inline_data[inline_size] = '\0'; + nd_set_link(nd, inline_data); + return inline_data; +} + +static void ext4_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie) +{ + if (cookie) + kfree(cookie); } const struct inode_operations ext4_symlink_inode_operations = { @@ -44,6 +83,7 @@ const struct inode_operations ext4_symlink_inode_operations = { const struct inode_operations ext4_fast_symlink_inode_operations = { .readlink = generic_readlink, .follow_link = ext4_follow_link, + .put_link = ext4_put_link, .setattr = ext4_setattr, .setxattr = generic_setxattr, .getxattr = generic_getxattr,