1328970deSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2*fa60ce2cSMasahiro Yamada /*
3ccd979bdSMark Fasheh * export.c
4ccd979bdSMark Fasheh *
5ccd979bdSMark Fasheh * Functions to facilitate NFS exporting
6ccd979bdSMark Fasheh *
7ccd979bdSMark Fasheh * Copyright (C) 2002, 2005 Oracle. All rights reserved.
8ccd979bdSMark Fasheh */
9ccd979bdSMark Fasheh
10ccd979bdSMark Fasheh #include <linux/fs.h>
11ccd979bdSMark Fasheh #include <linux/types.h>
12ccd979bdSMark Fasheh
13ccd979bdSMark Fasheh #include <cluster/masklog.h>
14ccd979bdSMark Fasheh
15ccd979bdSMark Fasheh #include "ocfs2.h"
16ccd979bdSMark Fasheh
176ca497a8Swengang wang #include "alloc.h"
18ccd979bdSMark Fasheh #include "dir.h"
19ccd979bdSMark Fasheh #include "dlmglue.h"
20379dfe9dSMark Fasheh #include "dcache.h"
21ccd979bdSMark Fasheh #include "export.h"
22ccd979bdSMark Fasheh #include "inode.h"
23ccd979bdSMark Fasheh
24ccd979bdSMark Fasheh #include "buffer_head_io.h"
256ca497a8Swengang wang #include "suballoc.h"
26781f200cSTao Ma #include "ocfs2_trace.h"
27ccd979bdSMark Fasheh
28ccd979bdSMark Fasheh struct ocfs2_inode_handle
29ccd979bdSMark Fasheh {
30ccd979bdSMark Fasheh u64 ih_blkno;
31ccd979bdSMark Fasheh u32 ih_generation;
32ccd979bdSMark Fasheh };
33ccd979bdSMark Fasheh
ocfs2_get_dentry(struct super_block * sb,struct ocfs2_inode_handle * handle)34644f9ab3SChristoph Hellwig static struct dentry *ocfs2_get_dentry(struct super_block *sb,
35644f9ab3SChristoph Hellwig struct ocfs2_inode_handle *handle)
36ccd979bdSMark Fasheh {
37ccd979bdSMark Fasheh struct inode *inode;
386ca497a8Swengang wang struct ocfs2_super *osb = OCFS2_SB(sb);
396ca497a8Swengang wang u64 blkno = handle->ih_blkno;
406ca497a8Swengang wang int status, set;
41ccd979bdSMark Fasheh struct dentry *result;
42ccd979bdSMark Fasheh
43781f200cSTao Ma trace_ocfs2_get_dentry_begin(sb, handle, (unsigned long long)blkno);
44ccd979bdSMark Fasheh
456ca497a8Swengang wang if (blkno == 0) {
466ca497a8Swengang wang result = ERR_PTR(-ESTALE);
476ca497a8Swengang wang goto bail;
48ccd979bdSMark Fasheh }
49ccd979bdSMark Fasheh
506ca497a8Swengang wang inode = ocfs2_ilookup(sb, blkno);
516ca497a8Swengang wang /*
526ca497a8Swengang wang * If the inode exists in memory, we only need to check it's
536ca497a8Swengang wang * generation number
546ca497a8Swengang wang */
556ca497a8Swengang wang if (inode)
566ca497a8Swengang wang goto check_gen;
57ccd979bdSMark Fasheh
586ca497a8Swengang wang /*
596ca497a8Swengang wang * This will synchronize us against ocfs2_delete_inode() on
606ca497a8Swengang wang * all nodes
616ca497a8Swengang wang */
626ca497a8Swengang wang status = ocfs2_nfs_sync_lock(osb, 1);
636ca497a8Swengang wang if (status < 0) {
646ca497a8Swengang wang mlog(ML_ERROR, "getting nfs sync lock(EX) failed %d\n", status);
656ca497a8Swengang wang goto check_err;
666ca497a8Swengang wang }
67ccd979bdSMark Fasheh
686ca497a8Swengang wang status = ocfs2_test_inode_bit(osb, blkno, &set);
696ca497a8Swengang wang if (status < 0) {
706ca497a8Swengang wang if (status == -EINVAL) {
716ca497a8Swengang wang /*
726ca497a8Swengang wang * The blkno NFS gave us doesn't even show up
736ca497a8Swengang wang * as an inode, we return -ESTALE to be
746ca497a8Swengang wang * nice
756ca497a8Swengang wang */
766ca497a8Swengang wang status = -ESTALE;
77781f200cSTao Ma } else
786ca497a8Swengang wang mlog(ML_ERROR, "test inode bit failed %d\n", status);
796ca497a8Swengang wang goto unlock_nfs_sync;
806ca497a8Swengang wang }
816ca497a8Swengang wang
82023d4ea3SJoseph Qi trace_ocfs2_get_dentry_test_bit(status, set);
836ca497a8Swengang wang /* If the inode allocator bit is clear, this inode must be stale */
846ca497a8Swengang wang if (!set) {
856ca497a8Swengang wang status = -ESTALE;
866ca497a8Swengang wang goto unlock_nfs_sync;
876ca497a8Swengang wang }
886ca497a8Swengang wang
896ca497a8Swengang wang inode = ocfs2_iget(osb, blkno, 0, 0);
906ca497a8Swengang wang
916ca497a8Swengang wang unlock_nfs_sync:
926ca497a8Swengang wang ocfs2_nfs_sync_unlock(osb, 1);
936ca497a8Swengang wang
946ca497a8Swengang wang check_err:
956ca497a8Swengang wang if (status < 0) {
966ca497a8Swengang wang if (status == -ESTALE) {
97781f200cSTao Ma trace_ocfs2_get_dentry_stale((unsigned long long)blkno,
98781f200cSTao Ma handle->ih_generation);
996ca497a8Swengang wang }
1006ca497a8Swengang wang result = ERR_PTR(status);
1016ca497a8Swengang wang goto bail;
1026ca497a8Swengang wang }
1036ca497a8Swengang wang
1046ca497a8Swengang wang if (IS_ERR(inode)) {
1056ca497a8Swengang wang mlog_errno(PTR_ERR(inode));
1067585d12fSKees Cook result = ERR_CAST(inode);
1076ca497a8Swengang wang goto bail;
1086ca497a8Swengang wang }
1096ca497a8Swengang wang
1106ca497a8Swengang wang check_gen:
111ccd979bdSMark Fasheh if (handle->ih_generation != inode->i_generation) {
112781f200cSTao Ma trace_ocfs2_get_dentry_generation((unsigned long long)blkno,
113781f200cSTao Ma handle->ih_generation,
114781f200cSTao Ma inode->i_generation);
115164f7e58SPan Bian iput(inode);
1166ca497a8Swengang wang result = ERR_PTR(-ESTALE);
1176ca497a8Swengang wang goto bail;
118ccd979bdSMark Fasheh }
119ccd979bdSMark Fasheh
12044003728SChristoph Hellwig result = d_obtain_alias(inode);
121ba87167cSAl Viro if (IS_ERR(result))
1226ca497a8Swengang wang mlog_errno(PTR_ERR(result));
123ccd979bdSMark Fasheh
1246ca497a8Swengang wang bail:
125781f200cSTao Ma trace_ocfs2_get_dentry_end(result);
126ccd979bdSMark Fasheh return result;
127ccd979bdSMark Fasheh }
128ccd979bdSMark Fasheh
ocfs2_get_parent(struct dentry * child)129ccd979bdSMark Fasheh static struct dentry *ocfs2_get_parent(struct dentry *child)
130ccd979bdSMark Fasheh {
131ccd979bdSMark Fasheh int status;
132ccd979bdSMark Fasheh u64 blkno;
133ccd979bdSMark Fasheh struct dentry *parent;
1342b0143b5SDavid Howells struct inode *dir = d_inode(child);
135e091eab0SShuning Zhang int set;
136ccd979bdSMark Fasheh
137781f200cSTao Ma trace_ocfs2_get_parent(child, child->d_name.len, child->d_name.name,
138b0697053SMark Fasheh (unsigned long long)OCFS2_I(dir)->ip_blkno);
139ccd979bdSMark Fasheh
140e091eab0SShuning Zhang status = ocfs2_nfs_sync_lock(OCFS2_SB(dir->i_sb), 1);
141e091eab0SShuning Zhang if (status < 0) {
142e091eab0SShuning Zhang mlog(ML_ERROR, "getting nfs sync lock(EX) failed %d\n", status);
143e091eab0SShuning Zhang parent = ERR_PTR(status);
144e091eab0SShuning Zhang goto bail;
145e091eab0SShuning Zhang }
146e091eab0SShuning Zhang
147e63aecb6SMark Fasheh status = ocfs2_inode_lock(dir, NULL, 0);
148ccd979bdSMark Fasheh if (status < 0) {
149ccd979bdSMark Fasheh if (status != -ENOENT)
150ccd979bdSMark Fasheh mlog_errno(status);
151ccd979bdSMark Fasheh parent = ERR_PTR(status);
152e091eab0SShuning Zhang goto unlock_nfs_sync;
153ccd979bdSMark Fasheh }
154ccd979bdSMark Fasheh
155be94d117SMark Fasheh status = ocfs2_lookup_ino_from_name(dir, "..", 2, &blkno);
156ccd979bdSMark Fasheh if (status < 0) {
157ccd979bdSMark Fasheh parent = ERR_PTR(-ENOENT);
158ccd979bdSMark Fasheh goto bail_unlock;
159ccd979bdSMark Fasheh }
160ccd979bdSMark Fasheh
161e091eab0SShuning Zhang status = ocfs2_test_inode_bit(OCFS2_SB(dir->i_sb), blkno, &set);
162e091eab0SShuning Zhang if (status < 0) {
163e091eab0SShuning Zhang if (status == -EINVAL) {
164e091eab0SShuning Zhang status = -ESTALE;
165e091eab0SShuning Zhang } else
166e091eab0SShuning Zhang mlog(ML_ERROR, "test inode bit failed %d\n", status);
167e091eab0SShuning Zhang parent = ERR_PTR(status);
168e091eab0SShuning Zhang goto bail_unlock;
169e091eab0SShuning Zhang }
170e091eab0SShuning Zhang
171e091eab0SShuning Zhang trace_ocfs2_get_dentry_test_bit(status, set);
172e091eab0SShuning Zhang if (!set) {
173e091eab0SShuning Zhang status = -ESTALE;
174e091eab0SShuning Zhang parent = ERR_PTR(status);
175e091eab0SShuning Zhang goto bail_unlock;
176e091eab0SShuning Zhang }
177e091eab0SShuning Zhang
17844003728SChristoph Hellwig parent = d_obtain_alias(ocfs2_iget(OCFS2_SB(dir->i_sb), blkno, 0, 0));
179379dfe9dSMark Fasheh
180ccd979bdSMark Fasheh bail_unlock:
181e63aecb6SMark Fasheh ocfs2_inode_unlock(dir, 0);
182ccd979bdSMark Fasheh
183e091eab0SShuning Zhang unlock_nfs_sync:
184e091eab0SShuning Zhang ocfs2_nfs_sync_unlock(OCFS2_SB(dir->i_sb), 1);
185e091eab0SShuning Zhang
186ccd979bdSMark Fasheh bail:
187781f200cSTao Ma trace_ocfs2_get_parent_end(parent);
188ccd979bdSMark Fasheh
189ccd979bdSMark Fasheh return parent;
190ccd979bdSMark Fasheh }
191ccd979bdSMark Fasheh
ocfs2_encode_fh(struct inode * inode,u32 * fh_in,int * max_len,struct inode * parent)192b0b0382bSAl Viro static int ocfs2_encode_fh(struct inode *inode, u32 *fh_in, int *max_len,
193b0b0382bSAl Viro struct inode *parent)
194ccd979bdSMark Fasheh {
195ccd979bdSMark Fasheh int len = *max_len;
196ccd979bdSMark Fasheh int type = 1;
197ccd979bdSMark Fasheh u64 blkno;
198ccd979bdSMark Fasheh u32 generation;
1991ca1a111SMark Fasheh __le32 *fh = (__force __le32 *) fh_in;
200ccd979bdSMark Fasheh
201b0b0382bSAl Viro #ifdef TRACE_HOOKS_ARE_NOT_BRAINDEAD_IN_YOUR_OPINION
202b0b0382bSAl Viro #error "You go ahead and fix that mess, then. Somehow"
203781f200cSTao Ma trace_ocfs2_encode_fh_begin(dentry, dentry->d_name.len,
204781f200cSTao Ma dentry->d_name.name,
205ccd979bdSMark Fasheh fh, len, connectable);
206b0b0382bSAl Viro #endif
207ccd979bdSMark Fasheh
208b0b0382bSAl Viro if (parent && (len < 6)) {
2095fe0c237SAneesh Kumar K.V *max_len = 6;
21094e07a75SNamjae Jeon type = FILEID_INVALID;
2115fe0c237SAneesh Kumar K.V goto bail;
2125fe0c237SAneesh Kumar K.V } else if (len < 3) {
2135fe0c237SAneesh Kumar K.V *max_len = 3;
21494e07a75SNamjae Jeon type = FILEID_INVALID;
215ccd979bdSMark Fasheh goto bail;
216ccd979bdSMark Fasheh }
217ccd979bdSMark Fasheh
218ccd979bdSMark Fasheh blkno = OCFS2_I(inode)->ip_blkno;
219ccd979bdSMark Fasheh generation = inode->i_generation;
220ccd979bdSMark Fasheh
221781f200cSTao Ma trace_ocfs2_encode_fh_self((unsigned long long)blkno, generation);
222ccd979bdSMark Fasheh
223ccd979bdSMark Fasheh len = 3;
224ccd979bdSMark Fasheh fh[0] = cpu_to_le32((u32)(blkno >> 32));
225ccd979bdSMark Fasheh fh[1] = cpu_to_le32((u32)(blkno & 0xffffffff));
226ccd979bdSMark Fasheh fh[2] = cpu_to_le32(generation);
227ccd979bdSMark Fasheh
228b0b0382bSAl Viro if (parent) {
229ccd979bdSMark Fasheh blkno = OCFS2_I(parent)->ip_blkno;
230ccd979bdSMark Fasheh generation = parent->i_generation;
231ccd979bdSMark Fasheh
232ccd979bdSMark Fasheh fh[3] = cpu_to_le32((u32)(blkno >> 32));
233ccd979bdSMark Fasheh fh[4] = cpu_to_le32((u32)(blkno & 0xffffffff));
234ccd979bdSMark Fasheh fh[5] = cpu_to_le32(generation);
235ccd979bdSMark Fasheh
236ccd979bdSMark Fasheh len = 6;
237ccd979bdSMark Fasheh type = 2;
238ccd979bdSMark Fasheh
239781f200cSTao Ma trace_ocfs2_encode_fh_parent((unsigned long long)blkno,
240781f200cSTao Ma generation);
241ccd979bdSMark Fasheh }
242ccd979bdSMark Fasheh
243ccd979bdSMark Fasheh *max_len = len;
244ccd979bdSMark Fasheh
245ccd979bdSMark Fasheh bail:
246781f200cSTao Ma trace_ocfs2_encode_fh_type(type);
247ccd979bdSMark Fasheh return type;
248ccd979bdSMark Fasheh }
249ccd979bdSMark Fasheh
ocfs2_fh_to_dentry(struct super_block * sb,struct fid * fid,int fh_len,int fh_type)250644f9ab3SChristoph Hellwig static struct dentry *ocfs2_fh_to_dentry(struct super_block *sb,
251644f9ab3SChristoph Hellwig struct fid *fid, int fh_len, int fh_type)
252ccd979bdSMark Fasheh {
253644f9ab3SChristoph Hellwig struct ocfs2_inode_handle handle;
254ccd979bdSMark Fasheh
255644f9ab3SChristoph Hellwig if (fh_len < 3 || fh_type > 2)
256644f9ab3SChristoph Hellwig return NULL;
257ccd979bdSMark Fasheh
258644f9ab3SChristoph Hellwig handle.ih_blkno = (u64)le32_to_cpu(fid->raw[0]) << 32;
259644f9ab3SChristoph Hellwig handle.ih_blkno |= (u64)le32_to_cpu(fid->raw[1]);
260644f9ab3SChristoph Hellwig handle.ih_generation = le32_to_cpu(fid->raw[2]);
261644f9ab3SChristoph Hellwig return ocfs2_get_dentry(sb, &handle);
262ccd979bdSMark Fasheh }
263ccd979bdSMark Fasheh
ocfs2_fh_to_parent(struct super_block * sb,struct fid * fid,int fh_len,int fh_type)264644f9ab3SChristoph Hellwig static struct dentry *ocfs2_fh_to_parent(struct super_block *sb,
265644f9ab3SChristoph Hellwig struct fid *fid, int fh_len, int fh_type)
266644f9ab3SChristoph Hellwig {
267644f9ab3SChristoph Hellwig struct ocfs2_inode_handle parent;
268ccd979bdSMark Fasheh
269644f9ab3SChristoph Hellwig if (fh_type != 2 || fh_len < 6)
270644f9ab3SChristoph Hellwig return NULL;
271ccd979bdSMark Fasheh
272644f9ab3SChristoph Hellwig parent.ih_blkno = (u64)le32_to_cpu(fid->raw[3]) << 32;
273644f9ab3SChristoph Hellwig parent.ih_blkno |= (u64)le32_to_cpu(fid->raw[4]);
274644f9ab3SChristoph Hellwig parent.ih_generation = le32_to_cpu(fid->raw[5]);
275644f9ab3SChristoph Hellwig return ocfs2_get_dentry(sb, &parent);
276ccd979bdSMark Fasheh }
277ccd979bdSMark Fasheh
27839655164SChristoph Hellwig const struct export_operations ocfs2_export_ops = {
279ccd979bdSMark Fasheh .encode_fh = ocfs2_encode_fh,
280644f9ab3SChristoph Hellwig .fh_to_dentry = ocfs2_fh_to_dentry,
281644f9ab3SChristoph Hellwig .fh_to_parent = ocfs2_fh_to_parent,
282ccd979bdSMark Fasheh .get_parent = ocfs2_get_parent,
283ccd979bdSMark Fasheh };
284