Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752573AbdFOP2Z (ORCPT ); Thu, 15 Jun 2017 11:28:25 -0400 Received: from mx144.netapp.com ([216.240.21.25]:38145 "EHLO mx144.netapp.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752137AbdFOP2U (ORCPT ); Thu, 15 Jun 2017 11:28:20 -0400 X-IronPort-AV: E=Sophos;i="5.39,343,1493708400"; d="scan'208";a="199670983" Authentication-Results: vger.kernel.org; dkim=none (message not signed) header.d=none;vger.kernel.org; dmarc=none action=none header.from=Netapp.com; From: Anna Schumaker Subject: Re: [PATCH 24/27] NFS: Add fs_context support. [ver #5] To: David Howells , , CC: , , , , References: <149745330648.10897.9605870130502083184.stgit@warthog.procyon.org.uk> <149745353411.10897.420622216132883178.stgit@warthog.procyon.org.uk> Message-ID: <12f4fc99-6e4c-7b38-bfcc-5539e25c3b76@Netapp.com> Date: Thu, 15 Jun 2017 11:28:08 -0400 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.1.1 MIME-Version: 1.0 In-Reply-To: <149745353411.10897.420622216132883178.stgit@warthog.procyon.org.uk> Content-Type: text/plain; charset=utf-8 Content-Language: en-US Content-Transfer-Encoding: 7bit X-Originating-IP: [99.9.112.69] X-ClientProxiedBy: MWHPR08CA0041.namprd08.prod.outlook.com (10.173.236.15) To BN6PR06MB2467.namprd06.prod.outlook.com (10.173.22.8) X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: BN6PR06MB2467: X-MS-Office365-Filtering-Correlation-Id: a8e45e91-6356-4795-4435-08d4b40323ff X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:(22001)(201703131423075)(201703031133081);SRVR:BN6PR06MB2467; X-Microsoft-Exchange-Diagnostics: 1;BN6PR06MB2467;3:BPz/fKgyxw9WO4kxBea8TsbfGvTtgOtpdptlsDXGLy3nPYXeB4802FYqu6/AfOZqral2FPTdYS9nZvsMtyRx+VxStZbIY2cRRijR4L6QAMAb5GW0XaIs6z9/OdKYO25cDseZEPCvTQWo/ML/7NyNiRZmgMTxZvE8s6O9yGHmlv7Kwy3iwljMP74WcCJa0H21kX5Dl6mQTG9Ccgk9NdTFSIWztI07HW/dnJ8I7rkO+FtFh565Q6UFEzJKnFYjVOQCEraLLwkSD+mmyB9pOD0ntMxJRFW85WF8m28GJUKbmRAehD0W8EN1sDheiykU878w3GeiJt07obHsxVuKWy7HDg==;25:a0BBP1PDQdaeg6DmEbhqn3T7+M5m6fs22FwkOqtZLXyhOTAPpuszGfw91EIW/S1817t5woEFaJqeUOK4rgNXUfLq15B1Q06D69gK91+9109GN9WAXEhytY4M6XMJ7wgOVusfZ9RdWvnG3qdAOIid59AjOiTuuEVdWd9vpiFGtMKbgXeaq26PEt5+yUGDq99T7dwOQlhsgpp6+nPDha4NTrtl7K3KSADxN0Tzw2w1olNb+frEAcP4JuejtIgBwumyRWL6m5YRtzvMBZKLZyqGmEp83iwPfz+1rPE5YHBQEWrW2XVqJwkJFBnEZCLuYwPX06DV6SMv0vxPNNUr1KA95E2e+KFFWp6AFz5375rRJyBWTP4+uZ87eSERFEjgxU99KxEHsDaqOa9Jxw7WBT4k0E7sMZ/sxTPT+BaE2L9ZCKahcPZ4YabjLYTmZ1gp3JbAOKFQ8/YUN3Qd/vHcU/lmSN/V4lC5E0VaAte7Z2vvwxI= X-Microsoft-Exchange-Diagnostics: 1;BN6PR06MB2467;31:vby2Xtn1uFfVYItYOO+imrzz37bRLbR5Y/Oyt08NUggtRNquf5SDIbTfT6WLB4lIX7hHa5a1bxOGWXlaKh15BtBf9rbRrevoTbB3War3oQLiydssKIcu3maUHgMnDh8U1MS5+5G9mFcTwb9JhoKijWOHZZgR32HZwRKq9Tb+FX3AB3pmmji1/DOld1+2Wkn2sSyEMumX1cmk1DbuF9hb48C5TqlWksxwaTi/bcSz+OTmItEu4xy0NIFgPS0K335y;20:lyB/fFaF6Mq2uYhTbr9j24+9wmjMzxw6pxJRP9QmLVpFub4Su1hTz4El82xKb14FgxC4BaYW9iuPr9irV2fZz3nfpsjSPLspElJY4WC5nZspvMUVJp8hf8hz38IdlCGMuJX1G9PBa+tm5IJejHObjLfjnzuU3n8uwYn5QaS6KbfRH8dvHYgoxb9NiyhFtwJ4+UNeyvAMnOTKBdg2LjK6EifaviLUuqGkpCMYLTn9Bqs4QkTBsZbNAVzoROf9l3sAK+BN1dr3qhxefOtQQZ4xb5zeG5cuQEK72cCbrW+5FH6adBZW6Mzpeu/rnsKK4glDb6PFASANnPJg8khtHCwOcF6RlNWesuVLIWuZoMUMQZWoUlQUi1V1w4QHGm1x694IuvDPZ9vCxaRa7sDCCbQCLH2UkLXnjbP3ZHuqSsb/IVP+2Uxb81KpLZd7iw9dhgj2WgyaumAl6izO22W42h35YaiHc37kj482f0OkAyqRRBULhisKnP7wVKZ1cl+Qi4sq X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:(158342451672863)(192374486261705)(9452136761055)(150554046322364); X-Exchange-Antispam-Report-CFA-Test: BCL:0;PCL:0;RULEID:(100000700101)(100105000095)(100000701101)(100105300095)(100000702101)(100105100095)(6040450)(601004)(2401047)(8121501046)(5005006)(100000703101)(100105400095)(10201501046)(3002001)(93006095)(93001095)(6055026)(6041248)(20161123564025)(20161123555025)(20161123560025)(20161123562025)(20161123558100)(201703131423075)(201702281528075)(201703061421075)(201703061406153)(6072148)(100000704101)(100105200095)(100000705101)(100105500095);SRVR:BN6PR06MB2467;BCL:0;PCL:0;RULEID:(100000800101)(100110000095)(100000801101)(100110300095)(100000802101)(100110100095)(100000803101)(100110400095)(100000804101)(100110200095)(100000805101)(100110500095);SRVR:BN6PR06MB2467; X-Microsoft-Exchange-Diagnostics: =?utf-8?B?MTtCTjZQUjA2TUIyNDY3OzQ6ZFowMkwreHAwK2ZzREZsQktKZnJXbmJ1UTNS?= =?utf-8?B?akhIQVFQVk4zRk96eWlhbWhuWjVZTlhWRk5lMnBrSTFnQVZQK2ozV0E5KzFY?= =?utf-8?B?TEtLQzM1TDVwQ1RmVWdmeFlvVktHSCtVWGJzWGN1K3RaY3ZuYnM5RHRvQTI3?= =?utf-8?B?Q1VvdTBQYUVFUnZCZnduRVJlSlgrN2lOUEVuNHBXVXczTHpRZTBXM0x3NHBw?= =?utf-8?B?L0IwOFZTNFBSZWpsRm8yMHUzOW5WcTNySVRVNEF5czhONVdEK3hlZnNucE9T?= =?utf-8?B?Z1l2WWlqM040alV6WHlFS3ZCdmtQR2JqRFV0dW5oM1JtbnNjdkxaSjR1d1hZ?= =?utf-8?B?NDY1NWFKemNoVTM5T3J4ZEhZRDg2L2hPcUZBY0ljR0ZmNWI1OXNITDlvUDJV?= =?utf-8?B?ZW9kUThmZksxejFDRFZ5T1JhcVZvd0FlOWJEYlVxbmErZlZnYThMU1g5Tnl2?= =?utf-8?B?UUNqb0NZdm1iK3B3dmxZL2xvQnJ5czRrSnF4N1FPS2lLME0zelo0QzM4Ymo2?= =?utf-8?B?T3JFeXY5OXpiYWJxUjVUT28yUllweUJObHU1TWVXVEdBNHFzNmJYOE5mMFE5?= =?utf-8?B?b0ttUVBlanRUMTJUd29vRUUwWldaajZmVzZTYVRwbklOYmNxazdrbEVrU3JN?= =?utf-8?B?eHYvbFFJUVJSRkhRbGpFc0lYZ004QjNSRmc5cFNHTEdiVFJKTGNQSEYwSmdZ?= =?utf-8?B?eHRTWWNHdTZsUTRTSVd0VU5OdEpXa2R4ZmdvVnpxemV1WmkybE9BZkJvSmFO?= =?utf-8?B?eExXcTVxY29MQUt1TVlmdDIzZkczbXZOcGxORFhYUU81Vnl5MGtjWGljVHVq?= =?utf-8?B?ZERySU5OTFZUTk9mMVBOT0pka21UaXY1TVA2RTZjMVVEMlFaWDhwYy9nOUxW?= =?utf-8?B?WUNPYTExMjRhNEh1cDd3ZmZOMTBTOU0xekRPOUVhVlhaRlU5bDFFRkdKbXhP?= =?utf-8?B?YkhreG5pL2tubTFBakE4NW1pUTR2bEpZUFFuWm91a3lKeWdsZmp5S1dZQTVQ?= =?utf-8?B?aVBxWmxYOWo3aW1FbitabHdBbU5UeFZtbkF1TXJqRVJOVllOUlFKQ1dMM01n?= =?utf-8?B?UEVKMEF5Umd0UzlLQmpxZmxBSFBJNGRDN1FXZk1KbDJsaTgrMHBPdmFFUHJE?= =?utf-8?B?aWpVNWxGUXB5YVFCNDkwUDlaRmRnbmo4UWVUTk95SklsbnRsYkRlUTZTdGVW?= =?utf-8?B?K2tuczNGbnN2WU0wUnFlTDFTUGsyNElUQlJ0ejNnQnlqZVVyUFdDYXFQaHFq?= =?utf-8?B?OTBGc0NTZEk0Q2pkczJoZWV0YlVvS085MFF3Zzl3VktwQisxUEF0OHl1VHVD?= =?utf-8?B?eGZrYXNYWExEVzg3bWVUM09xaEw0TVgzekhVRkg1aUJJRmJERENLNi83SkhR?= =?utf-8?B?d1BUb2RaMjhibkc2WVAvSFlWMzd0YXJyb1NzcVIzRkZtTnczV1p2WEkvMytk?= =?utf-8?B?ZDNFZHI0aUZmWmtZK2lzKzI1S3Z6L2JIay9IVW02MDRxaE1NWU1hTUJyYXF4?= =?utf-8?B?bEpvQWxqQm1QbFpoWGg0TGs3WStUSkpTRTJ2TitHSHRabzhkRzdFdDM3VVNu?= =?utf-8?B?VDBaWjJleVA3NWFoOTZKUHk5aWwwd3pKWWgvTkV2a2l1OS93MlF1OGFDQndz?= =?utf-8?B?WEY3Y1V4RHIwaHB1RnFNRFduaW5CaFM5ZXNHdUhQblkya3BXQmNHVUJ2ak5F?= =?utf-8?B?VVBZYlNjYU13YUdRVHJxV3hmbnYxYnE4dHhOc3lZOTB2L2pPNFZTSlFtaWxV?= =?utf-8?Q?4xMeG5YCUlH+KP06eQF7/7H2/+OcU4m4HNi4=3D?= X-Forefront-PRVS: 0339F89554 X-Forefront-Antispam-Report: SFV:NSPM;SFS:(10009020)(4630300001)(6009001)(39450400003)(39850400002)(39400400002)(39410400002)(39840400002)(24454002)(377454003)(54094003)(6246003)(53946003)(4001350100001)(38730400002)(6306002)(6512007)(230700001)(5890100001)(189998001)(42186005)(50986999)(76176999)(81166006)(50466002)(8676002)(54356999)(110136004)(31686004)(2906002)(53546009)(53936002)(25786009)(53416004)(4326008)(966005)(2950100002)(83506001)(7736002)(6116002)(3846002)(229853002)(6486002)(6666003)(6506006)(305945005)(86362001)(575784001)(5660300001)(72206003)(31696002)(33646002)(66066001)(23676002)(36756003)(47776003)(478600001)(559001)(579004);DIR:OUT;SFP:1101;SCL:1;SRVR:BN6PR06MB2467;H:gouda.nowheycreamery.com;FPR:;SPF:None;MLV:sfv;LANG:en; X-Microsoft-Exchange-Diagnostics: =?utf-8?B?MTtCTjZQUjA2TUIyNDY3OzIzOnQ0d2lBclNob0tLcEVpNWlPbjBKSUpTdVFM?= =?utf-8?B?bVNHeEYzMlVrY2VFN21Pa0FiOEo4eVBQdFA3ZlNQa29hM2Y5WndFUGExazhn?= =?utf-8?B?a2c2Z0dFd25kMkM1SjNsdHcvaW1JSTZiMXMrTVpPTHV5K3hHZW5hZTZQQm1Y?= =?utf-8?B?Vi9PcXAxdEpCYmJFdytuU0R0SnJGY3ZxQVM3OFNYNzV2Tk1OR0hDdUxyM21E?= =?utf-8?B?Mks0Mnd2am9LSTJ6anpMbGxjV1VsWk5UVVBKWlpxR2dNcFJjNHRZUEw2WFRt?= =?utf-8?B?cVN4ZkhsTUtuY1EwUHpneVpmbnNqUTlmUG1zRDV2Vi92N0FCeElZTTUrMXly?= =?utf-8?B?QjVSdVhBMzhSOHZSWDBQamNIL0R1R1VqOS9TZ3huc3pmaW9Fakl4R1VFdVJX?= =?utf-8?B?cnhMaHYrRG0zL0sycm1BMXQ4WVRNRHhRRWpSWEJ4UUFsMklXS1IyMkpEajIz?= =?utf-8?B?Zk1UKzVCSTd3cGZqT1hoZDlpUFlka3VReDVrZ0NIbWhxaWtwZW81ZWhtU0U1?= =?utf-8?B?cW5IVUhxaVAvNUxPYmtndEhsQU95c2s1QWhBQTd2ZUl6elNWdkR3bzEyOUtU?= =?utf-8?B?V0RVcXlHbnVNYU4vdTlVSmFnaGM1akJSNkJ2aHpLaEVDUk1DR0NESDZvVVVE?= =?utf-8?B?cFBoVzN5eW5rdHFJK1VTRWdDVjlMaGhERmEyL0ZXdnVxMDR6aFBmUWVlSEVF?= =?utf-8?B?QVRMZzFSZGxXVzJHTTRMOUtDemFHcTlPZXlLZFBQTlRIQzdHc210SGMxWGsr?= =?utf-8?B?NUFUZVNsYkVoZDR4MGR5aGVXYWdDWVBSVXUrL3hiUjB4T0FUNFdQaytJV1NR?= =?utf-8?B?Mmhxd3hvdXFrSHhVOTJEUTZUMWVqbVlRYklNL2l4RFM1dWpqaXh6V1BiOXFP?= =?utf-8?B?SUdma2pITFVPMUZlZ1RETW8rTjArWFIwS2ZTRzZ1Q1dGc1MxYVkycHU0TG1K?= =?utf-8?B?aEN6V243V1ZNeW90Q3EyOEFmcHFFMm5GVDhzQ0s1TUkySmIxYWZGaXZWZ2VW?= =?utf-8?B?SnpIY1lud0N0YjVyT1dlajJRR0tXNmNjUzJ4ekx6RmQyTEVNK0RSWlJQSXI1?= =?utf-8?B?NTVkV0lmaFAyakNLUm44YW44TENOYW94NEc5cXFUTW82QTh0SXAraWJUNFF6?= =?utf-8?B?VXppSGhoZEx0YWRJb0gzSTlPQVJkZ0xvZm9jREpOS3UzY1RpUU9rZ20xeE5p?= =?utf-8?B?RmU4aDVwT2l2TlVXRjVNU21LdUVHL0xrTmlhRnkrdVBFYWtPSDJMYWo0U2Vl?= =?utf-8?B?TTVnajlzZFliTGJxRFdOdnNvU3RFemJBWVU0RG1OeXAvQUdibmxMbDA0T091?= =?utf-8?B?dEYwYUNIMXhEZzB0RmY5SkJOdGJUMTRRY2JuVXExc0hKaGRFMUxZdzVEdkZp?= =?utf-8?B?TWk5ajJLOUhXVlFVTGJSUTJxa0ZhOS9xMTdmaGNtbnI3NEY3Y0JrdmViRmVO?= =?utf-8?B?U242VEJTYkFGU0xrVUlsUXpncnRUeG9ueVdiNGdTM0JVNGlYVGpESWkwOUQ3?= =?utf-8?B?aUxFd2MxNDNxSzZCY3Zad0NmVVA4b1IyWDk5bzYwKzVLcGxJTW9uTkZKOGJ1?= =?utf-8?B?RmZkQklvaHI0ZmoyeWJrM3RBMlZCSURvRFphcWVRY01jRzl1QStaRW95OGVE?= =?utf-8?B?L2NqNW96SnVqdkdwcjFMZFlhOC9EeVQxRnlra09Pd1VTVHdLUXJ2Vm5IUXBQ?= =?utf-8?B?WFJjOWxHK1AzMFdxUzJXT3VUVjZad3VmT3gvSExMN1FXeXA2cHUzY3JNd0s0?= =?utf-8?B?QURINExlRGVaTGtxY2gxekVzVllibWtkcGFoMzlMUmR4ZUw1am0rMW9WK0VL?= =?utf-8?B?d3pkNnFtN2ZNQU9MTEMyUFhUcjVhdlhSZHYvazBweGtTdWpqSjVxQ2JtQVJz?= =?utf-8?Q?nkTG6v53+npRY8X2WapMGYsqO1hSq7ID?= X-Microsoft-Exchange-Diagnostics: 1;BN6PR06MB2467;6:tX3uERlOtDMHMmE/TLKTEZLfhnWFdgQVdQdXOQkKfsuxTSEBqcaY7X9QMijxQvPQU0Sfg+gbxJ02aWCD8rTp3Vc8xTSfkZbKkXX4Qe1ra1YS3mH5u1EL7EDOZrke2n4Uo8F665Z+VQYvxGK17MzsQ5cFzhmO2tIygMsbOpf7NLlK0Xe69a1RX18rtEEXaR/0S70uJgTJQHtxku9aldGEwuDhqC5gnC8d64hY/wi4LxnmOqkK7zjQXWDbCyl0uXCIOTnQtzAodYKFBLHfY3c/CHRnWREpFLTDpyCQTROqc27ZYqwzBIWsInFoR9kk4aGB2nJeb1B28/AKVCGfPhvK3YuL4PDEIJJyAijSA0Vfp1K/QU6knNorAlBiir03R/qKuMpUK5XOcUtaK0hMSY8bScQNpt7uS1k3rHq9Vm0yKDk04Rj8zBtJs2Zt45TNP5EyOSnH8BSXwcdQADKFDqyPJQjxE64ddN6FPfs6+qZDLrtVfScnCU0E2CzuHRL49E3Pwn/bEkri23Ke6RPW6PEdRQ== X-Microsoft-Exchange-Diagnostics: 1;BN6PR06MB2467;5:Y+0JXLacdRSzey5HLlXYp1GF5drobBbjmeh+31hTmOsrLMhEzOifiI4YJEl4vrXshRBPmcKIZkYllZMjNRUaXoibLzmwx0nRVFrYN9fqSoBlAmWbD7XWDgMRYxJBJgTeBLQzmnDkqDJ0fuNJ9aIPHKg2nou2A/3O4gPxDPRJH+NmAmX7/Q/tH4/CkICcutkwsxEEpteDcNAsTiaP9ujgJQsYjaq8dmkQLOBAufZAkfAUlcjxrI+e5FyJ3lzNbnfY229TanN9XMGw66ZVXo2VBXJnYP0XjfetZXP7lK/w8/XYdbEJdVHoh1V4QqFj7wmaP7amUcMtELsGMp2R1M40eAzI0ultRnbXdEQp8GLHmXn2peN0zo5fsDCDEW4BMrm9vOxfUJgTSDwrVkOmQyoH+e30tyOWkZ6oXxDt+MNVG5ReOuFq5E5fngZNonZ/Kcmkwdrw0IyHec/5sJr0TLXUogE4OV9p1JmUfGBZCgCV064aV4MimHdyNnxrhAp405K0;24:N4D/9hDA13syUATcINtWXUh9tPFaTM3L++7Q+SQcag91x5Ldg7XFkBtnWJ6NNXvy822U6PK/uJT0tj9jYce1g740PcsREtPI0AD8npuATnw= SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-Microsoft-Exchange-Diagnostics: 1;BN6PR06MB2467;7:9SkcxPLsssmlJZqHLgQQcTEnDTlB5QX9yoPic4GPEnOWXk4t7S6p/zExAFPFNDMWVTdpKQfZIHl3im0BdlTI6THGOrLuJhsSEcNZ7UclscTajOrDt431QKc4O0g2qv9IYz/+UfWFrZToqnQgNA9rnij/n/iE8SoezLhFB3bgLgtjJ82AJ2UOw69kqzykmLXbK2+q5Vzp3HSPZvdATjpJSQoUfU2Ofb+WGajZQ0FLBHVxuGseWDa7ptCavXniev+ACwW3wPjRIB55sbEVl6DizTQgvS0decXs0UZIAv8wrP5fVX0Lc3KCwVhIl4W92mt3LWM/J5mWCOpPzPTd5uPsgg== X-MS-Exchange-CrossTenant-OriginalArrivalTime: 15 Jun 2017 15:28:12.7388 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-Transport-CrossTenantHeadersStamped: BN6PR06MB2467 X-OriginatorOrg: netapp.com Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 102795 Lines: 3064 Hi David, Several comments below: On 06/14/2017 11:18 AM, David Howells wrote: > Add filesystem context support to NFS, parsing the options in advance and > attaching the information to struct nfs_fs_context. The highlights are: > > (*) Merge nfs_mount_info and nfs_clone_mount into nfs_fs_context. This > structure represents NFS's superblock config. > > (*) Make use of the VFS's parsing support to split comma-separated lists. > > (*) Pin the NFS protocol module in the nfs_fs_context. > > (*) Attach supplementary error information to fs_context. This has the > downside that these strings must be static and can't be formatted. > > (*) Remove the auxiliary file_system_type structs since the information > necessary can be conveyed in the nfs_fs_context struct instead. > > (*) Root mounts are made by duplicating the config for the requested mount > so as to have the same parameters. Submounts pick up their parameters > from the parent superblock. > > Signed-off-by: David Howells > --- > > fs/nfs/client.c | 74 +++-- > fs/nfs/fs_context.c | 652 ++++++++++++++++++++++++++++------------------- > fs/nfs/getroot.c | 72 +++-- > fs/nfs/internal.h | 104 +++---- > fs/nfs/namespace.c | 76 ++++- > fs/nfs/nfs3_fs.h | 2 > fs/nfs/nfs3client.c | 6 > fs/nfs/nfs3proc.c | 2 > fs/nfs/nfs4_fs.h | 4 > fs/nfs/nfs4client.c | 44 ++- > fs/nfs/nfs4namespace.c | 208 +++++++++------ > fs/nfs/nfs4proc.c | 3 > fs/nfs/nfs4super.c | 220 ++++++++-------- > fs/nfs/proc.c | 2 > fs/nfs/super.c | 381 ++++++++------------------- > include/linux/nfs_xdr.h | 7 - > 16 files changed, 940 insertions(+), 917 deletions(-) > > diff --git a/fs/nfs/client.c b/fs/nfs/client.c > index d25dfa15f2ec..8c9b610ca952 100644 > --- a/fs/nfs/client.c > +++ b/fs/nfs/client.c > @@ -635,25 +635,24 @@ EXPORT_SYMBOL_GPL(nfs_init_client); > * Create a version 2 or 3 client > */ > static int nfs_init_server(struct nfs_server *server, > - const struct nfs_fs_context *cfg, > - struct nfs_subversion *nfs_mod) > + const struct nfs_fs_context *ctx) > { > struct rpc_timeout timeparms; > struct nfs_client_initdata cl_init = { > - .hostname = cfg->nfs_server.hostname, > - .addr = (const struct sockaddr *)&cfg->nfs_server.address, > - .addrlen = cfg->nfs_server.addrlen, > - .nfs_mod = nfs_mod, > - .proto = cfg->nfs_server.protocol, > - .net = cfg->net, > + .hostname = ctx->nfs_server.hostname, > + .addr = (const struct sockaddr *)&ctx->nfs_server.address, > + .addrlen = ctx->nfs_server.addrlen, > + .nfs_mod = ctx->nfs_mod, > + .proto = ctx->nfs_server.protocol, > + .net = ctx->fc.net_ns, > .timeparms = &timeparms, > }; > struct nfs_client *clp; > int error; > > - nfs_init_timeout_values(&timeparms, cfg->nfs_server.protocol, > - cfg->timeo, cfg->retrans); > - if (cfg->flags & NFS_MOUNT_NORESVPORT) > + nfs_init_timeout_values(&timeparms, ctx->nfs_server.protocol, > + ctx->timeo, ctx->retrans); > + if (ctx->flags & NFS_MOUNT_NORESVPORT) > set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags); > > /* Allocate or find a client reference we can use */ > @@ -664,46 +663,46 @@ static int nfs_init_server(struct nfs_server *server, > server->nfs_client = clp; > > /* Initialise the client representation from the mount data */ > - server->flags = cfg->flags; > - server->options = cfg->options; > + server->flags = ctx->flags; > + server->options = ctx->options; > server->caps |= NFS_CAP_HARDLINKS|NFS_CAP_SYMLINKS|NFS_CAP_FILEID| > NFS_CAP_MODE|NFS_CAP_NLINK|NFS_CAP_OWNER|NFS_CAP_OWNER_GROUP| > NFS_CAP_ATIME|NFS_CAP_CTIME|NFS_CAP_MTIME; > > - if (cfg->rsize) > - server->rsize = nfs_block_size(cfg->rsize, NULL); > - if (cfg->wsize) > - server->wsize = nfs_block_size(cfg->wsize, NULL); > + if (ctx->rsize) > + server->rsize = nfs_block_size(ctx->rsize, NULL); > + if (ctx->wsize) > + server->wsize = nfs_block_size(ctx->wsize, NULL); > > - server->acregmin = cfg->acregmin * HZ; > - server->acregmax = cfg->acregmax * HZ; > - server->acdirmin = cfg->acdirmin * HZ; > - server->acdirmax = cfg->acdirmax * HZ; > + server->acregmin = ctx->acregmin * HZ; > + server->acregmax = ctx->acregmax * HZ; > + server->acdirmin = ctx->acdirmin * HZ; > + server->acdirmax = ctx->acdirmax * HZ; > > /* Start lockd here, before we might error out */ > error = nfs_start_lockd(server); > if (error < 0) > goto error; > > - server->port = cfg->nfs_server.port; > - server->auth_info = cfg->auth_info; > + server->port = ctx->nfs_server.port; > + server->auth_info = ctx->auth_info; > > error = nfs_init_server_rpcclient(server, &timeparms, > - cfg->selected_flavor); > + ctx->selected_flavor); > if (error < 0) > goto error; > > /* Preserve the values of mount_server-related mount options */ > - if (cfg->mount_server.addrlen) { > - memcpy(&server->mountd_address, &cfg->mount_server.address, > - cfg->mount_server.addrlen); > - server->mountd_addrlen = cfg->mount_server.addrlen; > + if (ctx->mount_server.addrlen) { > + memcpy(&server->mountd_address, &ctx->mount_server.address, > + ctx->mount_server.addrlen); > + server->mountd_addrlen = ctx->mount_server.addrlen; > } > - server->mountd_version = cfg->mount_server.version; > - server->mountd_port = cfg->mount_server.port; > - server->mountd_protocol = cfg->mount_server.protocol; > + server->mountd_version = ctx->mount_server.version; > + server->mountd_port = ctx->mount_server.port; > + server->mountd_protocol = ctx->mount_server.protocol; > > - server->namelen = cfg->namlen; > + server->namelen = ctx->namlen; > return 0; > > error: > @@ -921,8 +920,7 @@ EXPORT_SYMBOL_GPL(nfs_free_server); > * Create a version 2 or 3 volume record > * - keyed on server and FSID > */ > -struct nfs_server *nfs_create_server(struct nfs_mount_info *mount_info, > - struct nfs_subversion *nfs_mod) > +struct nfs_server *nfs_create_server(struct nfs_fs_context *ctx) > { > struct nfs_server *server; > struct nfs_fattr *fattr; > @@ -938,18 +936,18 @@ struct nfs_server *nfs_create_server(struct nfs_mount_info *mount_info, > goto error; > > /* Get a client representation */ > - error = nfs_init_server(server, mount_info->ctx, nfs_mod); > + error = nfs_init_server(server, ctx); > if (error < 0) > goto error; > > /* Probe the root fh to retrieve its FSID */ > - error = nfs_probe_fsinfo(server, mount_info->mntfh, fattr); > + error = nfs_probe_fsinfo(server, ctx->mntfh, fattr); > if (error < 0) > goto error; > if (server->nfs_client->rpc_ops->version == 3) { > if (server->namelen == 0 || server->namelen > NFS3_MAXNAMLEN) > server->namelen = NFS3_MAXNAMLEN; > - if (!(mount_info->ctx->flags & NFS_MOUNT_NORDIRPLUS)) > + if (!(ctx->flags & NFS_MOUNT_NORDIRPLUS)) > server->caps |= NFS_CAP_READDIRPLUS; > } else { > if (server->namelen == 0 || server->namelen > NFS2_MAXNAMLEN) > @@ -957,7 +955,7 @@ struct nfs_server *nfs_create_server(struct nfs_mount_info *mount_info, > } > > if (!(fattr->valid & NFS_ATTR_FATTR)) { > - error = nfs_mod->rpc_ops->getattr(server, mount_info->mntfh, fattr, NULL); > + error = ctx->nfs_mod->rpc_ops->getattr(server, ctx->mntfh, fattr, NULL); > if (error < 0) { > dprintk("nfs_create_server: getattr error = %d\n", -error); > goto error; > diff --git a/fs/nfs/fs_context.c b/fs/nfs/fs_context.c > index 24becb82540f..e8e88aaa5164 100644 > --- a/fs/nfs/fs_context.c > +++ b/fs/nfs/fs_context.c > @@ -240,42 +240,8 @@ static const match_table_t nfs_vers_tokens = { > { Opt_vers_err, NULL } > }; > > -struct nfs_fs_context *nfs_alloc_parsed_mount_data(void) > -{ > - struct nfs_fs_context *ctx; > - > - ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); > - if (ctx) { > - ctx->timeo = NFS_UNSPEC_TIMEO; > - ctx->retrans = NFS_UNSPEC_RETRANS; > - ctx->acregmin = NFS_DEF_ACREGMIN; > - ctx->acregmax = NFS_DEF_ACREGMAX; > - ctx->acdirmin = NFS_DEF_ACDIRMIN; > - ctx->acdirmax = NFS_DEF_ACDIRMAX; > - ctx->mount_server.port = NFS_UNSPEC_PORT; > - ctx->nfs_server.port = NFS_UNSPEC_PORT; > - ctx->nfs_server.protocol = XPRT_TRANSPORT_TCP; > - ctx->selected_flavor = RPC_AUTH_MAXFLAVOR; > - ctx->minorversion = 0; > - ctx->need_mount = true; > - ctx->net = current->nsproxy->net_ns; > - security_init_mnt_opts(&ctx->lsm_opts); > - } > - return ctx; > -} > - > -void nfs_free_parsed_mount_data(struct nfs_fs_context *ctx) > -{ > - if (ctx) { > - kfree(ctx->client_address); > - kfree(ctx->mount_server.hostname); > - kfree(ctx->nfs_server.export_path); > - kfree(ctx->nfs_server.hostname); > - kfree(ctx->fscache_uniq); > - security_free_mnt_opts(&ctx->lsm_opts); > - kfree(ctx); > - } > -} > +const char nfs_slash[] = "/"; > +EXPORT_SYMBOL_GPL(nfs_slash); > > /* > * Sanity-check a server address provided by the mount command. > @@ -354,10 +320,8 @@ static int nfs_auth_info_add(struct nfs_fs_context *ctx, > return 0; > } > > - if (auth_info->flavor_len + 1 >= max_flavor_len) { > - dfprintk(MOUNT, "NFS: too many sec= flavors\n"); > - return -EINVAL; > - } > + if (auth_info->flavor_len + 1 >= max_flavor_len) > + return invalf("NFS: too many sec= flavors"); > > auth_info->flavors[auth_info->flavor_len++] = flavor; > return 0; > @@ -411,9 +375,7 @@ static int nfs_parse_security_flavors(struct nfs_fs_context *ctx, char *value) > pseudoflavor = RPC_AUTH_GSS_SPKMP; > break; > default: > - dfprintk(MOUNT, > - "NFS: sec= option '%s' not recognized\n", p); > - return -EINVAL; > + return invalf("NFS: sec=%s option not recognized", p); > } > > ret = nfs_auth_info_add(ctx, &ctx->auth_info, pseudoflavor); > @@ -457,8 +419,7 @@ static int nfs_parse_version_string(struct nfs_fs_context *ctx, > ctx->minorversion = 2; > break; > default: > - dfprintk(MOUNT, "NFS: Unsupported NFS version\n"); > - return -EINVAL; > + return invalf("NFS: Unsupported NFS version"); > } > return 0; > } > @@ -495,8 +456,9 @@ static int nfs_get_option_ui_bound(struct nfs_fs_context *ctx, > /* > * Parse a single mount option in "key[=val]" form. > */ > -static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p) > +static int nfs_fs_context_parse_option(struct fs_context *fc, char *p) > { > + struct nfs_fs_context *ctx = container_of(fc, struct nfs_fs_context, fc); > substring_t args[MAX_OPT_ARGS]; > char *string; > int ret, token; > @@ -715,8 +677,7 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p) > break; > default: > kfree(string); > - dfprintk(MOUNT, "NFS: unrecognized transport protocol\n"); > - return -EINVAL; > + return invalf("NFS: Unrecognized transport protocol"); > } > kfree(string); > break; > @@ -741,8 +702,7 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p) > break; > case Opt_xprt_rdma: /* not used for side protocols */ > default: > - dfprintk(MOUNT, "NFS: unrecognized transport protocol\n"); > - return -EINVAL; > + return invalf("NFS: Unrecognized transport protocol"); > } > break; > case Opt_addr: > @@ -750,7 +710,7 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p) > if (string == NULL) > goto out_nomem; > ctx->nfs_server.addrlen = > - rpc_pton(ctx->net, string, strlen(string), > + rpc_pton(fc->net_ns, string, strlen(string), > &ctx->nfs_server.address, > sizeof(ctx->nfs_server._address)); > kfree(string); > @@ -770,7 +730,7 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p) > if (string == NULL) > goto out_nomem; > ctx->mount_server.addrlen = > - rpc_pton(ctx->net, string, strlen(string), > + rpc_pton(fc->net_ns, string, strlen(string), > &ctx->mount_server.address, > sizeof(ctx->mount_server._address)); > kfree(string); > @@ -795,8 +755,7 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p) > ctx->flags |= NFS_MOUNT_LOOKUP_CACHE_NONEG|NFS_MOUNT_LOOKUP_CACHE_NONE; > break; > default: > - dfprintk(MOUNT, "NFS: invalid lookupcache argument\n"); > - return -EINVAL; > + return invalf("NFS: Invalid lookupcache argument"); > } > break; > case Opt_fscache_uniq: > @@ -826,16 +785,15 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p) > NFS_MOUNT_LOCAL_FCNTL); > break; > default: > - dfprintk(MOUNT, "NFS: invalid local_lock argument\n"); > - return -EINVAL; > - }; > + return invalf("NFS: invalid local_lock argument"); > + } > break; > > /* > * Special options > */ > case Opt_sloppy: > - ctx->sloppy = 1; > + fc->sloppy = 1; > dfprintk(MOUNT, "NFS: relaxing parsing rules\n"); > break; > case Opt_userspace: > @@ -845,116 +803,24 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p) > > default: > dfprintk(MOUNT, "NFS: unrecognized mount option '%s'\n", p); > - return -EINVAL; > + if (!fc->sloppy) > + return invalf("NFS: Unrecognized mount option '%s'", p); Did you mean to remove the dfprintk() above with this change, too? I wonder if the invalf() / errorf() changeover could go into its own patch to make it easier to catch any issues. > + break; > } > > return 0; > > -out_invalid_address: > - printk(KERN_INFO "NFS: bad IP address specified: %s\n", p); > - return -EINVAL; > -out_invalid_value: > - printk(KERN_INFO "NFS: bad mount option value specified: %s\n", p); > - return -EINVAL; > out_nomem: > printk(KERN_INFO "NFS: not enough memory to parse option\n"); > return -ENOMEM; > +out_invalid_value: > + return invalf("NFS: Bad mount option value specified"); > +out_invalid_address: > + return invalf("NFS: Bad IP address specified"); > } > > /* > - * Error-check and convert a string of mount options from user space into > - * a data structure. The whole mount string is processed; bad options are > - * skipped as they are encountered. If there were no errors, return 1; > - * otherwise return 0 (zero). > - */ > -int nfs_parse_mount_options(char *raw, struct nfs_fs_context *ctx) > -{ > - char *p, *secdata; > - int rc, sloppy = 0, invalid_option = 0; > - > - if (!raw) { > - dfprintk(MOUNT, "NFS: mount options string was NULL.\n"); > - return 1; > - } > - dfprintk(MOUNT, "NFS: nfs mount opts='%s'\n", raw); > - > - secdata = alloc_secdata(); > - if (!secdata) > - goto out_nomem; > - > - rc = security_sb_copy_data(raw, secdata); > - if (rc) > - goto out_security_failure; > - > - rc = security_sb_parse_opts_str(secdata, &ctx->lsm_opts); > - if (rc) > - goto out_security_failure; > - > - free_secdata(secdata); > - > - while ((p = strsep(&raw, ",")) != NULL) { > - if (!*p) > - continue; > - if (nfs_fs_context_parse_option(ctx, p) < 0) > - invalid_option = true; > - } > - > - if (!sloppy && invalid_option) > - return 0; > - > - if (ctx->minorversion && ctx->version != 4) > - goto out_minorversion_mismatch; > - > - if (ctx->options & NFS_OPTION_MIGRATION && > - (ctx->version != 4 || ctx->minorversion != 0)) > - goto out_migration_misuse; > - > - /* > - * verify that any proto=/mountproto= options match the address > - * families in the addr=/mountaddr= options. > - */ > - if (ctx->protofamily != AF_UNSPEC && > - ctx->protofamily != ctx->nfs_server.address.sa_family) > - goto out_proto_mismatch; > - > - if (ctx->mountfamily != AF_UNSPEC) { > - if (ctx->mount_server.addrlen) { > - if (ctx->mountfamily != ctx->mount_server.address.sa_family) > - goto out_mountproto_mismatch; > - } else { > - if (ctx->mountfamily != ctx->nfs_server.address.sa_family) > - goto out_mountproto_mismatch; > - } > - } > - > - return 1; > - > -out_minorversion_mismatch: > - printk(KERN_INFO "NFS: mount option vers=%u does not support " > - "minorversion=%u\n", ctx->version, ctx->minorversion); > - return 0; > -out_mountproto_mismatch: > - printk(KERN_INFO "NFS: mount server address does not match mountproto= " > - "option\n"); > - return 0; > -out_proto_mismatch: > - printk(KERN_INFO "NFS: server address does not match proto= option\n"); > - return 0; > -out_migration_misuse: > - printk(KERN_INFO > - "NFS: 'migration' not supported for this NFS version\n"); > - return -EINVAL; > -out_nomem: > - printk(KERN_INFO "NFS: not enough memory to parse option\n"); > - return 0; > -out_security_failure: > - free_secdata(secdata); > - printk(KERN_INFO "NFS: security options invalid: %d\n", rc); > - return 0; > -} > - > -/* > - * Split "dev_name" into "hostname:export_path". > + * Split sc->device into "hostname:export_path". > * > * The leftmost colon demarks the split between the server's hostname > * and the export path. If the hostname starts with a left square > @@ -963,9 +829,9 @@ int nfs_parse_mount_options(char *raw, struct nfs_fs_context *ctx) > * Note: caller frees hostname and export path, even on error. > */ > static int nfs_parse_devname(struct nfs_fs_context *ctx, > - const char *dev_name, > size_t maxnamlen, size_t maxpathlen) > { > + char *dev_name = ctx->fc.device; > size_t len; > char *end; > > @@ -1009,19 +875,15 @@ static int nfs_parse_devname(struct nfs_fs_context *ctx, > return 0; > > out_bad_devname: > - dfprintk(MOUNT, "NFS: device name not in host:path format\n"); > - return -EINVAL; > - > + return invalf("NFS: device name not in host:path format"); > out_nomem: > - dfprintk(MOUNT, "NFS: not enough memory to parse device name\n"); > + errorf("NFS: not enough memory to parse device name"); > return -ENOMEM; > - > out_hostname: > - dfprintk(MOUNT, "NFS: server hostname too long\n"); > + errorf("NFS: server hostname too long"); > return -ENAMETOOLONG; > - > out_path: > - dfprintk(MOUNT, "NFS: export pathname too long\n"); > + errorf("NFS: export pathname too long"); > return -ENAMETOOLONG; > } > > @@ -1041,14 +903,14 @@ static int nfs_parse_devname(struct nfs_fs_context *ctx, > * + breaking back: trying proto=udp after proto=tcp, v2 after v3, > * mountproto=tcp after mountproto=udp, and so on > */ > -static int nfs23_validate_mount_data(void *options, > - struct nfs_fs_context *ctx, > - struct nfs_fh *mntfh, > - const char *dev_name) > +static int nfs23_monolithic_mount_data(struct fs_context *fc, > + struct nfs_mount_data *data) > { > - struct nfs_mount_data *data = (struct nfs_mount_data *)options; > + struct nfs_fs_context *ctx = container_of(fc, struct nfs_fs_context, fc); > + struct nfs_fh *mntfh = ctx->mntfh; > struct sockaddr *sap = (struct sockaddr *)&ctx->nfs_server.address; > int extra_flags = NFS_MOUNT_LEGACY_INTERFACE; > + int ret; If I set SECURITY_SELINUX=n and compile, I see this: fs/nfs/fs_context.c:913:6: error: unused variable 'ret' [-Werror=unused-variable] int ret; > > if (data == NULL) > goto out_no_data; > @@ -1114,6 +976,9 @@ static int nfs23_validate_mount_data(void *options, > ctx->nfs_server.protocol = XPRT_TRANSPORT_UDP; > /* N.B. caller will free nfs_server.hostname in all cases */ > ctx->nfs_server.hostname = kstrdup(data->hostname, GFP_KERNEL); > + if (!ctx->nfs_server.hostname) > + goto out_nomem; > + > ctx->namlen = data->namlen; > ctx->bsize = data->bsize; > > @@ -1121,8 +986,6 @@ static int nfs23_validate_mount_data(void *options, > ctx->selected_flavor = data->pseudoflavor; > else > ctx->selected_flavor = RPC_AUTH_UNIX; > - if (!ctx->nfs_server.hostname) > - goto out_nomem; > > if (!(data->flags & NFS_MOUNT_NONLM)) > ctx->flags &= ~(NFS_MOUNT_LOCAL_FLOCK| > @@ -1130,6 +993,7 @@ static int nfs23_validate_mount_data(void *options, > else > ctx->flags |= (NFS_MOUNT_LOCAL_FLOCK| > NFS_MOUNT_LOCAL_FCNTL); > + > /* > * The legacy version 6 binary mount data from userspace has a > * field used only to transport selinux information into the > @@ -1140,17 +1004,16 @@ static int nfs23_validate_mount_data(void *options, > */ > if (data->context[0]){ > #ifdef CONFIG_SECURITY_SELINUX > - int rc; Keeping rc here would fix the problem I just mentioned > char *opts_str = kmalloc(sizeof(data->context) + 8, GFP_KERNEL); > if (!opts_str) > return -ENOMEM; > strcpy(opts_str, "context="); > data->context[NFS_MAX_CONTEXT_LEN] = '\0'; > strcat(opts_str, &data->context[0]); > - rc = security_sb_parse_opts_str(opts_str, &ctx->lsm_opts); > + ret = vfs_parse_mount_option(fc, opts_str); > kfree(opts_str); > - if (rc) > - return rc; > + if (ret) > + return ret; > #else > return -EINVAL; > #endif > @@ -1158,54 +1021,44 @@ static int nfs23_validate_mount_data(void *options, > > break; > default: > - return NFS_TEXT_DATA; > + return generic_monolithic_mount_data(fc, data); > } > > + ctx->skip_remount_option_check = true; > return 0; > > out_no_data: > - dfprintk(MOUNT, "NFS: mount program didn't pass any mount data\n"); > - return -EINVAL; > + if (fc->sb_flags & MS_REMOUNT) { > + ctx->skip_remount_option_check = true; > + return 0; > + } > + return invalf("NFS: mount program didn't pass any mount data"); > > out_no_v3: > - dfprintk(MOUNT, "NFS: nfs_mount_data version %d does not support v3\n", > - data->version); > - return -EINVAL; > + return invalf("NFS: nfs_mount_data version does not support v3"); > > out_no_sec: > - dfprintk(MOUNT, "NFS: nfs_mount_data version supports only AUTH_SYS\n"); > - return -EINVAL; > + return invalf("NFS: nfs_mount_data version supports only AUTH_SYS"); > > out_nomem: > - dfprintk(MOUNT, "NFS: not enough memory to handle mount options\n"); > + dfprintk(MOUNT, "NFS: not enough memory to handle mount options"); > return -ENOMEM; > > out_no_address: > - dfprintk(MOUNT, "NFS: mount program didn't pass remote address\n"); > - return -EINVAL; > + return invalf("NFS: mount program didn't pass remote address"); > > out_invalid_fh: > - dfprintk(MOUNT, "NFS: invalid root filehandle\n"); > - return -EINVAL; > -} > - > -#if IS_ENABLED(CONFIG_NFS_V4) I think the "IS_ENABLED(CONFIG_NFS_V4)" check needs to stay here, otherwise gcc wtill complain that nfs4_monolithic_mount_data() is defined but not used > - > -static void nfs4_validate_mount_flags(struct nfs_fs_context *ctx) > -{ > - ctx->flags &= ~(NFS_MOUNT_NONLM|NFS_MOUNT_NOACL|NFS_MOUNT_VER3| > - NFS_MOUNT_LOCAL_FLOCK|NFS_MOUNT_LOCAL_FCNTL); > + return invalf("NFS: invalid root filehandle"); > } > > /* > * Validate NFSv4 mount options > */ > -static int nfs4_validate_mount_data(void *options, > - struct nfs_fs_context *ctx, > - const char *dev_name) > +static int nfs4_monolithic_mount_data(struct fs_context *fc, > + struct nfs4_mount_data *data) > { > + struct nfs_fs_context *ctx = container_of(fc, struct nfs_fs_context, fc); > struct sockaddr *sap = (struct sockaddr *)&ctx->nfs_server.address; > - struct nfs4_mount_data *data = (struct nfs4_mount_data *)options; > char *c; > > if (data == NULL) > @@ -1255,7 +1108,7 @@ static int nfs4_validate_mount_data(void *options, > ctx->client_address = c; > > /* > - * Translate to nfs_fs_context, which nfs4_fill_super > + * Translate to nfs_fs_context, which nfs_fill_super > * can deal with. > */ > > @@ -1275,95 +1128,372 @@ static int nfs4_validate_mount_data(void *options, > > break; > default: > - return NFS_TEXT_DATA; > + return generic_monolithic_mount_data(fc, data); > } > > + ctx->skip_remount_option_check = true; > return 0; > > out_no_data: > - dfprintk(MOUNT, "NFS4: mount program didn't pass any mount data\n"); > - return -EINVAL; > + if (fc->sb_flags & MS_REMOUNT) { > + ctx->skip_remount_option_check = true; > + return 0; > + } > + return invalf("NFS4: mount program didn't pass any mount data"); > > out_inval_auth: > - dfprintk(MOUNT, "NFS4: Invalid number of RPC auth flavours %d\n", > - data->auth_flavourlen); > - return -EINVAL; > + return invalf("NFS4: Invalid number of RPC auth flavours %d", > + data->auth_flavourlen); > > out_no_address: > - dfprintk(MOUNT, "NFS4: mount program didn't pass remote address\n"); > - return -EINVAL; > + return invalf("NFS4: mount program didn't pass remote address"); > > out_invalid_transport_udp: > - dfprintk(MOUNT, "NFSv4: Unsupported transport protocol udp\n"); > - return -EINVAL; > + return invalf("NFSv4: Unsupported transport protocol udp"); > } > > -int nfs_validate_mount_data(struct file_system_type *fs_type, > - void *options, > - struct nfs_fs_context *ctx, > - struct nfs_fh *mntfh, > - const char *dev_name) > -{ > - if (fs_type == &nfs_fs_type) > - return nfs23_validate_mount_data(options, ctx, mntfh, dev_name); > - return nfs4_validate_mount_data(options, ctx, dev_name); > -} > -#else > -int nfs_validate_mount_data(struct file_system_type *fs_type, > - void *options, > - struct nfs_fs_context *ctx, > - struct nfs_fh *mntfh, > - const char *dev_name) > +/* > + * Parse a monolithic block of data from sys_mount(). > + */ > +static int nfs_monolithic_mount_data(struct fs_context *fc, void *data) > { > - return nfs23_validate_mount_data(options, ctx, mntfh, dev_name); > -} > + if (fc->fs_type == &nfs_fs_type) > + return nfs23_monolithic_mount_data(fc, data); > + > +#if IS_ENABLED(CONFIG_NFS_V4) > + if (fc->fs_type == &nfs4_fs_type) > + return nfs4_monolithic_mount_data(fc, data); > #endif > > -int nfs_validate_text_mount_data(void *options, > - struct nfs_fs_context *ctx, > - const char *dev_name) > + return invalf("NFS: Unsupported monolithic data version"); > +} > + > +/* > + * Validate the preparsed information in the config. > + */ > +static int nfs_fs_context_validate(struct fs_context *fc) > { > - int port = 0; > + struct nfs_fs_context *ctx = container_of(fc, struct nfs_fs_context, fc); > + struct nfs_subversion *nfs_mod; > + struct sockaddr *sap = (struct sockaddr *)&ctx->nfs_server.address; > int max_namelen = PAGE_SIZE; > int max_pathlen = NFS_MAXPATHLEN; > - struct sockaddr *sap = (struct sockaddr *)&ctx->nfs_server.address; > + int port = 0; > + int ret; > > - if (nfs_parse_mount_options((char *)options, ctx) == 0) > - return -EINVAL; > + if (ctx->fc.purpose == FS_CONTEXT_FOR_REMOUNT) > + return 0; > + > + if (!ctx->fc.device) > + goto out_no_device_name; > + > + /* Check for sanity first. */ > + if (ctx->minorversion && ctx->version != 4) > + goto out_minorversion_mismatch; > + > + if (ctx->options & NFS_OPTION_MIGRATION && > + (ctx->version != 4 || ctx->minorversion != 0)) > + goto out_migration_misuse; > + > + /* Verify that any proto=/mountproto= options match the address > + * families in the addr=/mountaddr= options. > + */ > + if (ctx->protofamily != AF_UNSPEC && > + ctx->protofamily != ctx->nfs_server.address.sa_family) > + goto out_proto_mismatch; > + > + if (ctx->mountfamily != AF_UNSPEC) { > + if (ctx->mount_server.addrlen) { > + if (ctx->mountfamily != ctx->mount_server.address.sa_family) > + goto out_mountproto_mismatch; > + } else { > + if (ctx->mountfamily != ctx->nfs_server.address.sa_family) > + goto out_mountproto_mismatch; > + } > + } > > if (!nfs_verify_server_address(sap)) > goto out_no_address; > > if (ctx->version == 4) { > -#if IS_ENABLED(CONFIG_NFS_V4) > - port = NFS_PORT; > - max_namelen = NFS4_MAXNAMLEN; > - max_pathlen = NFS4_MAXPATHLEN; > - nfs_validate_transport_protocol(ctx); > - if (ctx->nfs_server.protocol == XPRT_TRANSPORT_UDP) > - goto out_invalid_transport_udp; > - nfs4_validate_mount_flags(ctx); > -#else > - goto out_v4_not_compiled; > -#endif /* CONFIG_NFS_V4 */ > - } else > + if (IS_ENABLED(CONFIG_NFS_V4)) { > + port = NFS_PORT; > + max_namelen = NFS4_MAXNAMLEN; > + max_pathlen = NFS4_MAXPATHLEN; > + nfs_validate_transport_protocol(ctx); > + if (ctx->nfs_server.protocol == XPRT_TRANSPORT_UDP) > + goto out_invalid_transport_udp; > + ctx->flags &= ~(NFS_MOUNT_NONLM | NFS_MOUNT_NOACL | > + NFS_MOUNT_VER3 | NFS_MOUNT_LOCAL_FLOCK | > + NFS_MOUNT_LOCAL_FCNTL); > + } else { > + goto out_v4_not_compiled; > + } > + } else { > nfs_set_mount_transport_protocol(ctx); > + } > > nfs_set_port(sap, &ctx->nfs_server.port, port); > > - return nfs_parse_devname(ctx, dev_name, max_namelen, max_pathlen); > + ret = nfs_parse_devname(ctx, max_namelen, max_pathlen); > + if (ret < 0) > + return ret; > > -#if !IS_ENABLED(CONFIG_NFS_V4) > + /* Load the NFS protocol module if we haven't done so yet */ > + if (!ctx->nfs_mod) { > + nfs_mod = get_nfs_version(ctx->version); > + if (IS_ERR(nfs_mod)) { > + ret = PTR_ERR(nfs_mod); > + goto out_version_unavailable; > + } > + ctx->nfs_mod = nfs_mod; > + } > + return 0; > + > +out_no_device_name: > + return invalf("NFS: Device name not specified"); > out_v4_not_compiled: > - dfprintk(MOUNT, "NFS: NFSv4 is not compiled into kernel\n"); > + errorf("NFS: NFSv4 is not compiled into kernel"); > return -EPROTONOSUPPORT; > -#else > out_invalid_transport_udp: > - dfprintk(MOUNT, "NFSv4: Unsupported transport protocol udp\n"); > - return -EINVAL; > -#endif /* !CONFIG_NFS_V4 */ > - > + return invalf("NFSv4: Unsupported transport protocol udp"); > out_no_address: > - dfprintk(MOUNT, "NFS: mount program didn't pass remote address\n"); > - return -EINVAL; > + return invalf("NFS: mount program didn't pass remote address"); > +out_mountproto_mismatch: > + return invalf("NFS: Mount server address does not match mountproto= option"); > +out_proto_mismatch: > + return invalf("NFS: Server address does not match proto= option"); > +out_minorversion_mismatch: > + return invalf("NFS: Mount option vers=%u does not support minorversion=%u", > + ctx->version, ctx->minorversion); > +out_migration_misuse: > + return invalf("NFS: 'Migration' not supported for this NFS version"); > +out_version_unavailable: > + errorf("NFS: Version unavailable"); > + return ret; > +} > + > +/* > + * Use the preparsed information in the config to effect a mount. > + */ > +static int nfs_get_ordinary_tree(struct nfs_fs_context *ctx) > +{ > + ctx->set_security = nfs_set_sb_security; > + > + return ctx->nfs_mod->rpc_ops->try_get_tree(ctx); > } > + > +/* > + * Clone an NFS2/3/4 server record on xdev traversal (FSID-change) > + */ > +static int nfs_get_xdev_tree(struct nfs_fs_context *ctx) > +{ > + struct nfs_server *server; > + int ret; > + > + dprintk("--> nfs_xdev_mount()\n"); I think the dprintk()s in this function are just going to add noise. Can you do the patch without them? Thanks, Anna > + > + ctx->set_security = nfs_clone_sb_security; > + > + /* create a new volume representation */ > + server = ctx->nfs_mod->rpc_ops->clone_server(NFS_SB(ctx->clone_data.sb), > + ctx->mntfh, > + ctx->clone_data.fattr, > + ctx->selected_flavor); > + > + if (IS_ERR(server)) > + ret = PTR_ERR(server); > + else > + ret = nfs_get_tree_common(server, ctx); > + > + dprintk("<-- nfs_get_xdev_tree() = %d\n", ret); > + return ret; > +} > + > +/* > + * Create an NFS superblock by the appropriate method. > + */ > +static int nfs_get_tree(struct fs_context *fc) > +{ > + struct nfs_fs_context *ctx = container_of(fc, struct nfs_fs_context, fc); > + int ret; > + > + if (!ctx->nfs_mod) { > + pr_warn("Missing nfs_mod\n"); > + return -EINVAL; > + } > + if (!ctx->nfs_mod->rpc_ops) { > + pr_warn("Missing rpc_ops\n"); > + return -EINVAL; > + } > + > + if (ctx->nfs_mod->rpc_ops->get_tree) { > + ret = ctx->nfs_mod->rpc_ops->get_tree(ctx); > + if (ret != 1) > + return ret; > + } > + > + switch (ctx->mount_type) { > + case NFS_MOUNT_ORDINARY: > + return nfs_get_ordinary_tree(ctx); > + > + case NFS_MOUNT_CROSS_DEV: > + return nfs_get_xdev_tree(ctx); > + > + default: > + errorf("NFS: Unknown mount type"); > + return -ENOTSUPP; > + } > +} > + > +/* > + * Handle duplication of a configuration. The caller copied *src into *sc, but > + * it can't deal with resource pointers in the filesystem context, so we have > + * to do that. We need to clear pointers, copy data or get extra refs as > + * appropriate. > + */ > +static int nfs_fs_context_dup(struct fs_context *fc, struct fs_context *src) > +{ > + struct nfs_fs_context *ctx = container_of(fc, struct nfs_fs_context, fc); > + > + __module_get(ctx->nfs_mod->owner); > + ctx->client_address = NULL; > + ctx->mount_server.hostname = NULL; > + ctx->nfs_server.export_path = NULL; > + ctx->nfs_server.hostname = NULL; > + ctx->fscache_uniq = NULL; > + > + ctx->mntfh = nfs_alloc_fhandle(); > + if (!ctx->mntfh) > + return -ENOMEM; > + return 0; > +} > + > +static void nfs_fs_context_free(struct fs_context *fc) > +{ > + struct nfs_fs_context *ctx = container_of(fc, struct nfs_fs_context, fc); > + > + if (ctx->nfs_mod) > + put_nfs_version(ctx->nfs_mod); > + kfree(ctx->client_address); > + kfree(ctx->mount_server.hostname); > + if (ctx->nfs_server.export_path != nfs_slash) > + kfree(ctx->nfs_server.export_path); > + kfree(ctx->nfs_server.hostname); > + kfree(ctx->fscache_uniq); > + nfs_free_fhandle(ctx->mntfh); > +} > + > +static const struct fs_context_operations nfs_fs_context_ops = { > + .free = nfs_fs_context_free, > + .dup = nfs_fs_context_dup, > + .parse_option = nfs_fs_context_parse_option, > + .monolithic_mount_data = nfs_monolithic_mount_data, > + .validate = nfs_fs_context_validate, > + .get_tree = nfs_get_tree, > +}; > + > +/* > + * Initialise a configuration from an extant superblock for remounting. > + */ > +static int nfs_mount_init_from_sb(struct fs_context *fc, > + struct super_block *sb) > +{ > + struct nfs_fs_context *ctx = container_of(fc, struct nfs_fs_context, fc); > + struct nfs_server *nfss = sb->s_fs_info; > + struct net *net = nfss->nfs_client->cl_net; > + > + ctx->flags = nfss->flags; > + ctx->rsize = nfss->rsize; > + ctx->wsize = nfss->wsize; > + ctx->retrans = nfss->client->cl_timeout->to_retries; > + ctx->selected_flavor = nfss->client->cl_auth->au_flavor; > + ctx->acregmin = nfss->acregmin / HZ; > + ctx->acregmax = nfss->acregmax / HZ; > + ctx->acdirmin = nfss->acdirmin / HZ; > + ctx->acdirmax = nfss->acdirmax / HZ; > + ctx->timeo = 10U * nfss->client->cl_timeout->to_initval / HZ; > + ctx->nfs_server.port = nfss->port; > + ctx->nfs_server.addrlen = nfss->nfs_client->cl_addrlen; > + ctx->version = nfss->nfs_client->rpc_ops->version; > + ctx->minorversion = nfss->nfs_client->cl_minorversion; > + > + memcpy(&ctx->nfs_server.address, &nfss->nfs_client->cl_addr, > + ctx->nfs_server.addrlen); > + > + if (ctx->fc.net_ns != net) { > + put_net(ctx->fc.net_ns); > + ctx->fc.net_ns = get_net(net); > + } > + > + ctx->nfs_mod = nfss->nfs_client->cl_nfs_mod; > + if (!try_module_get(ctx->nfs_mod->owner)) { > + ctx->nfs_mod = NULL; > + errorf("NFS: Protocol module not available"); > + return -ENOENT; > + } > + > + return 0; > +} > + > +/* > + * Prepare superblock configuration. We use the namespaces attached to the > + * context. This may be the current process's namespaces, or it may be a > + * container's namespaces. > + */ > +static int nfs_init_fs_context(struct fs_context *fc, struct super_block *src_sb) > +{ > + struct nfs_fs_context *ctx = container_of(fc, struct nfs_fs_context, fc); > + > + ctx->mntfh = nfs_alloc_fhandle(); > + if (!ctx->mntfh) > + return -ENOMEM; > + > + ctx->fc.ops = &nfs_fs_context_ops; > + ctx->mount_type = NFS_MOUNT_ORDINARY; > + ctx->protofamily = AF_UNSPEC; > + ctx->mountfamily = AF_UNSPEC; > + ctx->mount_server.port = NFS_UNSPEC_PORT; > + > + if (!src_sb) { > + ctx->timeo = NFS_UNSPEC_TIMEO; > + ctx->retrans = NFS_UNSPEC_RETRANS; > + ctx->acregmin = NFS_DEF_ACREGMIN; > + ctx->acregmax = NFS_DEF_ACREGMAX; > + ctx->acdirmin = NFS_DEF_ACDIRMIN; > + ctx->acdirmax = NFS_DEF_ACDIRMAX; > + ctx->nfs_server.port = NFS_UNSPEC_PORT; > + ctx->nfs_server.protocol = XPRT_TRANSPORT_TCP; > + ctx->selected_flavor = RPC_AUTH_MAXFLAVOR; > + ctx->minorversion = 0; > + ctx->need_mount = true; > + return 0; > + } > + > + return nfs_mount_init_from_sb(fc, src_sb); > +} > + > +struct file_system_type nfs_fs_type = { > + .owner = THIS_MODULE, > + .name = "nfs", > + .init_fs_context = nfs_init_fs_context, > + .fs_context_size = sizeof(struct nfs_fs_context), > + .kill_sb = nfs_kill_super, > + .fs_flags = FS_RENAME_DOES_D_MOVE|FS_BINARY_MOUNTDATA, > +}; > +MODULE_ALIAS_FS("nfs"); > +EXPORT_SYMBOL_GPL(nfs_fs_type); > + > +#if IS_ENABLED(CONFIG_NFS_V4) > +struct file_system_type nfs4_fs_type = { > + .owner = THIS_MODULE, > + .name = "nfs4", > + .fs_context_size = sizeof(struct nfs_fs_context), > + .init_fs_context = nfs_init_fs_context, > + .kill_sb = nfs_kill_super, > + .fs_flags = FS_RENAME_DOES_D_MOVE|FS_BINARY_MOUNTDATA, > +}; > +MODULE_ALIAS_FS("nfs4"); > +MODULE_ALIAS("nfs4"); > +EXPORT_SYMBOL_GPL(nfs4_fs_type); > +#endif /* CONFIG_NFS_V4 */ > diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c > index 391dafaf9182..4a5ee38117b5 100644 > --- a/fs/nfs/getroot.c > +++ b/fs/nfs/getroot.c > @@ -68,66 +68,70 @@ static int nfs_superblock_set_dummy_root(struct super_block *sb, struct inode *i > /* > * get an NFS2/NFS3 root dentry from the root filehandle > */ > -struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh, > - const char *devname) > +int nfs_get_root(struct super_block *s, struct nfs_fs_context *ctx) > { > - struct nfs_server *server = NFS_SB(sb); > + struct nfs_server *server = NFS_SB(s); > struct nfs_fsinfo fsinfo; > - struct dentry *ret; > + struct dentry *root; > struct inode *inode; > - void *name = kstrdup(devname, GFP_KERNEL); > - int error; > + char *name; > + int error = -ENOMEM; > > + name = kstrdup(ctx->fc.device, GFP_KERNEL); > if (!name) > - return ERR_PTR(-ENOMEM); > + goto out; > > /* get the actual root for this mount */ > fsinfo.fattr = nfs_alloc_fattr(); > - if (fsinfo.fattr == NULL) { > - kfree(name); > - return ERR_PTR(-ENOMEM); > - } > + if (fsinfo.fattr == NULL) > + goto out_name; > > - error = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo); > + error = server->nfs_client->rpc_ops->getroot(server, ctx->mntfh, &fsinfo); > if (error < 0) { > dprintk("nfs_get_root: getattr error = %d\n", -error); > - ret = ERR_PTR(error); > - goto out; > + errorf("NFS: Couldn't getattr on root"); > + goto out_fattr; > } > > - inode = nfs_fhget(sb, mntfh, fsinfo.fattr, NULL); > + inode = nfs_fhget(s, ctx->mntfh, fsinfo.fattr, NULL); > if (IS_ERR(inode)) { > dprintk("nfs_get_root: get root inode failed\n"); > - ret = ERR_CAST(inode); > - goto out; > + error = PTR_ERR(inode); > + errorf("NFS: Couldn't get root inode"); > + goto out_fattr; > } > > - error = nfs_superblock_set_dummy_root(sb, inode); > - if (error != 0) { > - ret = ERR_PTR(error); > - goto out; > - } > + error = nfs_superblock_set_dummy_root(s, inode); > + if (error != 0) > + goto out_fattr; > > /* root dentries normally start off anonymous and get spliced in later > * if the dentry tree reaches them; however if the dentry already > * exists, we'll pick it up at this point and use it as the root > */ > - ret = d_obtain_root(inode); > - if (IS_ERR(ret)) { > + root = d_obtain_root(inode); > + if (IS_ERR(root)) { > dprintk("nfs_get_root: get root dentry failed\n"); > - goto out; > + error = PTR_ERR(root); > + errorf("NFS: Couldn't get root dentry"); > + goto out_fattr; > } > > - security_d_instantiate(ret, inode); > - spin_lock(&ret->d_lock); > - if (IS_ROOT(ret) && !ret->d_fsdata && > - !(ret->d_flags & DCACHE_NFSFS_RENAMED)) { > - ret->d_fsdata = name; > + security_d_instantiate(root, inode); > + spin_lock(&root->d_lock); > + if (IS_ROOT(root) && !root->d_fsdata && > + !(root->d_flags & DCACHE_NFSFS_RENAMED)) { > + root->d_fsdata = name; > name = NULL; > } > - spin_unlock(&ret->d_lock); > -out: > - kfree(name); > + spin_unlock(&root->d_lock); > + ctx->fc.root = root; > + error = 0; > + > +out_fattr: > nfs_free_fattr(fsinfo.fattr); > - return ret; > +out_name: > + kfree(name); > +out: > + return error; > } > diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h > index fa568407cda8..ef7193479cda 100644 > --- a/fs/nfs/internal.h > +++ b/fs/nfs/internal.h > @@ -3,7 +3,7 @@ > */ > > #include "nfs4_fs.h" > -#include > +#include > #include > #include > #include > @@ -36,18 +36,6 @@ static inline int nfs_attr_use_mounted_on_fileid(struct nfs_fattr *fattr) > return 1; > } > > -struct nfs_clone_mount { > - const struct super_block *sb; > - const struct dentry *dentry; > - struct nfs_fh *fh; > - struct nfs_fattr *fattr; > - char *hostname; > - char *mnt_path; > - struct sockaddr *addr; > - size_t addrlen; > - rpc_authflavor_t authflavor; > -}; > - > /* > * Note: RFC 1813 doesn't limit the number of auth flavors that > * a server can return, so make something up. > @@ -82,10 +70,22 @@ struct nfs_client_initdata { > const struct rpc_timeout *timeparms; > }; > > +enum nfs_mount_type { > + NFS_MOUNT_ORDINARY, > + NFS_MOUNT_CROSS_DEV, > + NFS4_MOUNT_REMOTE, > + NFS4_MOUNT_REFERRAL, > + NFS4_MOUNT_REMOTE_REFERRAL, > +}; > + > /* > * In-kernel mount arguments > */ > struct nfs_fs_context { > + struct fs_context fc; > + enum nfs_mount_type mount_type : 8; > + bool skip_remount_option_check; > + bool need_mount; > unsigned int flags; /* NFS{,4}_MOUNT_* flags */ > unsigned int rsize, wsize; > unsigned int timeo, retrans; > @@ -102,8 +102,6 @@ struct nfs_fs_context { > char *fscache_uniq; > unsigned short protofamily; > unsigned short mountfamily; > - bool need_mount; > - bool sloppy; > > struct { > union { > @@ -127,10 +125,22 @@ struct nfs_fs_context { > char *export_path; > int port; > unsigned short protocol; > + unsigned short export_path_len; > } nfs_server; > > - struct security_mnt_opts lsm_opts; > - struct net *net; > + struct nfs_fh *mntfh; > + struct nfs_subversion *nfs_mod; > + struct nfs_server *server; > + > + int (*set_security)(struct super_block *, struct nfs_fs_context *); > + > + /* Information for a cloned mount. */ > + struct nfs_clone_mount { > + struct super_block *sb; > + struct dentry *dentry; > + struct nfs_fattr *fattr; > + bool cloned; > + } clone_data; > > char buf[32]; /* Parse buffer */ > }; > @@ -150,14 +160,6 @@ struct nfs_mount_request { > struct net *net; > }; > > -struct nfs_mount_info { > - void (*fill_super)(struct super_block *, struct nfs_mount_info *); > - int (*set_security)(struct super_block *, struct dentry *, struct nfs_mount_info *); > - struct nfs_fs_context *ctx; > - struct nfs_clone_mount *cloned; > - struct nfs_fh *mntfh; > -}; > - > extern int nfs_mount(struct nfs_mount_request *info); > extern void nfs_umount(const struct nfs_mount_request *info); > > @@ -183,13 +185,9 @@ extern struct nfs_client *nfs4_find_client_ident(struct net *, int); > extern struct nfs_client * > nfs4_find_client_sessionid(struct net *, const struct sockaddr *, > struct nfs4_sessionid *, u32); > -extern struct nfs_server *nfs_create_server(struct nfs_mount_info *, > - struct nfs_subversion *); > -extern struct nfs_server *nfs4_create_server( > - struct nfs_mount_info *, > - struct nfs_subversion *); > -extern struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *, > - struct nfs_fh *); > +extern struct nfs_server *nfs_create_server(struct nfs_fs_context *); > +extern struct nfs_server *nfs4_create_server(struct nfs_fs_context *); > +extern struct nfs_server *nfs4_create_referral_server(struct nfs_fs_context *); > extern int nfs4_update_server(struct nfs_server *server, const char *hostname, > struct sockaddr *sap, size_t salen, > struct net *net); > @@ -243,19 +241,7 @@ extern struct svc_version nfs4_callback_version4; > struct nfs_pageio_descriptor; > > /* mount.c */ > -#define NFS_TEXT_DATA 1 > - > -extern struct nfs_fs_context *nfs_alloc_parsed_mount_data(void); > -extern void nfs_free_parsed_mount_data(struct nfs_fs_context *ctx); > -extern int nfs_parse_mount_options(char *raw, struct nfs_fs_context *ctx); > -extern int nfs_validate_mount_data(struct file_system_type *fs_type, > - void *options, > - struct nfs_fs_context *ctx, > - struct nfs_fh *mntfh, > - const char *dev_name); > -extern int nfs_validate_text_mount_data(void *options, > - struct nfs_fs_context *ctx, > - const char *dev_name); > +extern const char nfs_slash[]; > > /* pagelist.c */ > extern int __init nfs_init_nfspagecache(void); > @@ -418,23 +404,12 @@ extern int nfs_wait_atomic_killable(atomic_t *p); > /* super.c */ > extern const struct super_operations nfs_sops; > extern struct file_system_type nfs_fs_type; > -extern struct file_system_type nfs_xdev_fs_type; > -#if IS_ENABLED(CONFIG_NFS_V4) > -extern struct file_system_type nfs4_xdev_fs_type; > -extern struct file_system_type nfs4_referral_fs_type; > -#endif > bool nfs_auth_info_match(const struct nfs_auth_info *, rpc_authflavor_t); > -struct dentry *nfs_try_mount(int, const char *, struct nfs_mount_info *, > - struct nfs_subversion *); > -int nfs_set_sb_security(struct super_block *, struct dentry *, struct nfs_mount_info *); > -int nfs_clone_sb_security(struct super_block *, struct dentry *, struct nfs_mount_info *); > -struct dentry *nfs_fs_mount_common(struct nfs_server *, int, const char *, > - struct nfs_mount_info *, struct nfs_subversion *); > -struct dentry *nfs_fs_mount(struct file_system_type *, int, const char *, void *); > -struct dentry * nfs_xdev_mount_common(struct file_system_type *, int, > - const char *, struct nfs_mount_info *); > +int nfs_try_get_tree(struct nfs_fs_context *); > +int nfs_set_sb_security(struct super_block *, struct nfs_fs_context *); > +int nfs_clone_sb_security(struct super_block *, struct nfs_fs_context *); > +int nfs_get_tree_common(struct nfs_server *, struct nfs_fs_context *); > void nfs_kill_super(struct super_block *); > -void nfs_fill_super(struct super_block *, struct nfs_mount_info *); > > extern struct rpc_stat nfs_rpcstat; > > @@ -467,12 +442,9 @@ struct vfsmount *nfs_do_submount(struct dentry *, struct nfs_fh *, > struct nfs_fattr *, rpc_authflavor_t); > > /* getroot.c */ > -extern struct dentry *nfs_get_root(struct super_block *, struct nfs_fh *, > - const char *); > +extern int nfs_get_root(struct super_block *s, struct nfs_fs_context *cfg); > #if IS_ENABLED(CONFIG_NFS_V4) > -extern struct dentry *nfs4_get_root(struct super_block *, struct nfs_fh *, > - const char *); > - > +extern int nfs4_get_root(struct super_block *s, struct nfs_fs_context *cfg); > extern int nfs4_get_rootfh(struct nfs_server *server, struct nfs_fh *mntfh, bool); > #endif > > @@ -491,7 +463,7 @@ int nfs_show_options(struct seq_file *, struct dentry *); > int nfs_show_devname(struct seq_file *, struct dentry *); > int nfs_show_path(struct seq_file *, struct dentry *); > int nfs_show_stats(struct seq_file *, struct dentry *); > -int nfs_remount(struct super_block *sb, int *flags, char *raw_data); > +int nfs_remount(struct super_block *sb, struct fs_context *fc); > > /* write.c */ > extern void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, > diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c > index e5686be67be8..f80062d626f9 100644 > --- a/fs/nfs/namespace.c > +++ b/fs/nfs/namespace.c > @@ -18,6 +18,7 @@ > #include > #include > #include "internal.h" > +#include "nfs.h" > > #define NFSDBG_FACILITY NFSDBG_VFS > > @@ -209,16 +210,6 @@ void nfs_release_automount_timer(void) > cancel_delayed_work(&nfs_automount_task); > } > > -/* > - * Clone a mountpoint of the appropriate type > - */ > -static struct vfsmount *nfs_do_clone_mount(struct nfs_server *server, > - const char *devname, > - struct nfs_clone_mount *mountdata) > -{ > - return vfs_submount(mountdata->dentry, &nfs_xdev_fs_type, devname, mountdata); > -} > - > /** > * nfs_do_submount - set up mountpoint when crossing a filesystem boundary > * @dentry - parent directory > @@ -230,27 +221,58 @@ static struct vfsmount *nfs_do_clone_mount(struct nfs_server *server, > struct vfsmount *nfs_do_submount(struct dentry *dentry, struct nfs_fh *fh, > struct nfs_fattr *fattr, rpc_authflavor_t authflavor) > { > - struct nfs_clone_mount mountdata = { > - .sb = dentry->d_sb, > - .dentry = dentry, > - .fh = fh, > - .fattr = fattr, > - .authflavor = authflavor, > - }; > + struct nfs_fs_context *ctx; > + struct fs_context *fc; > struct vfsmount *mnt; > - char *page = (char *) __get_free_page(GFP_USER); > - char *devname; > + char *buffer, *p; > + int ret; > + > + /* Open a new filesystem context, transferring parameters from the > + * parent superblock, including the network namespace. > + */ > + fc = vfs_new_fs_context(&nfs_fs_type, dentry->d_sb, 0, > + FS_CONTEXT_FOR_SUBMOUNT); > + if (IS_ERR(fc)) > + return ERR_CAST(fc); > + ctx = container_of(fc, struct nfs_fs_context, fc); > + > + mnt = ERR_PTR(-ENOMEM); > + buffer = kmalloc(4096, GFP_USER); > + if (!buffer) > + goto err_fc; > + > + ctx->mount_type = NFS_MOUNT_CROSS_DEV; > + ctx->selected_flavor = authflavor; > + ctx->clone_data.sb = dentry->d_sb; > + ctx->clone_data.dentry = dentry; > + ctx->clone_data.fattr = fattr; > + ctx->clone_data.cloned = true; > + > + nfs_copy_fh(ctx->mntfh, fh); > + > + p = nfs_devname(dentry, buffer, 4096); > + if (IS_ERR(p)) { > + errorf("NFS: Couldn't determine submount pathname"); > + mnt = ERR_CAST(p); > + goto err_buffer; > + } > + > + ctx->fc.device = kmemdup(p, buffer + 4096 - p, GFP_KERNEL); > + kfree(buffer); > + if (!ctx->fc.device) > + goto err_fc; > > - if (page == NULL) > - return ERR_PTR(-ENOMEM); > + ret = vfs_get_tree(fc); > + if (ret < 0) > + goto err_fc; > > - devname = nfs_devname(dentry, page, PAGE_SIZE); > - if (IS_ERR(devname)) > - mnt = ERR_CAST(devname); > - else > - mnt = nfs_do_clone_mount(NFS_SB(dentry->d_sb), devname, &mountdata); > + mnt = vfs_kern_mount_fc(&ctx->fc); > + goto err_fc; > > - free_page((unsigned long)page); > +err_buffer: > + kfree(buffer); > +err_fc: > + put_fs_context(fc); > return mnt; > } > EXPORT_SYMBOL_GPL(nfs_do_submount); > diff --git a/fs/nfs/nfs3_fs.h b/fs/nfs/nfs3_fs.h > index e134d6548ab7..2094bb1f022e 100644 > --- a/fs/nfs/nfs3_fs.h > +++ b/fs/nfs/nfs3_fs.h > @@ -26,7 +26,7 @@ static inline int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl, > #endif /* CONFIG_NFS_V3_ACL */ > > /* nfs3client.c */ > -struct nfs_server *nfs3_create_server(struct nfs_mount_info *, struct nfs_subversion *); > +struct nfs_server *nfs3_create_server(struct nfs_fs_context *); > struct nfs_server *nfs3_clone_server(struct nfs_server *, struct nfs_fh *, > struct nfs_fattr *, rpc_authflavor_t); > > diff --git a/fs/nfs/nfs3client.c b/fs/nfs/nfs3client.c > index 7879f2a0fcfd..3b99d4985c4c 100644 > --- a/fs/nfs/nfs3client.c > +++ b/fs/nfs/nfs3client.c > @@ -45,10 +45,10 @@ static inline void nfs_init_server_aclclient(struct nfs_server *server) > } > #endif > > -struct nfs_server *nfs3_create_server(struct nfs_mount_info *mount_info, > - struct nfs_subversion *nfs_mod) > +struct nfs_server *nfs3_create_server(struct nfs_fs_context *ctx) > { > - struct nfs_server *server = nfs_create_server(mount_info, nfs_mod); > + struct nfs_server *server = nfs_create_server(ctx); > + > /* Create a client RPC handle for the NFS v3 ACL management interface */ > if (!IS_ERR(server)) > nfs_init_server_aclclient(server); > diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c > index 0c07b567118d..96e315916a34 100644 > --- a/fs/nfs/nfs3proc.c > +++ b/fs/nfs/nfs3proc.c > @@ -975,7 +975,7 @@ const struct nfs_rpc_ops nfs_v3_clientops = { > .nlmclnt_ops = &nlmclnt_fl_close_lock_ops, > .getroot = nfs3_proc_get_root, > .submount = nfs_submount, > - .try_mount = nfs_try_mount, > + .try_get_tree = nfs_try_get_tree, > .getattr = nfs3_proc_getattr, > .setattr = nfs3_proc_setattr, > .lookup = nfs3_proc_lookup, > diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h > index af285cc27ccf..c5882668dc8a 100644 > --- a/fs/nfs/nfs4_fs.h > +++ b/fs/nfs/nfs4_fs.h > @@ -467,7 +467,6 @@ extern const nfs4_stateid zero_stateid; > /* nfs4super.c */ > struct nfs_mount_info; > extern struct nfs_subversion nfs_v4; > -struct dentry *nfs4_try_mount(int, const char *, struct nfs_mount_info *, struct nfs_subversion *); > extern bool nfs4_disable_idmapping; > extern unsigned short max_session_slots; > extern unsigned short max_session_cb_slots; > @@ -477,6 +476,9 @@ extern bool recover_lost_locks; > #define NFS4_CLIENT_ID_UNIQ_LEN (64) > extern char nfs4_client_id_uniquifier[NFS4_CLIENT_ID_UNIQ_LEN]; > > +extern int nfs4_try_get_tree(struct nfs_fs_context *); > +extern int nfs4_get_tree(struct nfs_fs_context *); > + > /* nfs4sysctl.c */ > #ifdef CONFIG_SYSCTL > int nfs4_register_sysctl(void); > diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c > index 0b5e1ecfa8f8..431eae161383 100644 > --- a/fs/nfs/nfs4client.c > +++ b/fs/nfs/nfs4client.c > @@ -1032,14 +1032,14 @@ static int nfs4_init_server(struct nfs_server *server, > > /* Get a client record */ > error = nfs4_set_client(server, > - ctx->nfs_server.hostname, > - (const struct sockaddr *)&ctx->nfs_server.address, > - ctx->nfs_server.addrlen, > - ctx->client_address, > - ctx->nfs_server.protocol, > - &timeparms, > - ctx->minorversion, > - ctx->net); > + ctx->nfs_server.hostname, > + &ctx->nfs_server.address, > + ctx->nfs_server.addrlen, > + ctx->client_address, > + ctx->nfs_server.protocol, > + &timeparms, > + ctx->minorversion, > + ctx->fc.net_ns); > if (error < 0) > return error; > > @@ -1062,10 +1062,7 @@ static int nfs4_init_server(struct nfs_server *server, > * Create a version 4 volume record > * - keyed on server and FSID > */ > -/*struct nfs_server *nfs4_create_server(const struct nfs_fs_context *data, > - struct nfs_fh *mntfh)*/ > -struct nfs_server *nfs4_create_server(struct nfs_mount_info *mount_info, > - struct nfs_subversion *nfs_mod) > +struct nfs_server *nfs4_create_server(struct nfs_fs_context *ctx) > { > struct nfs_server *server; > bool auth_probe; > @@ -1075,14 +1072,14 @@ struct nfs_server *nfs4_create_server(struct nfs_mount_info *mount_info, > if (!server) > return ERR_PTR(-ENOMEM); > > - auth_probe = mount_info->ctx->auth_info.flavor_len < 1; > + auth_probe = ctx->auth_info.flavor_len < 1; > > /* set up the general RPC client */ > - error = nfs4_init_server(server, mount_info->ctx); > + error = nfs4_init_server(server, ctx); > if (error < 0) > goto error; > > - error = nfs4_server_common_setup(server, mount_info->mntfh, auth_probe); > + error = nfs4_server_common_setup(server, ctx->mntfh, auth_probe); > if (error < 0) > goto error; > > @@ -1096,8 +1093,7 @@ struct nfs_server *nfs4_create_server(struct nfs_mount_info *mount_info, > /* > * Create an NFS4 referral server record > */ > -struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, > - struct nfs_fh *mntfh) > +struct nfs_server *nfs4_create_referral_server(struct nfs_fs_context *ctx) > { > struct nfs_client *parent_client; > struct nfs_server *server, *parent_server; > @@ -1108,7 +1104,7 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, > if (!server) > return ERR_PTR(-ENOMEM); > > - parent_server = NFS_SB(data->sb); > + parent_server = NFS_SB(ctx->clone_data.sb); > parent_client = parent_server->nfs_client; > > /* Initialise the client representation from the parent server */ > @@ -1116,9 +1112,10 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, > > /* Get a client representation. > * Note: NFSv4 always uses TCP, */ > - error = nfs4_set_client(server, data->hostname, > - data->addr, > - data->addrlen, > + error = nfs4_set_client(server, > + ctx->nfs_server.hostname, > + &ctx->nfs_server.address, > + ctx->nfs_server.addrlen, > parent_client->cl_ipaddr, > rpc_protocol(parent_server->client), > parent_server->client->cl_timeout, > @@ -1127,13 +1124,14 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, > if (error < 0) > goto error; > > - error = nfs_init_server_rpcclient(server, parent_server->client->cl_timeout, data->authflavor); > + error = nfs_init_server_rpcclient(server, parent_server->client->cl_timeout, > + ctx->selected_flavor); > if (error < 0) > goto error; > > auth_probe = parent_server->auth_info.flavor_len < 1; > > - error = nfs4_server_common_setup(server, mntfh, auth_probe); > + error = nfs4_server_common_setup(server, ctx->mntfh, auth_probe); > if (error < 0) > goto error; > > diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c > index 7d531da1bae3..07466ae971cc 100644 > --- a/fs/nfs/nfs4namespace.c > +++ b/fs/nfs/nfs4namespace.c > @@ -7,6 +7,7 @@ > * NFSv4 namespace > */ > > +#include > #include > #include > #include > @@ -20,37 +21,64 @@ > #include > #include "internal.h" > #include "nfs4_fs.h" > +#include "nfs.h" > #include "dns_resolve.h" > > #define NFSDBG_FACILITY NFSDBG_VFS > > /* > + * Work out the length that an NFSv4 path would render to as a standard posix > + * path, with a leading slash but no terminating slash. > + */ > +static ssize_t nfs4_pathname_len(const struct nfs4_pathname *pathname) > +{ > + ssize_t len; > + int i; > + > + for (i = 0; i < pathname->ncomponents; i++) { > + const struct nfs4_string *component = &pathname->components[i]; > + > + if (component->len > NAME_MAX) > + goto too_long; > + len += 1 + component->len; /* Adding "/foo" */ > + if (len > PATH_MAX) > + goto too_long; > + } > + return len; > + > +too_long: > + return -ENAMETOOLONG; > +} > + > +/* > * Convert the NFSv4 pathname components into a standard posix path. > - * > - * Note that the resulting string will be placed at the end of the buffer > */ > -static inline char *nfs4_pathname_string(const struct nfs4_pathname *pathname, > - char *buffer, ssize_t buflen) > +static char *nfs4_pathname_string(const struct nfs4_pathname *pathname, > + unsigned short *_len) > { > - char *end = buffer + buflen; > - int n; > + ssize_t len; > + char *buf, *p; > + int i; > > - *--end = '\0'; > - buflen--; > - > - n = pathname->ncomponents; > - while (--n >= 0) { > - const struct nfs4_string *component = &pathname->components[n]; > - buflen -= component->len + 1; > - if (buflen < 0) > - goto Elong; > - end -= component->len; > - memcpy(end, component->data, component->len); > - *--end = '/'; > + len = nfs4_pathname_len(pathname); > + if (len < 0) > + return ERR_PTR(len); > + *_len = len; > + > + p = buf = kmalloc(len + 1, GFP_KERNEL); > + if (!buf) > + return ERR_PTR(-ENOMEM); > + > + for (i = 0; i < pathname->ncomponents; i++) { > + const struct nfs4_string *component = &pathname->components[i]; > + > + *p++ = '/'; > + memcpy(p, component->data, component->len); > + p += component->len; > } > - return end; > -Elong: > - return ERR_PTR(-ENAMETOOLONG); > + > + *p = 0; > + return buf; > } > > /* > @@ -99,21 +127,25 @@ static char *nfs4_path(struct dentry *dentry, char *buffer, ssize_t buflen) > */ > static int nfs4_validate_fspath(struct dentry *dentry, > const struct nfs4_fs_locations *locations, > - char *page, char *page2) > + struct nfs_fs_context *ctx) > { > - const char *path, *fs_path; > + const char *path; > + char *buf; > + int n; > > - path = nfs4_path(dentry, page, PAGE_SIZE); > - if (IS_ERR(path)) > + buf = kmalloc(4096, GFP_KERNEL); > + path = nfs4_path(dentry, buf, 4096); > + if (IS_ERR(path)) { > + kfree(buf); > return PTR_ERR(path); > + } > > - fs_path = nfs4_pathname_string(&locations->fs_path, page2, PAGE_SIZE); > - if (IS_ERR(fs_path)) > - return PTR_ERR(fs_path); > - > - if (strncmp(path, fs_path, strlen(fs_path)) != 0) { > + n = strncmp(path, ctx->nfs_server.export_path, > + ctx->nfs_server.export_path_len); > + kfree(buf); > + if (n != 0) { > dprintk("%s: path %s does not begin with fsroot %s\n", > - __func__, path, fs_path); > + __func__, path, ctx->nfs_server.export_path); > return -ENOENT; > } > > @@ -234,56 +266,66 @@ nfs4_negotiate_security(struct rpc_clnt *clnt, struct inode *inode, > return new; > } > > -static struct vfsmount *try_location(struct nfs_clone_mount *mountdata, > - char *page, char *page2, > +static struct vfsmount *try_location(struct dentry *dentry, > + struct nfs_fs_context *ctx, > const struct nfs4_fs_location *location) > { > - const size_t addr_bufsize = sizeof(struct sockaddr_storage); > - struct net *net = rpc_net_ns(NFS_SB(mountdata->sb)->client); > + struct net *net = rpc_net_ns(NFS_SB(dentry->d_sb)->client); > struct vfsmount *mnt = ERR_PTR(-ENOENT); > - char *mnt_path; > - unsigned int maxbuflen; > - unsigned int s; > + unsigned int len, s; > + char *p; > > - mnt_path = nfs4_pathname_string(&location->rootpath, page2, PAGE_SIZE); > - if (IS_ERR(mnt_path)) > - return ERR_CAST(mnt_path); > - mountdata->mnt_path = mnt_path; > - maxbuflen = mnt_path - 1 - page2; > + /* Allocate a buffer big enough to hold any of the hostnames plus a > + * terminating char and also a buffer big enough to hold the hostname > + * plus a colon plus the path. > + */ > + len = 0; > + for (s = 0; s < location->nservers; s++) { > + const struct nfs4_string *buf = &location->servers[s]; > + if (buf->len > len) > + len = buf->len; > + } > > - mountdata->addr = kmalloc(addr_bufsize, GFP_KERNEL); > - if (mountdata->addr == NULL) > + ctx->nfs_server.hostname = kmalloc(len + 1, GFP_KERNEL); > + if (!ctx->nfs_server.hostname) > return ERR_PTR(-ENOMEM); > > + ctx->fc.device = kmalloc(len + 1 + ctx->nfs_server.export_path_len + 1, > + GFP_KERNEL); > + if (!ctx->fc.device) > + return ERR_PTR(-ENOMEM); > + > for (s = 0; s < location->nservers; s++) { > const struct nfs4_string *buf = &location->servers[s]; > > - if (buf->len <= 0 || buf->len >= maxbuflen) > - continue; > - > if (memchr(buf->data, IPV6_SCOPE_DELIMITER, buf->len)) > continue; > > - mountdata->addrlen = nfs_parse_server_name(buf->data, buf->len, > - mountdata->addr, addr_bufsize, net); > - if (mountdata->addrlen == 0) > + ctx->nfs_server.addrlen = > + nfs_parse_server_name(buf->data, buf->len, > + &ctx->nfs_server.address, > + sizeof(ctx->nfs_server._address), > + net); > + if (ctx->nfs_server.addrlen == 0) > continue; > > - rpc_set_port(mountdata->addr, NFS_PORT); > + rpc_set_port(&ctx->nfs_server.address, NFS_PORT); > > - memcpy(page2, buf->data, buf->len); > - page2[buf->len] = '\0'; > - mountdata->hostname = page2; > + memcpy(ctx->nfs_server.hostname, buf->data, buf->len); > + ctx->nfs_server.hostname[buf->len] = '\0'; > > - snprintf(page, PAGE_SIZE, "%s:%s", > - mountdata->hostname, > - mountdata->mnt_path); > + p = ctx->fc.device; > + memcpy(p, buf->data, buf->len); > + p += buf->len; > + *p++ = ':'; > + memcpy(p, ctx->nfs_server.export_path, ctx->nfs_server.export_path_len); > + p += ctx->nfs_server.export_path_len; > + *p = 0; > > - mnt = vfs_submount(mountdata->dentry, &nfs4_referral_fs_type, page, mountdata); > + mnt = vfs_kern_mount_fc(&ctx->fc); > if (!IS_ERR(mnt)) > break; > } > - kfree(mountdata->addr); > return mnt; > } > > @@ -296,33 +338,43 @@ static struct vfsmount *try_location(struct nfs_clone_mount *mountdata, > static struct vfsmount *nfs_follow_referral(struct dentry *dentry, > const struct nfs4_fs_locations *locations) > { > - struct vfsmount *mnt = ERR_PTR(-ENOENT); > - struct nfs_clone_mount mountdata = { > - .sb = dentry->d_sb, > - .dentry = dentry, > - .authflavor = NFS_SB(dentry->d_sb)->client->cl_auth->au_flavor, > - }; > - char *page = NULL, *page2 = NULL; > + struct nfs_fs_context *ctx; > + struct fs_context *fc; > + struct vfsmount *mnt; > + char *export_path; > int loc, error; > > if (locations == NULL || locations->nlocations <= 0) > goto out; > > + fc = vfs_new_fs_context(&nfs4_fs_type, dentry->d_sb, 0, > + FS_CONTEXT_FOR_SUBMOUNT); > + if (IS_ERR(fc)) { > + mnt = ERR_CAST(fc); > + goto out; > + } > + ctx = container_of(fc, struct nfs_fs_context, fc); > + > dprintk("%s: referral at %pd2\n", __func__, dentry); > > - page = (char *) __get_free_page(GFP_USER); > - if (!page) > - goto out; > + ctx->mount_type = NFS4_MOUNT_REFERRAL; > + ctx->clone_data.sb = dentry->d_sb; > + ctx->clone_data.dentry = dentry; > + ctx->clone_data.cloned = true; > > - page2 = (char *) __get_free_page(GFP_USER); > - if (!page2) > - goto out; > + export_path = nfs4_pathname_string(&locations->fs_path, > + &ctx->nfs_server.export_path_len); > + if (IS_ERR(export_path)) { > + mnt = ERR_CAST(export_path); > + goto out_sc; > + } > + ctx->nfs_server.export_path = export_path; > > /* Ensure fs path is a prefix of current dentry path */ > - error = nfs4_validate_fspath(dentry, locations, page, page2); > + error = nfs4_validate_fspath(dentry, locations, ctx); > if (error < 0) { > mnt = ERR_PTR(error); > - goto out; > + goto out_sc; > } > > for (loc = 0; loc < locations->nlocations; loc++) { > @@ -332,14 +384,14 @@ static struct vfsmount *nfs_follow_referral(struct dentry *dentry, > location->rootpath.ncomponents == 0) > continue; > > - mnt = try_location(&mountdata, page, page2, location); > + mnt = try_location(ctx->clone_data.dentry, ctx, location); > if (!IS_ERR(mnt)) > break; > } > > +out_sc: > + put_fs_context(fc); > out: > - free_page((unsigned long) page); > - free_page((unsigned long) page2); > return mnt; > } > > diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c > index c08c46a3b8cd..ca792f799941 100644 > --- a/fs/nfs/nfs4proc.c > +++ b/fs/nfs/nfs4proc.c > @@ -9307,8 +9307,9 @@ const struct nfs_rpc_ops nfs_v4_clientops = { > .file_inode_ops = &nfs4_file_inode_operations, > .file_ops = &nfs4_file_operations, > .getroot = nfs4_proc_get_root, > + .get_tree = nfs4_get_tree, > .submount = nfs4_submount, > - .try_mount = nfs4_try_mount, > + .try_get_tree = nfs4_try_get_tree, > .getattr = nfs4_proc_getattr, > .setattr = nfs4_proc_setattr, > .lookup = nfs4_proc_lookup, > diff --git a/fs/nfs/nfs4super.c b/fs/nfs/nfs4super.c > index 70111f222a25..9f2eacfee42c 100644 > --- a/fs/nfs/nfs4super.c > +++ b/fs/nfs/nfs4super.c > @@ -3,6 +3,7 @@ > */ > #include > #include > +#include > #include > #include > #include "delegation.h" > @@ -17,36 +18,6 @@ > > static int nfs4_write_inode(struct inode *inode, struct writeback_control *wbc); > static void nfs4_evict_inode(struct inode *inode); > -static struct dentry *nfs4_remote_mount(struct file_system_type *fs_type, > - int flags, const char *dev_name, void *raw_data); > -static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type, > - int flags, const char *dev_name, void *raw_data); > -static struct dentry *nfs4_remote_referral_mount(struct file_system_type *fs_type, > - int flags, const char *dev_name, void *raw_data); > - > -static struct file_system_type nfs4_remote_fs_type = { > - .owner = THIS_MODULE, > - .name = "nfs4", > - .mount = nfs4_remote_mount, > - .kill_sb = nfs_kill_super, > - .fs_flags = FS_RENAME_DOES_D_MOVE|FS_BINARY_MOUNTDATA, > -}; > - > -static struct file_system_type nfs4_remote_referral_fs_type = { > - .owner = THIS_MODULE, > - .name = "nfs4", > - .mount = nfs4_remote_referral_mount, > - .kill_sb = nfs_kill_super, > - .fs_flags = FS_RENAME_DOES_D_MOVE|FS_BINARY_MOUNTDATA, > -}; > - > -struct file_system_type nfs4_referral_fs_type = { > - .owner = THIS_MODULE, > - .name = "nfs4", > - .mount = nfs4_referral_mount, > - .kill_sb = nfs_kill_super, > - .fs_flags = FS_RENAME_DOES_D_MOVE|FS_BINARY_MOUNTDATA, > -}; > > static const struct super_operations nfs4_sops = { > .alloc_inode = nfs_alloc_inode, > @@ -60,16 +31,16 @@ static const struct super_operations nfs4_sops = { > .show_devname = nfs_show_devname, > .show_path = nfs_show_path, > .show_stats = nfs_show_stats, > - .remount_fs = nfs_remount, > + .remount_fs_fc = nfs_remount, > }; > > struct nfs_subversion nfs_v4 = { > - .owner = THIS_MODULE, > - .nfs_fs = &nfs4_fs_type, > - .rpc_vers = &nfs_version4, > - .rpc_ops = &nfs_v4_clientops, > - .sops = &nfs4_sops, > - .xattr = nfs4_xattr_handlers, > + .owner = THIS_MODULE, > + .nfs_fs = &nfs4_fs_type, > + .rpc_vers = &nfs_version4, > + .rpc_ops = &nfs_v4_clientops, > + .sops = &nfs4_sops, > + .xattr = nfs4_xattr_handlers, > }; > > static int nfs4_write_inode(struct inode *inode, struct writeback_control *wbc) > @@ -103,47 +74,63 @@ static void nfs4_evict_inode(struct inode *inode) > /* > * Get the superblock for the NFS4 root partition > */ > -static struct dentry * > -nfs4_remote_mount(struct file_system_type *fs_type, int flags, > - const char *dev_name, void *info) > +static int nfs4_get_remote_tree(struct nfs_fs_context *ctx) > { > - struct nfs_mount_info *mount_info = info; > struct nfs_server *server; > - struct dentry *mntroot = ERR_PTR(-ENOMEM); > > - mount_info->set_security = nfs_set_sb_security; > + ctx->set_security = nfs_set_sb_security; > > /* Get a volume representation */ > - server = nfs4_create_server(mount_info, &nfs_v4); > - if (IS_ERR(server)) { > - mntroot = ERR_CAST(server); > - goto out; > - } > - > - mntroot = nfs_fs_mount_common(server, flags, dev_name, mount_info, &nfs_v4); > + server = nfs4_create_server(ctx); > + if (IS_ERR(server)) > + return PTR_ERR(server); > > -out: > - return mntroot; > + return nfs_get_tree_common(server, ctx); > } > > -static struct vfsmount *nfs_do_root_mount(struct file_system_type *fs_type, > - int flags, void *data, const char *hostname) > +/* > + * Create a mount for the root of the server. We copy the mount context we > + * have for the parameters and set its hostname, path and type. > + */ > +static struct vfsmount *nfs_do_root_mount(struct nfs_fs_context *ctx, > + const char *hostname, > + enum nfs_mount_type type) > { > + struct nfs_fs_context *root_ctx; > + struct fs_context *root_fc; > struct vfsmount *root_mnt; > char *root_devname; > size_t len; > + int ret; > + > + root_fc = vfs_dup_fs_context(&ctx->fc); > + if (IS_ERR(root_fc)) > + return ERR_CAST(root_fc); > + root_ctx = container_of(root_fc, struct nfs_fs_context, fc); > + > + root_ctx->mount_type = type; > + root_ctx->nfs_server.export_path = (char *)nfs_slash; > > len = strlen(hostname) + 5; > + root_mnt = ERR_PTR(-ENOMEM); > root_devname = kmalloc(len, GFP_KERNEL); > if (root_devname == NULL) > - return ERR_PTR(-ENOMEM); > + goto out_fc; > + > /* Does hostname needs to be enclosed in brackets? */ > if (strchr(hostname, ':')) > snprintf(root_devname, len, "[%s]:/", hostname); > else > snprintf(root_devname, len, "%s:/", hostname); > - root_mnt = vfs_kern_mount(fs_type, flags, root_devname, data); > - kfree(root_devname); > + root_ctx->fc.device = root_devname; > + > + ret = vfs_get_tree(&root_ctx->fc); > + if (ret < 0) > + return ERR_PTR(ret); > + > + root_mnt = vfs_kern_mount_fc(&root_ctx->fc); > +out_fc: > + put_fs_context(root_fc); > return root_mnt; > } > > @@ -234,89 +221,98 @@ static struct dentry *nfs_follow_remote_path(struct vfsmount *root_mnt, > return dentry; > } > > -struct dentry *nfs4_try_mount(int flags, const char *dev_name, > - struct nfs_mount_info *mount_info, > - struct nfs_subversion *nfs_mod) > +int nfs4_try_get_tree(struct nfs_fs_context *ctx) > { > - char *export_path; > struct vfsmount *root_mnt; > - struct dentry *res; > - struct nfs_fs_context *ctx = mount_info->ctx; > + struct dentry *root; > > - dfprintk(MOUNT, "--> nfs4_try_mount()\n"); > + dfprintk(MOUNT, "--> nfs4_try_get_tree()\n"); > > - export_path = ctx->nfs_server.export_path; > - ctx->nfs_server.export_path = "/"; > - root_mnt = nfs_do_root_mount(&nfs4_remote_fs_type, flags, mount_info, > - ctx->nfs_server.hostname); > - ctx->nfs_server.export_path = export_path; > - > - res = nfs_follow_remote_path(root_mnt, export_path); > + /* We create a mount for the server's root, walk to the requested > + * location and then create another mount for that. > + */ > + root_mnt = nfs_do_root_mount(ctx, ctx->nfs_server.hostname, > + NFS4_MOUNT_REMOTE); > + if (IS_ERR(root_mnt)) > + return PTR_ERR(root_mnt); > + > + root = nfs_follow_remote_path(root_mnt, ctx->nfs_server.export_path); > + if (IS_ERR(root)) { > + errorf("NFS4: Couldn't follow remote path"); > + dfprintk(MOUNT, "<-- nfs4_try_mount() = %ld [error]\n", > + PTR_ERR(root)); > + return PTR_ERR(root); > + } > > - dfprintk(MOUNT, "<-- nfs4_try_mount() = %d%s\n", > - PTR_ERR_OR_ZERO(res), > - IS_ERR(res) ? " [error]" : ""); > - return res; > + ctx->fc.root = root; > + dfprintk(MOUNT, "<-- nfs4_try_get_tree() = 0\n"); > + return 0; > } > > -static struct dentry * > -nfs4_remote_referral_mount(struct file_system_type *fs_type, int flags, > - const char *dev_name, void *raw_data) > +static int nfs4_get_remote_referral_tree(struct nfs_fs_context *ctx) > { > - struct nfs_mount_info mount_info = { > - .fill_super = nfs_fill_super, > - .set_security = nfs_clone_sb_security, > - .cloned = raw_data, > - }; > struct nfs_server *server; > - struct dentry *mntroot = ERR_PTR(-ENOMEM); > > - dprintk("--> nfs4_referral_get_sb()\n"); > + dprintk("--> nfs4_get_remote_referral_tree()\n"); > > - mount_info.mntfh = nfs_alloc_fhandle(); > - if (mount_info.cloned == NULL || mount_info.mntfh == NULL) > - goto out; > + ctx->set_security = nfs_clone_sb_security; > + > + if (!ctx->clone_data.cloned) > + return -EINVAL; > > /* create a new volume representation */ > - server = nfs4_create_referral_server(mount_info.cloned, mount_info.mntfh); > - if (IS_ERR(server)) { > - mntroot = ERR_CAST(server); > - goto out; > - } > + server = nfs4_create_referral_server(ctx); > + if (IS_ERR(server)) > + return PTR_ERR(server); > > - mntroot = nfs_fs_mount_common(server, flags, dev_name, &mount_info, &nfs_v4); > -out: > - nfs_free_fhandle(mount_info.mntfh); > - return mntroot; > + return nfs_get_tree_common(server, ctx); > } > > /* > * Create an NFS4 server record on referral traversal > */ > -static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type, > - int flags, const char *dev_name, void *raw_data) > +static int nfs4_get_referral_tree(struct nfs_fs_context *ctx) > { > - struct nfs_clone_mount *data = raw_data; > - char *export_path; > struct vfsmount *root_mnt; > - struct dentry *res; > + struct dentry *root; > > dprintk("--> nfs4_referral_mount()\n"); > > - export_path = data->mnt_path; > - data->mnt_path = "/"; > + root_mnt = nfs_do_root_mount(ctx, ctx->nfs_server.hostname, > + NFS4_MOUNT_REMOTE_REFERRAL); > > - root_mnt = nfs_do_root_mount(&nfs4_remote_referral_fs_type, > - flags, data, data->hostname); > - data->mnt_path = export_path; > + root = nfs_follow_remote_path(root_mnt, ctx->nfs_server.export_path); > + if (IS_ERR(root)) { > + errorf("NFS4: Couldn't follow remote path"); > + dfprintk(MOUNT, "<-- nfs4_referral_mount() = %ld [error]\n", > + PTR_ERR(root)); > + return PTR_ERR(root); > + } > > - res = nfs_follow_remote_path(root_mnt, export_path); > - dprintk("<-- nfs4_referral_mount() = %d%s\n", > - PTR_ERR_OR_ZERO(res), > - IS_ERR(res) ? " [error]" : ""); > - return res; > + ctx->fc.root = root; > + dfprintk(MOUNT, "<-- nfs4_get_referral_tree() = 0\n"); > + return 0; > } > > +/* > + * Handle special NFS4 mount types. > + */ > +int nfs4_get_tree(struct nfs_fs_context *ctx) > +{ > + switch (ctx->mount_type) { > + case NFS4_MOUNT_REMOTE: > + return nfs4_get_remote_tree(ctx); > + > + case NFS4_MOUNT_REFERRAL: > + return nfs4_get_referral_tree(ctx); > + > + case NFS4_MOUNT_REMOTE_REFERRAL: > + return nfs4_get_remote_referral_tree(ctx); > + > + default: > + return 1; > + } > +} > > static int __init init_nfs_v4(void) > { > diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c > index 9872cf676a50..cd22b82e7bb8 100644 > --- a/fs/nfs/proc.c > +++ b/fs/nfs/proc.c > @@ -705,7 +705,7 @@ const struct nfs_rpc_ops nfs_v2_clientops = { > .file_ops = &nfs_file_operations, > .getroot = nfs_proc_get_root, > .submount = nfs_submount, > - .try_mount = nfs_try_mount, > + .try_get_tree = nfs_try_get_tree, > .getattr = nfs_proc_getattr, > .setattr = nfs_proc_setattr, > .lookup = nfs_proc_lookup, > diff --git a/fs/nfs/super.c b/fs/nfs/super.c > index c13f0ff42df9..3ef689c08f48 100644 > --- a/fs/nfs/super.c > +++ b/fs/nfs/super.c > @@ -69,27 +69,6 @@ > > #define NFSDBG_FACILITY NFSDBG_VFS > > -static struct dentry *nfs_xdev_mount(struct file_system_type *fs_type, > - int flags, const char *dev_name, void *raw_data); > - > -struct file_system_type nfs_fs_type = { > - .owner = THIS_MODULE, > - .name = "nfs", > - .mount = nfs_fs_mount, > - .kill_sb = nfs_kill_super, > - .fs_flags = FS_RENAME_DOES_D_MOVE|FS_BINARY_MOUNTDATA, > -}; > -MODULE_ALIAS_FS("nfs"); > -EXPORT_SYMBOL_GPL(nfs_fs_type); > - > -struct file_system_type nfs_xdev_fs_type = { > - .owner = THIS_MODULE, > - .name = "nfs", > - .mount = nfs_xdev_mount, > - .kill_sb = nfs_kill_super, > - .fs_flags = FS_RENAME_DOES_D_MOVE|FS_BINARY_MOUNTDATA, > -}; > - > const struct super_operations nfs_sops = { > .alloc_inode = nfs_alloc_inode, > .destroy_inode = nfs_destroy_inode, > @@ -102,22 +81,11 @@ const struct super_operations nfs_sops = { > .show_devname = nfs_show_devname, > .show_path = nfs_show_path, > .show_stats = nfs_show_stats, > - .remount_fs = nfs_remount, > + .remount_fs_fc = nfs_remount, > }; > EXPORT_SYMBOL_GPL(nfs_sops); > > #if IS_ENABLED(CONFIG_NFS_V4) > -struct file_system_type nfs4_fs_type = { > - .owner = THIS_MODULE, > - .name = "nfs4", > - .mount = nfs_fs_mount, > - .kill_sb = nfs_kill_super, > - .fs_flags = FS_RENAME_DOES_D_MOVE|FS_BINARY_MOUNTDATA, > -}; > -MODULE_ALIAS_FS("nfs4"); > -MODULE_ALIAS("nfs4"); > -EXPORT_SYMBOL_GPL(nfs4_fs_type); > - > static int __init register_nfs4_fs(void) > { > return register_filesystem(&nfs4_fs_type); > @@ -710,11 +678,11 @@ bool nfs_auth_info_match(const struct nfs_auth_info *auth_info, > EXPORT_SYMBOL_GPL(nfs_auth_info_match); > > /* > - * Ensure that a specified authtype in cfg->auth_info is supported by > - * the server. Returns 0 and sets cfg->selected_flavor if it's ok, and > + * Ensure that a specified authtype in ctx->auth_info is supported by > + * the server. Returns 0 and sets ctx->selected_flavor if it's ok, and > * -EACCES if not. > */ > -static int nfs_verify_authflavors(struct nfs_fs_context *cfg, > +static int nfs_verify_authflavors(struct nfs_fs_context *ctx, > rpc_authflavor_t *server_authlist, unsigned int count) > { > rpc_authflavor_t flavor = RPC_AUTH_MAXFLAVOR; > @@ -732,7 +700,7 @@ static int nfs_verify_authflavors(struct nfs_fs_context *cfg, > for (i = 0; i < count; i++) { > flavor = server_authlist[i]; > > - if (nfs_auth_info_match(&cfg->auth_info, flavor)) > + if (nfs_auth_info_match(&ctx->auth_info, flavor)) > goto out; > > if (flavor == RPC_AUTH_NULL) > @@ -749,8 +717,8 @@ static int nfs_verify_authflavors(struct nfs_fs_context *cfg, > return -EACCES; > > out: > - cfg->selected_flavor = flavor; > - dfprintk(MOUNT, "NFS: using auth flavor %u\n", cfg->selected_flavor); > + ctx->selected_flavor = flavor; > + dfprintk(MOUNT, "NFS: using auth flavor %u\n", ctx->selected_flavor); > return 0; > } > > @@ -758,50 +726,50 @@ static int nfs_verify_authflavors(struct nfs_fs_context *cfg, > * Use the remote server's MOUNT service to request the NFS file handle > * corresponding to the provided path. > */ > -static int nfs_request_mount(struct nfs_fs_context *cfg, > +static int nfs_request_mount(struct nfs_fs_context *ctx, > struct nfs_fh *root_fh, > rpc_authflavor_t *server_authlist, > unsigned int *server_authlist_len) > { > struct nfs_mount_request request = { > .sap = (struct sockaddr *) > - &cfg->mount_server.address, > - .dirpath = cfg->nfs_server.export_path, > - .protocol = cfg->mount_server.protocol, > + &ctx->mount_server.address, > + .dirpath = ctx->nfs_server.export_path, > + .protocol = ctx->mount_server.protocol, > .fh = root_fh, > - .noresvport = cfg->flags & NFS_MOUNT_NORESVPORT, > + .noresvport = ctx->flags & NFS_MOUNT_NORESVPORT, > .auth_flav_len = server_authlist_len, > .auth_flavs = server_authlist, > - .net = cfg->net, > + .net = ctx->fc.net_ns, > }; > int status; > > - if (cfg->mount_server.version == 0) { > - switch (cfg->version) { > + if (ctx->mount_server.version == 0) { > + switch (ctx->version) { > default: > - cfg->mount_server.version = NFS_MNT3_VERSION; > + ctx->mount_server.version = NFS_MNT3_VERSION; > break; > case 2: > - cfg->mount_server.version = NFS_MNT_VERSION; > + ctx->mount_server.version = NFS_MNT_VERSION; > } > } > - request.version = cfg->mount_server.version; > + request.version = ctx->mount_server.version; > > - if (cfg->mount_server.hostname) > - request.hostname = cfg->mount_server.hostname; > + if (ctx->mount_server.hostname) > + request.hostname = ctx->mount_server.hostname; > else > - request.hostname = cfg->nfs_server.hostname; > + request.hostname = ctx->nfs_server.hostname; > > /* > * Construct the mount server's address. > */ > - if (cfg->mount_server.address.sa_family == AF_UNSPEC) { > - memcpy(request.sap, &cfg->nfs_server.address, > - cfg->nfs_server.addrlen); > - cfg->mount_server.addrlen = cfg->nfs_server.addrlen; > + if (ctx->mount_server.address.sa_family == AF_UNSPEC) { > + memcpy(request.sap, &ctx->nfs_server.address, > + ctx->nfs_server.addrlen); > + ctx->mount_server.addrlen = ctx->nfs_server.addrlen; > } > - request.salen = cfg->mount_server.addrlen; > - nfs_set_port(request.sap, &cfg->mount_server.port, 0); > + request.salen = ctx->mount_server.addrlen; > + nfs_set_port(request.sap, &ctx->mount_server.port, 0); > > /* > * Now ask the mount server to map our export path > @@ -817,20 +785,17 @@ static int nfs_request_mount(struct nfs_fs_context *cfg, > return 0; > } > > -static struct nfs_server *nfs_try_mount_request(struct nfs_mount_info *mount_info, > - struct nfs_subversion *nfs_mod) > +static struct nfs_server *nfs_try_mount_request(struct nfs_fs_context *ctx) > { > int status; > unsigned int i; > bool tried_auth_unix = false; > bool auth_null_in_list = false; > struct nfs_server *server = ERR_PTR(-EACCES); > - struct nfs_fs_context *ctx = mount_info->ctx; > rpc_authflavor_t authlist[NFS_MAX_SECFLAVORS]; > unsigned int authlist_len = ARRAY_SIZE(authlist); > > - status = nfs_request_mount(ctx, mount_info->mntfh, authlist, > - &authlist_len); > + status = nfs_request_mount(ctx, ctx->mntfh, authlist, &authlist_len); > if (status) > return ERR_PTR(status); > > @@ -844,7 +809,7 @@ static struct nfs_server *nfs_try_mount_request(struct nfs_mount_info *mount_inf > ctx->selected_flavor); > if (status) > return ERR_PTR(status); > - return nfs_mod->rpc_ops->create_server(mount_info, nfs_mod); > + return ctx->nfs_mod->rpc_ops->create_server(ctx); > } > > /* > @@ -871,7 +836,7 @@ static struct nfs_server *nfs_try_mount_request(struct nfs_mount_info *mount_inf > } > dfprintk(MOUNT, "NFS: attempting to use auth flavor %u\n", flavor); > ctx->selected_flavor = flavor; > - server = nfs_mod->rpc_ops->create_server(mount_info, nfs_mod); > + server = ctx->nfs_mod->rpc_ops->create_server(ctx); > if (!IS_ERR(server)) > return server; > } > @@ -887,26 +852,27 @@ static struct nfs_server *nfs_try_mount_request(struct nfs_mount_info *mount_inf > /* Last chance! Try AUTH_UNIX */ > dfprintk(MOUNT, "NFS: attempting to use auth flavor %u\n", RPC_AUTH_UNIX); > ctx->selected_flavor = RPC_AUTH_UNIX; > - return nfs_mod->rpc_ops->create_server(mount_info, nfs_mod); > + return ctx->nfs_mod->rpc_ops->create_server(ctx); > } > > -struct dentry *nfs_try_mount(int flags, const char *dev_name, > - struct nfs_mount_info *mount_info, > - struct nfs_subversion *nfs_mod) > +int nfs_try_get_tree(struct nfs_fs_context *ctx) > { > struct nfs_server *server; > > - if (mount_info->ctx->need_mount) > - server = nfs_try_mount_request(mount_info, nfs_mod); > + if (ctx->need_mount) > + server = nfs_try_mount_request(ctx); > else > - server = nfs_mod->rpc_ops->create_server(mount_info, nfs_mod); > + server = ctx->nfs_mod->rpc_ops->create_server(ctx); > > - if (IS_ERR(server)) > - return ERR_CAST(server); > + if (IS_ERR(server)) { > + errorf("NFS: Couldn't create server"); > + return PTR_ERR(server); > + } > > - return nfs_fs_mount_common(server, flags, dev_name, mount_info, nfs_mod); > + return nfs_get_tree_common(server, ctx); > } > -EXPORT_SYMBOL_GPL(nfs_try_mount); > +EXPORT_SYMBOL_GPL(nfs_try_get_tree); > + > > #define NFS_REMOUNT_CMP_FLAGMASK ~(NFS_MOUNT_INTR \ > | NFS_MOUNT_SECURE \ > @@ -946,15 +912,11 @@ nfs_compare_remount_data(struct nfs_server *nfss, > return 0; > } > > -int > -nfs_remount(struct super_block *sb, int *flags, char *raw_data) > +int nfs_remount(struct super_block *sb, struct fs_context *fc) > { > - int error; > + struct nfs_fs_context *ctx = > + container_of(fc, struct nfs_fs_context, fc); > struct nfs_server *nfss = sb->s_fs_info; > - struct nfs_fs_context *ctx; > - struct nfs_mount_data *options = (struct nfs_mount_data *)raw_data; > - struct nfs4_mount_data *options4 = (struct nfs4_mount_data *)raw_data; > - u32 nfsvers = nfss->nfs_client->rpc_ops->version; > > sync_filesystem(sb); > > @@ -964,39 +926,9 @@ nfs_remount(struct super_block *sb, int *flags, char *raw_data) > * ones were explicitly specified. Fall back to legacy behavior and > * just return success. > */ > - if ((nfsvers == 4 && (!options4 || options4->version == 1)) || > - (nfsvers <= 3 && (!options || (options->version >= 1 && > - options->version <= 6)))) > + if (ctx->skip_remount_option_check) > return 0; > > - ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); > - if (ctx == NULL) > - return -ENOMEM; > - > - /* fill out struct with values from existing mount */ > - ctx->flags = nfss->flags; > - ctx->rsize = nfss->rsize; > - ctx->wsize = nfss->wsize; > - ctx->retrans = nfss->client->cl_timeout->to_retries; > - ctx->selected_flavor = nfss->client->cl_auth->au_flavor; > - ctx->acregmin = nfss->acregmin / HZ; > - ctx->acregmax = nfss->acregmax / HZ; > - ctx->acdirmin = nfss->acdirmin / HZ; > - ctx->acdirmax = nfss->acdirmax / HZ; > - ctx->timeo = 10U * nfss->client->cl_timeout->to_initval / HZ; > - ctx->nfs_server.port = nfss->port; > - ctx->nfs_server.addrlen = nfss->nfs_client->cl_addrlen; > - ctx->version = nfsvers; > - ctx->minorversion = nfss->nfs_client->cl_minorversion; > - ctx->net = current->nsproxy->net_ns; > - memcpy(&ctx->nfs_server.address, &nfss->nfs_client->cl_addr, > - ctx->nfs_server.addrlen); > - > - /* overwrite those values with any that were specified */ > - error = -EINVAL; > - if (!nfs_parse_mount_options((char *)options, ctx)) > - goto out; > - > /* > * noac is a special case. It implies -o sync, but that's not > * necessarily reflected in the mtab options. do_remount_sb > @@ -1004,13 +936,10 @@ nfs_remount(struct super_block *sb, int *flags, char *raw_data) > * remount options, so we have to explicitly reset it. > */ > if (ctx->flags & NFS_MOUNT_NOAC) > - *flags |= SB_SYNCHRONOUS; > + ctx->fc.sb_flags |= SB_SYNCHRONOUS; > > /* compare new mount options with old ones */ > - error = nfs_compare_remount_data(nfss, ctx); > -out: > - kfree(ctx); > - return error; > + return nfs_compare_remount_data(nfss, ctx); > } > EXPORT_SYMBOL_GPL(nfs_remount); > > @@ -1037,9 +966,8 @@ static void nfs_initialise_sb(struct super_block *sb) > /* > * Finish setting up an NFS2/3 superblock > */ > -void nfs_fill_super(struct super_block *sb, struct nfs_mount_info *mount_info) > +static void nfs_fill_super(struct super_block *sb, struct nfs_fs_context *ctx) > { > - struct nfs_fs_context *ctx = mount_info->ctx; > struct nfs_server *server = NFS_SB(sb); > > sb->s_blocksize_bits = 0; > @@ -1059,15 +987,13 @@ void nfs_fill_super(struct super_block *sb, struct nfs_mount_info *mount_info) > > nfs_initialise_sb(sb); > } > -EXPORT_SYMBOL_GPL(nfs_fill_super); > > /* > * Finish setting up a cloned NFS2/3/4 superblock > */ > -static void nfs_clone_super(struct super_block *sb, > - struct nfs_mount_info *mount_info) > +static void nfs_clone_super(struct super_block *sb, struct nfs_fs_context *ctx) > { > - const struct super_block *old_sb = mount_info->cloned->sb; > + const struct super_block *old_sb = ctx->clone_data.sb; > struct nfs_server *server = NFS_SB(sb); > > sb->s_blocksize_bits = old_sb->s_blocksize_bits; > @@ -1087,13 +1013,14 @@ static void nfs_clone_super(struct super_block *sb, > nfs_initialise_sb(sb); > } > > -static int nfs_compare_mount_options(const struct super_block *s, const struct nfs_server *b, int flags) > +static int nfs_compare_mount_options(const struct super_block *s, const struct nfs_server *b, > + const struct nfs_fs_context *ctx) > { > const struct nfs_server *a = s->s_fs_info; > const struct rpc_clnt *clnt_a = a->client; > const struct rpc_clnt *clnt_b = b->client; > > - if ((s->s_flags & NFS_SB_MASK) != (flags & NFS_SB_MASK)) > + if ((s->s_flags & NFS_SB_MASK) != (ctx->fc.sb_flags & NFS_SB_MASK)) > goto Ebusy; > if (a->nfs_client != b->nfs_client) > goto Ebusy; > @@ -1119,18 +1046,13 @@ static int nfs_compare_mount_options(const struct super_block *s, const struct n > return 0; > } > > -struct nfs_sb_mountdata { > - struct nfs_server *server; > - int mntflags; > -}; > - > -static int nfs_set_super(struct super_block *s, void *data) > +static int nfs_set_super(struct super_block *s, struct fs_context *fc) > { > - struct nfs_sb_mountdata *sb_mntdata = data; > - struct nfs_server *server = sb_mntdata->server; > + struct nfs_fs_context *ctx = container_of(fc, struct nfs_fs_context, fc); > + struct nfs_server *server = ctx->server; > int ret; > > - s->s_flags = sb_mntdata->mntflags; > + s->s_flags = ctx->fc.sb_flags; > s->s_fs_info = server; > s->s_d_op = server->nfs_client->rpc_ops->dentry_ops; > ret = set_anon_super(s, server); > @@ -1181,11 +1103,10 @@ static int nfs_compare_super_address(struct nfs_server *server1, > return 1; > } > > -static int nfs_compare_super(struct super_block *sb, void *data) > +static int nfs_compare_super(struct super_block *sb, struct fs_context *fc) > { > - struct nfs_sb_mountdata *sb_mntdata = data; > - struct nfs_server *server = sb_mntdata->server, *old = NFS_SB(sb); > - int mntflags = sb_mntdata->mntflags; > + struct nfs_fs_context *ctx = container_of(fc, struct nfs_fs_context, fc); > + struct nfs_server *server = ctx->server, *old = NFS_SB(sb); > > if (!nfs_compare_super_address(old, server)) > return 0; > @@ -1194,13 +1115,12 @@ static int nfs_compare_super(struct super_block *sb, void *data) > return 0; > if (memcmp(&old->fsid, &server->fsid, sizeof(old->fsid)) != 0) > return 0; > - return nfs_compare_mount_options(sb, server, mntflags); > + return nfs_compare_mount_options(sb, server, ctx); > } > > #ifdef CONFIG_NFS_FSCACHE > static void nfs_get_cache_cookie(struct super_block *sb, > - struct nfs_fs_context *ctx, > - struct nfs_clone_mount *cloned) > + struct nfs_fs_context *ctx) > { > struct nfs_server *nfss = NFS_SB(sb); > char *uniq = NULL; > @@ -1209,77 +1129,72 @@ static void nfs_get_cache_cookie(struct super_block *sb, > nfss->fscache_key = NULL; > nfss->fscache = NULL; > > - if (ctx) { > + if (!ctx) > + return; > + > + if (ctx->clone_data.cloned) { > + struct nfs_server *mnt_s = NFS_SB(ctx->clone_data.sb); > + if (!(mnt_s->options & NFS_OPTION_FSCACHE)) > + return; > + if (mnt_s->fscache_key) { > + uniq = mnt_s->fscache_key->key.uniquifier; > + ulen = mnt_s->fscache_key->key.uniq_len; > + } > + } else { > if (!(ctx->options & NFS_OPTION_FSCACHE)) > return; > if (ctx->fscache_uniq) { > uniq = ctx->fscache_uniq; > ulen = strlen(ctx->fscache_uniq); > } > - } else if (cloned) { > - struct nfs_server *mnt_s = NFS_SB(cloned->sb); > - if (!(mnt_s->options & NFS_OPTION_FSCACHE)) > - return; > - if (mnt_s->fscache_key) { > - uniq = mnt_s->fscache_key->key.uniquifier; > - ulen = mnt_s->fscache_key->key.uniq_len; > - }; > - } else > return; > + } > > nfs_fscache_get_super_cookie(sb, uniq, ulen); > } > #else > static void nfs_get_cache_cookie(struct super_block *sb, > - struct nfs_fs_context *parsed, > - struct nfs_clone_mount *cloned) > + struct nfs_fs_context *ctx) > { > } > #endif > > -int nfs_set_sb_security(struct super_block *s, struct dentry *mntroot, > - struct nfs_mount_info *mount_info) > +int nfs_set_sb_security(struct super_block *sb, struct nfs_fs_context *ctx) > { > int error; > unsigned long kflags = 0, kflags_out = 0; > - if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL) > + > + if (NFS_SB(sb)->caps & NFS_CAP_SECURITY_LABEL) > kflags |= SECURITY_LSM_NATIVE_LABELS; > > - error = security_sb_set_mnt_opts(s, &mount_info->ctx->lsm_opts, > - kflags, &kflags_out); > + error = security_sb_set_mnt_opts(sb, ctx->fc.security, > + kflags, &kflags_out); > if (error) > goto err; > > - if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL && > - !(kflags_out & SECURITY_LSM_NATIVE_LABELS)) > - NFS_SB(s)->caps &= ~NFS_CAP_SECURITY_LABEL; > + if (NFS_SB(sb)->caps & NFS_CAP_SECURITY_LABEL && > + !(kflags_out & SECURITY_LSM_NATIVE_LABELS)) > + NFS_SB(sb)->caps &= ~NFS_CAP_SECURITY_LABEL; > err: > return error; > } > EXPORT_SYMBOL_GPL(nfs_set_sb_security); > > -int nfs_clone_sb_security(struct super_block *s, struct dentry *mntroot, > - struct nfs_mount_info *mount_info) > +int nfs_clone_sb_security(struct super_block *sb, struct nfs_fs_context *ctx) > { > /* clone any lsm security options from the parent to the new sb */ > - if (d_inode(mntroot)->i_op != NFS_SB(s)->nfs_client->rpc_ops->dir_inode_ops) > + if (d_inode(ctx->fc.root)->i_op != > + NFS_SB(sb)->nfs_client->rpc_ops->dir_inode_ops) > return -ESTALE; > - return security_sb_clone_mnt_opts(mount_info->cloned->sb, s); > + return security_sb_clone_mnt_opts(ctx->clone_data.sb, sb); > } > EXPORT_SYMBOL_GPL(nfs_clone_sb_security); > > -struct dentry *nfs_fs_mount_common(struct nfs_server *server, > - int flags, const char *dev_name, > - struct nfs_mount_info *mount_info, > - struct nfs_subversion *nfs_mod) > +int nfs_get_tree_common(struct nfs_server *server, struct nfs_fs_context *ctx) > { > struct super_block *s; > struct dentry *mntroot = ERR_PTR(-ENOMEM); > - int (*compare_super)(struct super_block *, void *) = nfs_compare_super; > - struct nfs_sb_mountdata sb_mntdata = { > - .mntflags = flags, > - .server = server, > - }; > + int (*compare_super)(struct super_block *, struct fs_context *) = nfs_compare_super; > int error; > > if (server->flags & NFS_MOUNT_UNSHARED) > @@ -1287,16 +1202,19 @@ struct dentry *nfs_fs_mount_common(struct nfs_server *server, > > /* -o noac implies -o sync */ > if (server->flags & NFS_MOUNT_NOAC) > - sb_mntdata.mntflags |= SB_SYNCHRONOUS; > + ctx->fc.sb_flags |= SB_SYNCHRONOUS; > > - if (mount_info->cloned != NULL && mount_info->cloned->sb != NULL) > - if (mount_info->cloned->sb->s_flags & SB_SYNCHRONOUS) > - sb_mntdata.mntflags |= SB_SYNCHRONOUS; > + if (ctx->clone_data.cloned && ctx->clone_data.sb != NULL) > + if (ctx->clone_data.sb->s_flags & SB_SYNCHRONOUS) > + ctx->fc.sb_flags |= SB_SYNCHRONOUS; > > /* Get a superblock - note that we may end up sharing one that already exists */ > - s = sget(nfs_mod->nfs_fs, compare_super, nfs_set_super, flags, &sb_mntdata); > + ctx->server = server; > + s = sget_fc(&ctx->fc, compare_super, nfs_set_super); > + ctx->server = NULL; > if (IS_ERR(s)) { > - mntroot = ERR_CAST(s); > + error = PTR_ERR(s); > + errorf("NFS: Couldn't get superblock"); > goto out_err_nosb; > } > > @@ -1316,22 +1234,28 @@ struct dentry *nfs_fs_mount_common(struct nfs_server *server, > > if (!s->s_root) { > /* initial superblock/root creation */ > - mount_info->fill_super(s, mount_info); > - nfs_get_cache_cookie(s, mount_info->ctx, mount_info->cloned); > + if (ctx->clone_data.sb) > + nfs_clone_super(s, ctx); > + else > + nfs_fill_super(s, ctx); > + nfs_get_cache_cookie(s, ctx); > } > > - mntroot = nfs_get_root(s, mount_info->mntfh, dev_name); > - if (IS_ERR(mntroot)) > + error = nfs_get_root(s, ctx); > + if (error < 0) { > + errorf("NFS: Couldn't get root dentry"); > goto error_splat_super; > + } > > - error = mount_info->set_security(s, mntroot, mount_info); > + error = ctx->set_security(s, ctx); > if (error) > goto error_splat_root; > > s->s_flags |= SB_ACTIVE; > + error = 0; > > out: > - return mntroot; > + return error; > > out_err_nosb: > nfs_free_server(server); > @@ -1339,53 +1263,11 @@ struct dentry *nfs_fs_mount_common(struct nfs_server *server, > > error_splat_root: > dput(mntroot); > - mntroot = ERR_PTR(error); > error_splat_super: > deactivate_locked_super(s); > goto out; > } > -EXPORT_SYMBOL_GPL(nfs_fs_mount_common); > - > -struct dentry *nfs_fs_mount(struct file_system_type *fs_type, > - int flags, const char *dev_name, void *raw_data) > -{ > - struct nfs_mount_info mount_info = { > - .fill_super = nfs_fill_super, > - .set_security = nfs_set_sb_security, > - }; > - struct dentry *mntroot = ERR_PTR(-ENOMEM); > - struct nfs_subversion *nfs_mod; > - int error; > - > - mount_info.ctx = nfs_alloc_parsed_mount_data(); > - mount_info.mntfh = nfs_alloc_fhandle(); > - if (mount_info.ctx == NULL || mount_info.mntfh == NULL) > - goto out; > - > - /* Validate the mount data */ > - error = nfs_validate_mount_data(fs_type, raw_data, mount_info.ctx, mount_info.mntfh, dev_name); > - if (error == NFS_TEXT_DATA) > - error = nfs_validate_text_mount_data(raw_data, mount_info.ctx, dev_name); > - if (error < 0) { > - mntroot = ERR_PTR(error); > - goto out; > - } > - > - nfs_mod = get_nfs_version(mount_info.ctx->version); > - if (IS_ERR(nfs_mod)) { > - mntroot = ERR_CAST(nfs_mod); > - goto out; > - } > - > - mntroot = nfs_mod->rpc_ops->try_mount(flags, dev_name, &mount_info, nfs_mod); > - > - put_nfs_version(nfs_mod); > -out: > - nfs_free_parsed_mount_data(mount_info.ctx); > - nfs_free_fhandle(mount_info.mntfh); > - return mntroot; > -} > -EXPORT_SYMBOL_GPL(nfs_fs_mount); > +EXPORT_SYMBOL_GPL(nfs_get_tree_common); > > /* > * Destroy an NFS2/3 superblock > @@ -1404,41 +1286,6 @@ void nfs_kill_super(struct super_block *s) > } > EXPORT_SYMBOL_GPL(nfs_kill_super); > > -/* > - * Clone an NFS2/3/4 server record on xdev traversal (FSID-change) > - */ > -static struct dentry * > -nfs_xdev_mount(struct file_system_type *fs_type, int flags, > - const char *dev_name, void *raw_data) > -{ > - struct nfs_clone_mount *data = raw_data; > - struct nfs_mount_info mount_info = { > - .fill_super = nfs_clone_super, > - .set_security = nfs_clone_sb_security, > - .cloned = data, > - }; > - struct nfs_server *server; > - struct dentry *mntroot = ERR_PTR(-ENOMEM); > - struct nfs_subversion *nfs_mod = NFS_SB(data->sb)->nfs_client->cl_nfs_mod; > - > - dprintk("--> nfs_xdev_mount()\n"); > - > - mount_info.mntfh = mount_info.cloned->fh; > - > - /* create a new volume representation */ > - server = nfs_mod->rpc_ops->clone_server(NFS_SB(data->sb), data->fh, data->fattr, data->authflavor); > - > - if (IS_ERR(server)) > - mntroot = ERR_CAST(server); > - else > - mntroot = nfs_fs_mount_common(server, flags, > - dev_name, &mount_info, nfs_mod); > - > - dprintk("<-- nfs_xdev_mount() = %ld\n", > - IS_ERR(mntroot) ? PTR_ERR(mntroot) : 0L); > - return mntroot; > -} > - > #if IS_ENABLED(CONFIG_NFS_V4) > > /* > diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h > index b28c83475ee8..71697103a887 100644 > --- a/include/linux/nfs_xdr.h > +++ b/include/linux/nfs_xdr.h > @@ -1542,6 +1542,7 @@ struct nfs_subversion; > struct nfs_mount_info; > struct nfs_client_initdata; > struct nfs_pageio_descriptor; > +struct nfs_fs_context; > > /* > * RPC procedure vector for NFSv2/NFSv3 demuxing > @@ -1556,10 +1557,10 @@ struct nfs_rpc_ops { > > int (*getroot) (struct nfs_server *, struct nfs_fh *, > struct nfs_fsinfo *); > + int (*get_tree)(struct nfs_fs_context *); > struct vfsmount *(*submount) (struct nfs_server *, struct dentry *, > struct nfs_fh *, struct nfs_fattr *); > - struct dentry *(*try_mount) (int, const char *, struct nfs_mount_info *, > - struct nfs_subversion *); > + int (*try_get_tree) (struct nfs_fs_context *); > int (*getattr) (struct nfs_server *, struct nfs_fh *, > struct nfs_fattr *, struct nfs4_label *); > int (*setattr) (struct dentry *, struct nfs_fattr *, > @@ -1620,7 +1621,7 @@ struct nfs_rpc_ops { > struct nfs_client *(*init_client) (struct nfs_client *, > const struct nfs_client_initdata *); > void (*free_client) (struct nfs_client *); > - struct nfs_server *(*create_server)(struct nfs_mount_info *, struct nfs_subversion *); > + struct nfs_server *(*create_server)(struct nfs_fs_context *); > struct nfs_server *(*clone_server)(struct nfs_server *, struct nfs_fh *, > struct nfs_fattr *, rpc_authflavor_t); > }; > > -- > To unsubscribe from this list: send the line "unsubscribe linux-nfs" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html >