1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * export.c |
4 | * |
5 | * Functions to facilitate NFS exporting |
6 | * |
7 | * Copyright (C) 2002, 2005 Oracle. All rights reserved. |
8 | */ |
9 | |
10 | #include <linux/fs.h> |
11 | #include <linux/types.h> |
12 | |
13 | #include <cluster/masklog.h> |
14 | |
15 | #include "ocfs2.h" |
16 | |
17 | #include "alloc.h" |
18 | #include "dir.h" |
19 | #include "dlmglue.h" |
20 | #include "dcache.h" |
21 | #include "export.h" |
22 | #include "inode.h" |
23 | |
24 | #include "buffer_head_io.h" |
25 | #include "suballoc.h" |
26 | #include "ocfs2_trace.h" |
27 | |
28 | struct ocfs2_inode_handle |
29 | { |
30 | u64 ih_blkno; |
31 | u32 ih_generation; |
32 | }; |
33 | |
34 | static struct dentry *ocfs2_get_dentry(struct super_block *sb, |
35 | struct ocfs2_inode_handle *handle) |
36 | { |
37 | struct inode *inode; |
38 | struct ocfs2_super *osb = OCFS2_SB(sb); |
39 | u64 blkno = handle->ih_blkno; |
40 | int status, set; |
41 | struct dentry *result; |
42 | |
43 | trace_ocfs2_get_dentry_begin(sb, handle, blkno: (unsigned long long)blkno); |
44 | |
45 | if (blkno == 0) { |
46 | result = ERR_PTR(error: -ESTALE); |
47 | goto bail; |
48 | } |
49 | |
50 | inode = ocfs2_ilookup(sb, feoff: blkno); |
51 | /* |
52 | * If the inode exists in memory, we only need to check it's |
53 | * generation number |
54 | */ |
55 | if (inode) |
56 | goto check_gen; |
57 | |
58 | /* |
59 | * This will synchronize us against ocfs2_delete_inode() on |
60 | * all nodes |
61 | */ |
62 | status = ocfs2_nfs_sync_lock(osb, ex: 1); |
63 | if (status < 0) { |
64 | mlog(ML_ERROR, "getting nfs sync lock(EX) failed %d\n" , status); |
65 | goto check_err; |
66 | } |
67 | |
68 | status = ocfs2_test_inode_bit(osb, blkno, res: &set); |
69 | if (status < 0) { |
70 | if (status == -EINVAL) { |
71 | /* |
72 | * The blkno NFS gave us doesn't even show up |
73 | * as an inode, we return -ESTALE to be |
74 | * nice |
75 | */ |
76 | status = -ESTALE; |
77 | } else |
78 | mlog(ML_ERROR, "test inode bit failed %d\n" , status); |
79 | goto unlock_nfs_sync; |
80 | } |
81 | |
82 | trace_ocfs2_get_dentry_test_bit(val1: status, val2: set); |
83 | /* If the inode allocator bit is clear, this inode must be stale */ |
84 | if (!set) { |
85 | status = -ESTALE; |
86 | goto unlock_nfs_sync; |
87 | } |
88 | |
89 | inode = ocfs2_iget(osb, feoff: blkno, flags: 0, sysfile_type: 0); |
90 | |
91 | unlock_nfs_sync: |
92 | ocfs2_nfs_sync_unlock(osb, ex: 1); |
93 | |
94 | check_err: |
95 | if (status < 0) { |
96 | if (status == -ESTALE) { |
97 | trace_ocfs2_get_dentry_stale(val1: (unsigned long long)blkno, |
98 | val2: handle->ih_generation); |
99 | } |
100 | result = ERR_PTR(error: status); |
101 | goto bail; |
102 | } |
103 | |
104 | if (IS_ERR(ptr: inode)) { |
105 | mlog_errno(PTR_ERR(inode)); |
106 | result = ERR_CAST(ptr: inode); |
107 | goto bail; |
108 | } |
109 | |
110 | check_gen: |
111 | if (handle->ih_generation != inode->i_generation) { |
112 | trace_ocfs2_get_dentry_generation(val1: (unsigned long long)blkno, |
113 | val2: handle->ih_generation, |
114 | val3: inode->i_generation); |
115 | iput(inode); |
116 | result = ERR_PTR(error: -ESTALE); |
117 | goto bail; |
118 | } |
119 | |
120 | result = d_obtain_alias(inode); |
121 | if (IS_ERR(ptr: result)) |
122 | mlog_errno(PTR_ERR(result)); |
123 | |
124 | bail: |
125 | trace_ocfs2_get_dentry_end(pointer: result); |
126 | return result; |
127 | } |
128 | |
129 | static struct dentry *ocfs2_get_parent(struct dentry *child) |
130 | { |
131 | int status; |
132 | u64 blkno; |
133 | struct dentry *parent; |
134 | struct inode *dir = d_inode(dentry: child); |
135 | int set; |
136 | |
137 | trace_ocfs2_get_parent(child, len: child->d_name.len, name: child->d_name.name, |
138 | ino: (unsigned long long)OCFS2_I(inode: dir)->ip_blkno); |
139 | |
140 | status = ocfs2_nfs_sync_lock(OCFS2_SB(dir->i_sb), ex: 1); |
141 | if (status < 0) { |
142 | mlog(ML_ERROR, "getting nfs sync lock(EX) failed %d\n" , status); |
143 | parent = ERR_PTR(error: status); |
144 | goto bail; |
145 | } |
146 | |
147 | status = ocfs2_inode_lock(dir, NULL, 0); |
148 | if (status < 0) { |
149 | if (status != -ENOENT) |
150 | mlog_errno(status); |
151 | parent = ERR_PTR(error: status); |
152 | goto unlock_nfs_sync; |
153 | } |
154 | |
155 | status = ocfs2_lookup_ino_from_name(dir, name: ".." , namelen: 2, blkno: &blkno); |
156 | if (status < 0) { |
157 | parent = ERR_PTR(error: -ENOENT); |
158 | goto bail_unlock; |
159 | } |
160 | |
161 | status = ocfs2_test_inode_bit(OCFS2_SB(dir->i_sb), blkno, res: &set); |
162 | if (status < 0) { |
163 | if (status == -EINVAL) { |
164 | status = -ESTALE; |
165 | } else |
166 | mlog(ML_ERROR, "test inode bit failed %d\n" , status); |
167 | parent = ERR_PTR(error: status); |
168 | goto bail_unlock; |
169 | } |
170 | |
171 | trace_ocfs2_get_dentry_test_bit(val1: status, val2: set); |
172 | if (!set) { |
173 | status = -ESTALE; |
174 | parent = ERR_PTR(error: status); |
175 | goto bail_unlock; |
176 | } |
177 | |
178 | parent = d_obtain_alias(ocfs2_iget(OCFS2_SB(dir->i_sb), feoff: blkno, flags: 0, sysfile_type: 0)); |
179 | |
180 | bail_unlock: |
181 | ocfs2_inode_unlock(inode: dir, ex: 0); |
182 | |
183 | unlock_nfs_sync: |
184 | ocfs2_nfs_sync_unlock(OCFS2_SB(dir->i_sb), ex: 1); |
185 | |
186 | bail: |
187 | trace_ocfs2_get_parent_end(pointer: parent); |
188 | |
189 | return parent; |
190 | } |
191 | |
192 | static int ocfs2_encode_fh(struct inode *inode, u32 *fh_in, int *max_len, |
193 | struct inode *parent) |
194 | { |
195 | int len = *max_len; |
196 | int type = 1; |
197 | u64 blkno; |
198 | u32 generation; |
199 | __le32 *fh = (__force __le32 *) fh_in; |
200 | |
201 | #ifdef TRACE_HOOKS_ARE_NOT_BRAINDEAD_IN_YOUR_OPINION |
202 | #error "You go ahead and fix that mess, then. Somehow" |
203 | trace_ocfs2_encode_fh_begin(dentry, dentry->d_name.len, |
204 | dentry->d_name.name, |
205 | fh, len, connectable); |
206 | #endif |
207 | |
208 | if (parent && (len < 6)) { |
209 | *max_len = 6; |
210 | type = FILEID_INVALID; |
211 | goto bail; |
212 | } else if (len < 3) { |
213 | *max_len = 3; |
214 | type = FILEID_INVALID; |
215 | goto bail; |
216 | } |
217 | |
218 | blkno = OCFS2_I(inode)->ip_blkno; |
219 | generation = inode->i_generation; |
220 | |
221 | trace_ocfs2_encode_fh_self(val1: (unsigned long long)blkno, val2: generation); |
222 | |
223 | len = 3; |
224 | fh[0] = cpu_to_le32((u32)(blkno >> 32)); |
225 | fh[1] = cpu_to_le32((u32)(blkno & 0xffffffff)); |
226 | fh[2] = cpu_to_le32(generation); |
227 | |
228 | if (parent) { |
229 | blkno = OCFS2_I(inode: parent)->ip_blkno; |
230 | generation = parent->i_generation; |
231 | |
232 | fh[3] = cpu_to_le32((u32)(blkno >> 32)); |
233 | fh[4] = cpu_to_le32((u32)(blkno & 0xffffffff)); |
234 | fh[5] = cpu_to_le32(generation); |
235 | |
236 | len = 6; |
237 | type = 2; |
238 | |
239 | trace_ocfs2_encode_fh_parent(val1: (unsigned long long)blkno, |
240 | val2: generation); |
241 | } |
242 | |
243 | *max_len = len; |
244 | |
245 | bail: |
246 | trace_ocfs2_encode_fh_type(num: type); |
247 | return type; |
248 | } |
249 | |
250 | static struct dentry *ocfs2_fh_to_dentry(struct super_block *sb, |
251 | struct fid *fid, int fh_len, int fh_type) |
252 | { |
253 | struct ocfs2_inode_handle handle; |
254 | |
255 | if (fh_len < 3 || fh_type > 2) |
256 | return NULL; |
257 | |
258 | handle.ih_blkno = (u64)le32_to_cpu(fid->raw[0]) << 32; |
259 | handle.ih_blkno |= (u64)le32_to_cpu(fid->raw[1]); |
260 | handle.ih_generation = le32_to_cpu(fid->raw[2]); |
261 | return ocfs2_get_dentry(sb, handle: &handle); |
262 | } |
263 | |
264 | static struct dentry *ocfs2_fh_to_parent(struct super_block *sb, |
265 | struct fid *fid, int fh_len, int fh_type) |
266 | { |
267 | struct ocfs2_inode_handle parent; |
268 | |
269 | if (fh_type != 2 || fh_len < 6) |
270 | return NULL; |
271 | |
272 | parent.ih_blkno = (u64)le32_to_cpu(fid->raw[3]) << 32; |
273 | parent.ih_blkno |= (u64)le32_to_cpu(fid->raw[4]); |
274 | parent.ih_generation = le32_to_cpu(fid->raw[5]); |
275 | return ocfs2_get_dentry(sb, handle: &parent); |
276 | } |
277 | |
278 | const struct export_operations ocfs2_export_ops = { |
279 | .encode_fh = ocfs2_encode_fh, |
280 | .fh_to_dentry = ocfs2_fh_to_dentry, |
281 | .fh_to_parent = ocfs2_fh_to_parent, |
282 | .get_parent = ocfs2_get_parent, |
283 | }; |
284 | |