1
2
3
4
5
6
7
8#ifndef _LINUX_NFSD_NFSFH_H
9#define _LINUX_NFSD_NFSFH_H
10
11#include <linux/crc32.h>
12#include <linux/sunrpc/svc.h>
13#include <uapi/linux/nfsd/nfsfh.h>
14#include <linux/iversion.h>
15#include <linux/exportfs.h>
16
17static inline __u32 ino_t_to_u32(ino_t ino)
18{
19 return (__u32) ino;
20}
21
22static inline ino_t u32_to_ino_t(__u32 uino)
23{
24 return (ino_t) uino;
25}
26
27
28
29
30
31typedef struct svc_fh {
32 struct knfsd_fh fh_handle;
33 int fh_maxsize;
34 struct dentry * fh_dentry;
35 struct svc_export * fh_export;
36
37 bool fh_locked;
38 bool fh_want_write;
39 bool fh_no_wcc;
40 bool fh_no_atomic_attr;
41
42
43
44
45 int fh_flags;
46#ifdef CONFIG_NFSD_V3
47 bool fh_post_saved;
48 bool fh_pre_saved;
49
50
51 __u64 fh_pre_size;
52 struct timespec64 fh_pre_mtime;
53 struct timespec64 fh_pre_ctime;
54
55
56
57
58 u64 fh_pre_change;
59
60
61 struct kstat fh_post_attr;
62 u64 fh_post_change;
63#endif
64} svc_fh;
65#define NFSD4_FH_FOREIGN (1<<0)
66#define SET_FH_FLAG(c, f) ((c)->fh_flags |= (f))
67#define HAS_FH_FLAG(c, f) ((c)->fh_flags & (f))
68
69enum nfsd_fsid {
70 FSID_DEV = 0,
71 FSID_NUM,
72 FSID_MAJOR_MINOR,
73 FSID_ENCODE_DEV,
74 FSID_UUID4_INUM,
75 FSID_UUID8,
76 FSID_UUID16,
77 FSID_UUID16_INUM,
78};
79
80enum fsid_source {
81 FSIDSOURCE_DEV,
82 FSIDSOURCE_FSID,
83 FSIDSOURCE_UUID,
84};
85extern enum fsid_source fsid_source(const struct svc_fh *fhp);
86
87
88
89
90
91
92
93
94
95
96
97
98static inline void mk_fsid(int vers, u32 *fsidv, dev_t dev, ino_t ino,
99 u32 fsid, unsigned char *uuid)
100{
101 u32 *up;
102 switch(vers) {
103 case FSID_DEV:
104 fsidv[0] = (__force __u32)htonl((MAJOR(dev)<<16) |
105 MINOR(dev));
106 fsidv[1] = ino_t_to_u32(ino);
107 break;
108 case FSID_NUM:
109 fsidv[0] = fsid;
110 break;
111 case FSID_MAJOR_MINOR:
112 fsidv[0] = (__force __u32)htonl(MAJOR(dev));
113 fsidv[1] = (__force __u32)htonl(MINOR(dev));
114 fsidv[2] = ino_t_to_u32(ino);
115 break;
116
117 case FSID_ENCODE_DEV:
118 fsidv[0] = new_encode_dev(dev);
119 fsidv[1] = ino_t_to_u32(ino);
120 break;
121
122 case FSID_UUID4_INUM:
123
124 up = (u32*)uuid;
125 fsidv[0] = ino_t_to_u32(ino);
126 fsidv[1] = up[0] ^ up[1] ^ up[2] ^ up[3];
127 break;
128
129 case FSID_UUID8:
130
131 up = (u32*)uuid;
132 fsidv[0] = up[0] ^ up[2];
133 fsidv[1] = up[1] ^ up[3];
134 break;
135
136 case FSID_UUID16:
137
138 memcpy(fsidv, uuid, 16);
139 break;
140
141 case FSID_UUID16_INUM:
142
143 *(u64*)fsidv = (u64)ino;
144 memcpy(fsidv+2, uuid, 16);
145 break;
146 default: BUG();
147 }
148}
149
150static inline int key_len(int type)
151{
152 switch(type) {
153 case FSID_DEV: return 8;
154 case FSID_NUM: return 4;
155 case FSID_MAJOR_MINOR: return 12;
156 case FSID_ENCODE_DEV: return 8;
157 case FSID_UUID4_INUM: return 8;
158 case FSID_UUID8: return 8;
159 case FSID_UUID16: return 16;
160 case FSID_UUID16_INUM: return 24;
161 default: return 0;
162 }
163}
164
165
166
167
168extern char * SVCFH_fmt(struct svc_fh *fhp);
169
170
171
172
173__be32 fh_verify(struct svc_rqst *, struct svc_fh *, umode_t, int);
174__be32 fh_compose(struct svc_fh *, struct svc_export *, struct dentry *, struct svc_fh *);
175__be32 fh_update(struct svc_fh *);
176void fh_put(struct svc_fh *);
177
178static __inline__ struct svc_fh *
179fh_copy(struct svc_fh *dst, struct svc_fh *src)
180{
181 WARN_ON(src->fh_dentry || src->fh_locked);
182
183 *dst = *src;
184 return dst;
185}
186
187static inline void
188fh_copy_shallow(struct knfsd_fh *dst, struct knfsd_fh *src)
189{
190 dst->fh_size = src->fh_size;
191 memcpy(&dst->fh_base, &src->fh_base, src->fh_size);
192}
193
194static __inline__ struct svc_fh *
195fh_init(struct svc_fh *fhp, int maxsize)
196{
197 memset(fhp, 0, sizeof(*fhp));
198 fhp->fh_maxsize = maxsize;
199 return fhp;
200}
201
202static inline bool fh_match(struct knfsd_fh *fh1, struct knfsd_fh *fh2)
203{
204 if (fh1->fh_size != fh2->fh_size)
205 return false;
206 if (memcmp(fh1->fh_base.fh_pad, fh2->fh_base.fh_pad, fh1->fh_size) != 0)
207 return false;
208 return true;
209}
210
211static inline bool fh_fsid_match(struct knfsd_fh *fh1, struct knfsd_fh *fh2)
212{
213 if (fh1->fh_fsid_type != fh2->fh_fsid_type)
214 return false;
215 if (memcmp(fh1->fh_fsid, fh2->fh_fsid, key_len(fh1->fh_fsid_type)) != 0)
216 return false;
217 return true;
218}
219
220#ifdef CONFIG_CRC32
221
222
223
224
225
226
227
228static inline u32 knfsd_fh_hash(const struct knfsd_fh *fh)
229{
230 return ~crc32_le(0xFFFFFFFF, (unsigned char *)&fh->fh_base, fh->fh_size);
231}
232#else
233static inline u32 knfsd_fh_hash(const struct knfsd_fh *fh)
234{
235 return 0;
236}
237#endif
238
239#ifdef CONFIG_NFSD_V3
240
241
242
243
244static inline void
245fh_clear_wcc(struct svc_fh *fhp)
246{
247 fhp->fh_post_saved = false;
248 fhp->fh_pre_saved = false;
249}
250
251
252
253
254
255
256
257
258
259
260
261
262static inline u64 nfsd4_change_attribute(struct kstat *stat,
263 struct inode *inode)
264{
265 if (inode->i_sb->s_export_op->fetch_iversion)
266 return inode->i_sb->s_export_op->fetch_iversion(inode);
267 else if (IS_I_VERSION(inode)) {
268 u64 chattr;
269
270 chattr = stat->ctime.tv_sec;
271 chattr <<= 30;
272 chattr += stat->ctime.tv_nsec;
273 chattr += inode_query_iversion(inode);
274 return chattr;
275 } else
276 return time_to_chattr(&stat->ctime);
277}
278
279extern void fill_pre_wcc(struct svc_fh *fhp);
280extern void fill_post_wcc(struct svc_fh *fhp);
281#else
282#define fh_clear_wcc(ignored)
283#define fill_pre_wcc(ignored)
284#define fill_post_wcc(notused)
285#endif
286
287
288
289
290
291
292
293
294
295static inline void
296fh_lock_nested(struct svc_fh *fhp, unsigned int subclass)
297{
298 struct dentry *dentry = fhp->fh_dentry;
299 struct inode *inode;
300
301 BUG_ON(!dentry);
302
303 if (fhp->fh_locked) {
304 printk(KERN_WARNING "fh_lock: %pd2 already locked!\n",
305 dentry);
306 return;
307 }
308
309 inode = d_inode(dentry);
310 inode_lock_nested(inode, subclass);
311 fill_pre_wcc(fhp);
312 fhp->fh_locked = true;
313}
314
315static inline void
316fh_lock(struct svc_fh *fhp)
317{
318 fh_lock_nested(fhp, I_MUTEX_NORMAL);
319}
320
321
322
323
324static inline void
325fh_unlock(struct svc_fh *fhp)
326{
327 if (fhp->fh_locked) {
328 fill_post_wcc(fhp);
329 inode_unlock(d_inode(fhp->fh_dentry));
330 fhp->fh_locked = false;
331 }
332}
333
334#endif
335