18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* -*- mode: c; c-basic-offset: 8; -*- 38c2ecf20Sopenharmony_ci * vim: noexpandtab sw=8 ts=8 sts=0: 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * export.c 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Functions to facilitate NFS exporting 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Copyright (C) 2002, 2005 Oracle. All rights reserved. 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/fs.h> 138c2ecf20Sopenharmony_ci#include <linux/types.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <cluster/masklog.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include "ocfs2.h" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include "alloc.h" 208c2ecf20Sopenharmony_ci#include "dir.h" 218c2ecf20Sopenharmony_ci#include "dlmglue.h" 228c2ecf20Sopenharmony_ci#include "dcache.h" 238c2ecf20Sopenharmony_ci#include "export.h" 248c2ecf20Sopenharmony_ci#include "inode.h" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#include "buffer_head_io.h" 278c2ecf20Sopenharmony_ci#include "suballoc.h" 288c2ecf20Sopenharmony_ci#include "ocfs2_trace.h" 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistruct ocfs2_inode_handle 318c2ecf20Sopenharmony_ci{ 328c2ecf20Sopenharmony_ci u64 ih_blkno; 338c2ecf20Sopenharmony_ci u32 ih_generation; 348c2ecf20Sopenharmony_ci}; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistatic struct dentry *ocfs2_get_dentry(struct super_block *sb, 378c2ecf20Sopenharmony_ci struct ocfs2_inode_handle *handle) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci struct inode *inode; 408c2ecf20Sopenharmony_ci struct ocfs2_super *osb = OCFS2_SB(sb); 418c2ecf20Sopenharmony_ci u64 blkno = handle->ih_blkno; 428c2ecf20Sopenharmony_ci int status, set; 438c2ecf20Sopenharmony_ci struct dentry *result; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci trace_ocfs2_get_dentry_begin(sb, handle, (unsigned long long)blkno); 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci if (blkno == 0) { 488c2ecf20Sopenharmony_ci result = ERR_PTR(-ESTALE); 498c2ecf20Sopenharmony_ci goto bail; 508c2ecf20Sopenharmony_ci } 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci inode = ocfs2_ilookup(sb, blkno); 538c2ecf20Sopenharmony_ci /* 548c2ecf20Sopenharmony_ci * If the inode exists in memory, we only need to check it's 558c2ecf20Sopenharmony_ci * generation number 568c2ecf20Sopenharmony_ci */ 578c2ecf20Sopenharmony_ci if (inode) 588c2ecf20Sopenharmony_ci goto check_gen; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci /* 618c2ecf20Sopenharmony_ci * This will synchronize us against ocfs2_delete_inode() on 628c2ecf20Sopenharmony_ci * all nodes 638c2ecf20Sopenharmony_ci */ 648c2ecf20Sopenharmony_ci status = ocfs2_nfs_sync_lock(osb, 1); 658c2ecf20Sopenharmony_ci if (status < 0) { 668c2ecf20Sopenharmony_ci mlog(ML_ERROR, "getting nfs sync lock(EX) failed %d\n", status); 678c2ecf20Sopenharmony_ci goto check_err; 688c2ecf20Sopenharmony_ci } 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci status = ocfs2_test_inode_bit(osb, blkno, &set); 718c2ecf20Sopenharmony_ci if (status < 0) { 728c2ecf20Sopenharmony_ci if (status == -EINVAL) { 738c2ecf20Sopenharmony_ci /* 748c2ecf20Sopenharmony_ci * The blkno NFS gave us doesn't even show up 758c2ecf20Sopenharmony_ci * as an inode, we return -ESTALE to be 768c2ecf20Sopenharmony_ci * nice 778c2ecf20Sopenharmony_ci */ 788c2ecf20Sopenharmony_ci status = -ESTALE; 798c2ecf20Sopenharmony_ci } else 808c2ecf20Sopenharmony_ci mlog(ML_ERROR, "test inode bit failed %d\n", status); 818c2ecf20Sopenharmony_ci goto unlock_nfs_sync; 828c2ecf20Sopenharmony_ci } 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci trace_ocfs2_get_dentry_test_bit(status, set); 858c2ecf20Sopenharmony_ci /* If the inode allocator bit is clear, this inode must be stale */ 868c2ecf20Sopenharmony_ci if (!set) { 878c2ecf20Sopenharmony_ci status = -ESTALE; 888c2ecf20Sopenharmony_ci goto unlock_nfs_sync; 898c2ecf20Sopenharmony_ci } 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci inode = ocfs2_iget(osb, blkno, 0, 0); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ciunlock_nfs_sync: 948c2ecf20Sopenharmony_ci ocfs2_nfs_sync_unlock(osb, 1); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cicheck_err: 978c2ecf20Sopenharmony_ci if (status < 0) { 988c2ecf20Sopenharmony_ci if (status == -ESTALE) { 998c2ecf20Sopenharmony_ci trace_ocfs2_get_dentry_stale((unsigned long long)blkno, 1008c2ecf20Sopenharmony_ci handle->ih_generation); 1018c2ecf20Sopenharmony_ci } 1028c2ecf20Sopenharmony_ci result = ERR_PTR(status); 1038c2ecf20Sopenharmony_ci goto bail; 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci if (IS_ERR(inode)) { 1078c2ecf20Sopenharmony_ci mlog_errno(PTR_ERR(inode)); 1088c2ecf20Sopenharmony_ci result = ERR_CAST(inode); 1098c2ecf20Sopenharmony_ci goto bail; 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cicheck_gen: 1138c2ecf20Sopenharmony_ci if (handle->ih_generation != inode->i_generation) { 1148c2ecf20Sopenharmony_ci trace_ocfs2_get_dentry_generation((unsigned long long)blkno, 1158c2ecf20Sopenharmony_ci handle->ih_generation, 1168c2ecf20Sopenharmony_ci inode->i_generation); 1178c2ecf20Sopenharmony_ci iput(inode); 1188c2ecf20Sopenharmony_ci result = ERR_PTR(-ESTALE); 1198c2ecf20Sopenharmony_ci goto bail; 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci result = d_obtain_alias(inode); 1238c2ecf20Sopenharmony_ci if (IS_ERR(result)) 1248c2ecf20Sopenharmony_ci mlog_errno(PTR_ERR(result)); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cibail: 1278c2ecf20Sopenharmony_ci trace_ocfs2_get_dentry_end(result); 1288c2ecf20Sopenharmony_ci return result; 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistatic struct dentry *ocfs2_get_parent(struct dentry *child) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci int status; 1348c2ecf20Sopenharmony_ci u64 blkno; 1358c2ecf20Sopenharmony_ci struct dentry *parent; 1368c2ecf20Sopenharmony_ci struct inode *dir = d_inode(child); 1378c2ecf20Sopenharmony_ci int set; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci trace_ocfs2_get_parent(child, child->d_name.len, child->d_name.name, 1408c2ecf20Sopenharmony_ci (unsigned long long)OCFS2_I(dir)->ip_blkno); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci status = ocfs2_nfs_sync_lock(OCFS2_SB(dir->i_sb), 1); 1438c2ecf20Sopenharmony_ci if (status < 0) { 1448c2ecf20Sopenharmony_ci mlog(ML_ERROR, "getting nfs sync lock(EX) failed %d\n", status); 1458c2ecf20Sopenharmony_ci parent = ERR_PTR(status); 1468c2ecf20Sopenharmony_ci goto bail; 1478c2ecf20Sopenharmony_ci } 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci status = ocfs2_inode_lock(dir, NULL, 0); 1508c2ecf20Sopenharmony_ci if (status < 0) { 1518c2ecf20Sopenharmony_ci if (status != -ENOENT) 1528c2ecf20Sopenharmony_ci mlog_errno(status); 1538c2ecf20Sopenharmony_ci parent = ERR_PTR(status); 1548c2ecf20Sopenharmony_ci goto unlock_nfs_sync; 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci status = ocfs2_lookup_ino_from_name(dir, "..", 2, &blkno); 1588c2ecf20Sopenharmony_ci if (status < 0) { 1598c2ecf20Sopenharmony_ci parent = ERR_PTR(-ENOENT); 1608c2ecf20Sopenharmony_ci goto bail_unlock; 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci status = ocfs2_test_inode_bit(OCFS2_SB(dir->i_sb), blkno, &set); 1648c2ecf20Sopenharmony_ci if (status < 0) { 1658c2ecf20Sopenharmony_ci if (status == -EINVAL) { 1668c2ecf20Sopenharmony_ci status = -ESTALE; 1678c2ecf20Sopenharmony_ci } else 1688c2ecf20Sopenharmony_ci mlog(ML_ERROR, "test inode bit failed %d\n", status); 1698c2ecf20Sopenharmony_ci parent = ERR_PTR(status); 1708c2ecf20Sopenharmony_ci goto bail_unlock; 1718c2ecf20Sopenharmony_ci } 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci trace_ocfs2_get_dentry_test_bit(status, set); 1748c2ecf20Sopenharmony_ci if (!set) { 1758c2ecf20Sopenharmony_ci status = -ESTALE; 1768c2ecf20Sopenharmony_ci parent = ERR_PTR(status); 1778c2ecf20Sopenharmony_ci goto bail_unlock; 1788c2ecf20Sopenharmony_ci } 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci parent = d_obtain_alias(ocfs2_iget(OCFS2_SB(dir->i_sb), blkno, 0, 0)); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_cibail_unlock: 1838c2ecf20Sopenharmony_ci ocfs2_inode_unlock(dir, 0); 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ciunlock_nfs_sync: 1868c2ecf20Sopenharmony_ci ocfs2_nfs_sync_unlock(OCFS2_SB(dir->i_sb), 1); 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cibail: 1898c2ecf20Sopenharmony_ci trace_ocfs2_get_parent_end(parent); 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci return parent; 1928c2ecf20Sopenharmony_ci} 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_cistatic int ocfs2_encode_fh(struct inode *inode, u32 *fh_in, int *max_len, 1958c2ecf20Sopenharmony_ci struct inode *parent) 1968c2ecf20Sopenharmony_ci{ 1978c2ecf20Sopenharmony_ci int len = *max_len; 1988c2ecf20Sopenharmony_ci int type = 1; 1998c2ecf20Sopenharmony_ci u64 blkno; 2008c2ecf20Sopenharmony_ci u32 generation; 2018c2ecf20Sopenharmony_ci __le32 *fh = (__force __le32 *) fh_in; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci#ifdef TRACE_HOOKS_ARE_NOT_BRAINDEAD_IN_YOUR_OPINION 2048c2ecf20Sopenharmony_ci#error "You go ahead and fix that mess, then. Somehow" 2058c2ecf20Sopenharmony_ci trace_ocfs2_encode_fh_begin(dentry, dentry->d_name.len, 2068c2ecf20Sopenharmony_ci dentry->d_name.name, 2078c2ecf20Sopenharmony_ci fh, len, connectable); 2088c2ecf20Sopenharmony_ci#endif 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci if (parent && (len < 6)) { 2118c2ecf20Sopenharmony_ci *max_len = 6; 2128c2ecf20Sopenharmony_ci type = FILEID_INVALID; 2138c2ecf20Sopenharmony_ci goto bail; 2148c2ecf20Sopenharmony_ci } else if (len < 3) { 2158c2ecf20Sopenharmony_ci *max_len = 3; 2168c2ecf20Sopenharmony_ci type = FILEID_INVALID; 2178c2ecf20Sopenharmony_ci goto bail; 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci blkno = OCFS2_I(inode)->ip_blkno; 2218c2ecf20Sopenharmony_ci generation = inode->i_generation; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci trace_ocfs2_encode_fh_self((unsigned long long)blkno, generation); 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci len = 3; 2268c2ecf20Sopenharmony_ci fh[0] = cpu_to_le32((u32)(blkno >> 32)); 2278c2ecf20Sopenharmony_ci fh[1] = cpu_to_le32((u32)(blkno & 0xffffffff)); 2288c2ecf20Sopenharmony_ci fh[2] = cpu_to_le32(generation); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci if (parent) { 2318c2ecf20Sopenharmony_ci blkno = OCFS2_I(parent)->ip_blkno; 2328c2ecf20Sopenharmony_ci generation = parent->i_generation; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci fh[3] = cpu_to_le32((u32)(blkno >> 32)); 2358c2ecf20Sopenharmony_ci fh[4] = cpu_to_le32((u32)(blkno & 0xffffffff)); 2368c2ecf20Sopenharmony_ci fh[5] = cpu_to_le32(generation); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci len = 6; 2398c2ecf20Sopenharmony_ci type = 2; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci trace_ocfs2_encode_fh_parent((unsigned long long)blkno, 2428c2ecf20Sopenharmony_ci generation); 2438c2ecf20Sopenharmony_ci } 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci *max_len = len; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_cibail: 2488c2ecf20Sopenharmony_ci trace_ocfs2_encode_fh_type(type); 2498c2ecf20Sopenharmony_ci return type; 2508c2ecf20Sopenharmony_ci} 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_cistatic struct dentry *ocfs2_fh_to_dentry(struct super_block *sb, 2538c2ecf20Sopenharmony_ci struct fid *fid, int fh_len, int fh_type) 2548c2ecf20Sopenharmony_ci{ 2558c2ecf20Sopenharmony_ci struct ocfs2_inode_handle handle; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci if (fh_len < 3 || fh_type > 2) 2588c2ecf20Sopenharmony_ci return NULL; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci handle.ih_blkno = (u64)le32_to_cpu(fid->raw[0]) << 32; 2618c2ecf20Sopenharmony_ci handle.ih_blkno |= (u64)le32_to_cpu(fid->raw[1]); 2628c2ecf20Sopenharmony_ci handle.ih_generation = le32_to_cpu(fid->raw[2]); 2638c2ecf20Sopenharmony_ci return ocfs2_get_dentry(sb, &handle); 2648c2ecf20Sopenharmony_ci} 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_cistatic struct dentry *ocfs2_fh_to_parent(struct super_block *sb, 2678c2ecf20Sopenharmony_ci struct fid *fid, int fh_len, int fh_type) 2688c2ecf20Sopenharmony_ci{ 2698c2ecf20Sopenharmony_ci struct ocfs2_inode_handle parent; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci if (fh_type != 2 || fh_len < 6) 2728c2ecf20Sopenharmony_ci return NULL; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci parent.ih_blkno = (u64)le32_to_cpu(fid->raw[3]) << 32; 2758c2ecf20Sopenharmony_ci parent.ih_blkno |= (u64)le32_to_cpu(fid->raw[4]); 2768c2ecf20Sopenharmony_ci parent.ih_generation = le32_to_cpu(fid->raw[5]); 2778c2ecf20Sopenharmony_ci return ocfs2_get_dentry(sb, &parent); 2788c2ecf20Sopenharmony_ci} 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ciconst struct export_operations ocfs2_export_ops = { 2818c2ecf20Sopenharmony_ci .encode_fh = ocfs2_encode_fh, 2828c2ecf20Sopenharmony_ci .fh_to_dentry = ocfs2_fh_to_dentry, 2838c2ecf20Sopenharmony_ci .fh_to_parent = ocfs2_fh_to_parent, 2848c2ecf20Sopenharmony_ci .get_parent = ocfs2_get_parent, 2858c2ecf20Sopenharmony_ci}; 286