From patchwork Thu Apr 26 22:34:49 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Sandeen X-Patchwork-Id: 155336 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 CC6E9B6FC2 for ; Fri, 27 Apr 2012 08:34:56 +1000 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755254Ab2DZWez (ORCPT ); Thu, 26 Apr 2012 18:34:55 -0400 Received: from mx1.redhat.com ([209.132.183.28]:29137 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752077Ab2DZWey (ORCPT ); Thu, 26 Apr 2012 18:34:54 -0400 Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id q3QMYpxr026529 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Thu, 26 Apr 2012 18:34:51 -0400 Received: from liberator.sandeen.net (ovpn01.gateway.prod.ext.phx2.redhat.com [10.5.9.1]) by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id q3QMYnV6015344 (version=TLSv1/SSLv3 cipher=DHE-RSA-CAMELLIA256-SHA bits=256 verify=NO); Thu, 26 Apr 2012 18:34:50 -0400 Message-ID: <4F99CD89.7070407@redhat.com> Date: Thu, 26 Apr 2012 17:34:49 -0500 From: Eric Sandeen User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:11.0) Gecko/20120327 Thunderbird/11.0.1 MIME-Version: 1.0 To: ext4 development , Bernd Schubert Subject: [PATCH] ext4: call vfs llseek code from ext4_dir_llseek References: <4F984F22.10203@redhat.com> <4F99904F.3040000@redhat.com> In-Reply-To: <4F99904F.3040000@redhat.com> X-Enigmail-Version: 1.4.1 X-Scanned-By: MIMEDefang 2.68 on 10.5.11.22 Sender: linux-ext4-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-ext4@vger.kernel.org ext4_dir_llseek can call the vfs llseek functions and get all the the functionality needed by the NFS server. For htree directories, we call the _sized() variant with the maximum allowable hash value. For non-htree, we can call ext4_file_llseek, which will sort out the maximum allowable offset based on whether the dir is extent based or not. This does lose the special SEEK_END handling of going to the max hash size, but I know of no usecase for that and no bugs, despite SEEK_END going to i_size and not the hash EOF for many years now, so I don't think the cut & paste is warranted. The vfs function can be expanded if it's critical. This also returns dir llseek to it's (mostly) lockless implementation. Signed-off-by: Eric Sandeen --- -- To unsubscribe from this list: send the line "unsubscribe linux-ext4" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c index b867862..faebc89 100644 --- a/fs/ext4/dir.c +++ b/fs/ext4/dir.c @@ -312,74 +312,26 @@ static inline loff_t ext4_get_htree_eof(struct file *filp) /* - * ext4_dir_llseek() based on generic_file_llseek() to handle both - * non-htree and htree directories, where the "offset" is in terms - * of the filename hash value instead of the byte offset. + * ext4_dir_llseek() calls generic_file_llseek_size to handle htree + * directories, where the "offset" is in terms of the filename hash + * value instead of the byte offset. * - * NOTE: offsets obtained *before* ext4_set_inode_flag(dir, EXT4_INODE_INDEX) - * will be invalid once the directory was converted into a dx directory + * Because we may return a 64-bit hash that is well beyond offset limits, + * we need to pass the max hash as the maximum allowable offset in + * the htree directory case. + * + * For non-htree, ext4_llseek already chooses the proper max offset. */ loff_t ext4_dir_llseek(struct file *file, loff_t offset, int origin) { struct inode *inode = file->f_mapping->host; - loff_t ret = -EINVAL; int dx_dir = is_dx_dir(inode); - mutex_lock(&inode->i_mutex); - - /* NOTE: relative offsets with dx directories might not work - * as expected, as it is difficult to figure out the - * correct offset between dx hashes */ - - switch (origin) { - case SEEK_END: - if (unlikely(offset > 0)) - goto out_err; /* not supported for directories */ - - /* so only negative offsets are left, does that have a - * meaning for directories at all? */ - if (dx_dir) - offset += ext4_get_htree_eof(file); - else - offset += inode->i_size; - break; - case SEEK_CUR: - /* - * Here we special-case the lseek(fd, 0, SEEK_CUR) - * position-querying operation. Avoid rewriting the "same" - * f_pos value back to the file because a concurrent read(), - * write() or lseek() might have altered it - */ - if (offset == 0) { - offset = file->f_pos; - goto out_ok; - } - - offset += file->f_pos; - break; - } - - if (unlikely(offset < 0)) - goto out_err; - - if (!dx_dir) { - if (offset > inode->i_sb->s_maxbytes) - goto out_err; - } else if (offset > ext4_get_htree_eof(file)) - goto out_err; - - /* Special lock needed here? */ - if (offset != file->f_pos) { - file->f_pos = offset; - file->f_version = 0; - } - -out_ok: - ret = offset; -out_err: - mutex_unlock(&inode->i_mutex); - - return ret; + if (likely(dx_dir)) + return generic_file_llseek_size(file, offset, origin, + ext4_get_htree_eof(file)); + else + return ext4_llseek(file, offset, origin); } /*