From patchwork Thu Apr 3 05:46:52 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: NeilBrown X-Patchwork-Id: 3931461 Return-Path: X-Original-To: patchwork-linux-nfs@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 913B89F334 for ; Thu, 3 Apr 2014 05:47:25 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id EB3CF20218 for ; Thu, 3 Apr 2014 05:47:24 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 2DC0D20204 for ; Thu, 3 Apr 2014 05:47:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933338AbaDCFrD (ORCPT ); Thu, 3 Apr 2014 01:47:03 -0400 Received: from cantor2.suse.de ([195.135.220.15]:55277 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S933021AbaDCFrB (ORCPT ); Thu, 3 Apr 2014 01:47:01 -0400 Received: from relay1.suse.de (charybdis-ext.suse.de [195.135.220.254]) by mx2.suse.de (Postfix) with ESMTP id 54775ACE0 for ; Thu, 3 Apr 2014 05:46:59 +0000 (UTC) Date: Thu, 3 Apr 2014 16:46:52 +1100 From: NeilBrown To: NFS Subject: Should exportfs/mountd cope with case-insensitive directory names. Message-ID: <20140403164652.5d7770ad@notabene.brown> X-Mailer: Claws Mail 3.9.2 (GTK+ 2.24.22; x86_64-suse-linux-gnu) Mime-Version: 1.0 Sender: linux-nfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org X-Spam-Status: No, score=-7.4 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, T_TVD_MIME_EPI, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Hi, I came across an interesting issue recently. Suppose you have a filesystem which supports case-insensitive file names (like VFAT, but in this particular case 'NSS' - Novell Storage Services). And support you export some subdirectory (or sub-volume) using a non-canonical name. i.e. you "mkdir /path/export", the put "/path/EXPORT" in /etc/exports and mount server:/path/EXPORT from some client. This all works until the export cache times out and the kernel asks mountd if "/path/export" is exported. mountd says "no" and suddenly all accesses fail. I don't think much of case-insensitive file names, but I suspect we should either make this work, it issue a warning as to why it is failing. A simple work around is to export the canonical name and use it when mounting. But if the sysadmin doesn't know they need to, they are unlikely to guess. I don't think there is any API to test if a name is canonical, or to get the canonical name, so I cannot see any way in advance to see if this problem situation has arisen. So the only option I can think of is to fix it. The following patch (or something much like it for an older nfs-utils) seems to do the trick. What do people think? Is this a reasonable thing to do? Is it likely to have negative consequences that I haven't thought of? Thanks, NeilBrown diff --git a/utils/mountd/cache.c b/utils/mountd/cache.c index 9a1bb2767ac2..2d91db76b867 100644 --- a/utils/mountd/cache.c +++ b/utils/mountd/cache.c @@ -377,6 +377,28 @@ static char *next_mnt(void **v, char *p) return me->mnt_dir; } +static int same_path(char *child, char *parent, int len) +{ + static char p[PATH_MAX]; + struct stat sc, sp; + if (len <= 0) + len = strlen(child); + strncpy(p, child, len); + p[len] = 0; + if (strcmp(p, parent) == 0) + return 1; + + if (lstat(p, &sc) != 0) + return 0; + if (lstat(parent, &sp) != 0) + return 0; + if (sc.st_dev != sp.st_dev) + return 0; + if (sc.st_ino != sp.st_ino) + return 0; + return 1; +} + static int is_subdirectory(char *child, char *parent) { /* Check is child is strictly a subdirectory of @@ -387,7 +409,7 @@ static int is_subdirectory(char *child, char *parent) if (strcmp(parent, "/") == 0 && child[1] != 0) return 1; - return (strncmp(child, parent, l) == 0 && child[l] == '/'); + return (same_path(child, parent, l) && child[l] == '/'); } static int path_matches(nfs_export *exp, char *path) @@ -396,7 +418,7 @@ static int path_matches(nfs_export *exp, char *path) * exact match, or does the export have CROSSMOUNT, and path * is a descendant? */ - return strcmp(path, exp->m_export.e_path) == 0 + return same_path(path, exp->m_export.e_path, 0) || ((exp->m_export.e_flags & NFSEXP_CROSSMOUNT) && is_subdirectory(path, exp->m_export.e_path)); }