1 /* SPDX-License-Identifier: GPL-2.0 */ 2 /* 3 * Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de> 4 * 5 * This file describes the layout of the file handles as passed 6 * over the wire. 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 16 static inline __u32 ino_t_to_u32(ino_t ino) 17 { 18 return (__u32) ino; 19 } 20 21 static inline ino_t u32_to_ino_t(__u32 uino) 22 { 23 return (ino_t) uino; 24 } 25 26 /* 27 * This is the internal representation of an NFS handle used in knfsd. 28 * pre_mtime/post_version will be used to support wcc_attr's in NFSv3. 29 */ 30 typedef struct svc_fh { 31 struct knfsd_fh fh_handle; /* FH data */ 32 int fh_maxsize; /* max size for fh_handle */ 33 struct dentry * fh_dentry; /* validated dentry */ 34 struct svc_export * fh_export; /* export pointer */ 35 36 bool fh_locked; /* inode locked by us */ 37 bool fh_want_write; /* remount protection taken */ 38 bool fh_no_wcc; /* no wcc data needed */ 39 bool fh_no_atomic_attr; 40 /* 41 * wcc data is not atomic with 42 * operation 43 */ 44 int fh_flags; /* FH flags */ 45 #ifdef CONFIG_NFSD_V3 46 bool fh_post_saved; /* post-op attrs saved */ 47 bool fh_pre_saved; /* pre-op attrs saved */ 48 49 /* Pre-op attributes saved during fh_lock */ 50 __u64 fh_pre_size; /* size before operation */ 51 struct timespec64 fh_pre_mtime; /* mtime before oper */ 52 struct timespec64 fh_pre_ctime; /* ctime before oper */ 53 /* 54 * pre-op nfsv4 change attr: note must check IS_I_VERSION(inode) 55 * to find out if it is valid. 56 */ 57 u64 fh_pre_change; 58 59 /* Post-op attributes saved in fh_unlock */ 60 struct kstat fh_post_attr; /* full attrs after operation */ 61 u64 fh_post_change; /* nfsv4 change; see above */ 62 #endif /* CONFIG_NFSD_V3 */ 63 } svc_fh; 64 #define NFSD4_FH_FOREIGN (1<<0) 65 #define SET_FH_FLAG(c, f) ((c)->fh_flags |= (f)) 66 #define HAS_FH_FLAG(c, f) ((c)->fh_flags & (f)) 67 68 enum nfsd_fsid { 69 FSID_DEV = 0, 70 FSID_NUM, 71 FSID_MAJOR_MINOR, 72 FSID_ENCODE_DEV, 73 FSID_UUID4_INUM, 74 FSID_UUID8, 75 FSID_UUID16, 76 FSID_UUID16_INUM, 77 }; 78 79 enum fsid_source { 80 FSIDSOURCE_DEV, 81 FSIDSOURCE_FSID, 82 FSIDSOURCE_UUID, 83 }; 84 extern enum fsid_source fsid_source(struct svc_fh *fhp); 85 86 87 /* 88 * This might look a little large to "inline" but in all calls except 89 * one, 'vers' is constant so moste of the function disappears. 90 * 91 * In some cases the values are considered to be host endian and in 92 * others, net endian. fsidv is always considered to be u32 as the 93 * callers don't know which it will be. So we must use __force to keep 94 * sparse from complaining. Since these values are opaque to the 95 * client, that shouldn't be a problem. 96 */ 97 static inline void mk_fsid(int vers, u32 *fsidv, dev_t dev, ino_t ino, 98 u32 fsid, unsigned char *uuid) 99 { 100 u32 *up; 101 switch(vers) { 102 case FSID_DEV: 103 fsidv[0] = (__force __u32)htonl((MAJOR(dev)<<16) | 104 MINOR(dev)); 105 fsidv[1] = ino_t_to_u32(ino); 106 break; 107 case FSID_NUM: 108 fsidv[0] = fsid; 109 break; 110 case FSID_MAJOR_MINOR: 111 fsidv[0] = (__force __u32)htonl(MAJOR(dev)); 112 fsidv[1] = (__force __u32)htonl(MINOR(dev)); 113 fsidv[2] = ino_t_to_u32(ino); 114 break; 115 116 case FSID_ENCODE_DEV: 117 fsidv[0] = new_encode_dev(dev); 118 fsidv[1] = ino_t_to_u32(ino); 119 break; 120 121 case FSID_UUID4_INUM: 122 /* 4 byte fsid and inode number */ 123 up = (u32*)uuid; 124 fsidv[0] = ino_t_to_u32(ino); 125 fsidv[1] = up[0] ^ up[1] ^ up[2] ^ up[3]; 126 break; 127 128 case FSID_UUID8: 129 /* 8 byte fsid */ 130 up = (u32*)uuid; 131 fsidv[0] = up[0] ^ up[2]; 132 fsidv[1] = up[1] ^ up[3]; 133 break; 134 135 case FSID_UUID16: 136 /* 16 byte fsid - NFSv3+ only */ 137 memcpy(fsidv, uuid, 16); 138 break; 139 140 case FSID_UUID16_INUM: 141 /* 8 byte inode and 16 byte fsid */ 142 *(u64*)fsidv = (u64)ino; 143 memcpy(fsidv+2, uuid, 16); 144 break; 145 default: BUG(); 146 } 147 } 148 149 static inline int key_len(int type) 150 { 151 switch(type) { 152 case FSID_DEV: return 8; 153 case FSID_NUM: return 4; 154 case FSID_MAJOR_MINOR: return 12; 155 case FSID_ENCODE_DEV: return 8; 156 case FSID_UUID4_INUM: return 8; 157 case FSID_UUID8: return 8; 158 case FSID_UUID16: return 16; 159 case FSID_UUID16_INUM: return 24; 160 default: return 0; 161 } 162 } 163 164 /* 165 * Shorthand for dprintk()'s 166 */ 167 extern char * SVCFH_fmt(struct svc_fh *fhp); 168 169 /* 170 * Function prototypes 171 */ 172 __be32 fh_verify(struct svc_rqst *, struct svc_fh *, umode_t, int); 173 __be32 fh_compose(struct svc_fh *, struct svc_export *, struct dentry *, struct svc_fh *); 174 __be32 fh_update(struct svc_fh *); 175 void fh_put(struct svc_fh *); 176 177 static __inline__ struct svc_fh * 178 fh_copy(struct svc_fh *dst, struct svc_fh *src) 179 { 180 WARN_ON(src->fh_dentry || src->fh_locked); 181 182 *dst = *src; 183 return dst; 184 } 185 186 static inline void 187 fh_copy_shallow(struct knfsd_fh *dst, struct knfsd_fh *src) 188 { 189 dst->fh_size = src->fh_size; 190 memcpy(&dst->fh_base, &src->fh_base, src->fh_size); 191 } 192 193 static __inline__ struct svc_fh * 194 fh_init(struct svc_fh *fhp, int maxsize) 195 { 196 memset(fhp, 0, sizeof(*fhp)); 197 fhp->fh_maxsize = maxsize; 198 return fhp; 199 } 200 201 static inline bool fh_match(struct knfsd_fh *fh1, struct knfsd_fh *fh2) 202 { 203 if (fh1->fh_size != fh2->fh_size) 204 return false; 205 if (memcmp(fh1->fh_base.fh_pad, fh2->fh_base.fh_pad, fh1->fh_size) != 0) 206 return false; 207 return true; 208 } 209 210 static inline bool fh_fsid_match(struct knfsd_fh *fh1, struct knfsd_fh *fh2) 211 { 212 if (fh1->fh_fsid_type != fh2->fh_fsid_type) 213 return false; 214 if (memcmp(fh1->fh_fsid, fh2->fh_fsid, key_len(fh1->fh_fsid_type)) != 0) 215 return false; 216 return true; 217 } 218 219 #ifdef CONFIG_CRC32 220 /** 221 * knfsd_fh_hash - calculate the crc32 hash for the filehandle 222 * @fh - pointer to filehandle 223 * 224 * returns a crc32 hash for the filehandle that is compatible with 225 * the one displayed by "wireshark". 226 */ 227 228 static inline u32 229 knfsd_fh_hash(struct knfsd_fh *fh) 230 { 231 return ~crc32_le(0xFFFFFFFF, (unsigned char *)&fh->fh_base, fh->fh_size); 232 } 233 #else 234 static inline u32 235 knfsd_fh_hash(struct knfsd_fh *fh) 236 { 237 return 0; 238 } 239 #endif 240 241 #ifdef CONFIG_NFSD_V3 242 /* 243 * The wcc data stored in current_fh should be cleared 244 * between compound ops. 245 */ 246 static inline void 247 fh_clear_wcc(struct svc_fh *fhp) 248 { 249 fhp->fh_post_saved = false; 250 fhp->fh_pre_saved = false; 251 } 252 253 /* 254 * We could use i_version alone as the change attribute. However, 255 * i_version can go backwards after a reboot. On its own that doesn't 256 * necessarily cause a problem, but if i_version goes backwards and then 257 * is incremented again it could reuse a value that was previously used 258 * before boot, and a client who queried the two values might 259 * incorrectly assume nothing changed. 260 * 261 * By using both ctime and the i_version counter we guarantee that as 262 * long as time doesn't go backwards we never reuse an old value. 263 */ 264 static inline u64 nfsd4_change_attribute(struct kstat *stat, 265 struct inode *inode) 266 { 267 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 279 extern void fill_pre_wcc(struct svc_fh *fhp); 280 extern 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 /* CONFIG_NFSD_V3 */ 286 287 288 /* 289 * Lock a file handle/inode 290 * NOTE: both fh_lock and fh_unlock are done "by hand" in 291 * vfs.c:nfsd_rename as it needs to grab 2 i_mutex's at once 292 * so, any changes here should be reflected there. 293 */ 294 295 static inline void 296 fh_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 315 static inline void 316 fh_lock(struct svc_fh *fhp) 317 { 318 fh_lock_nested(fhp, I_MUTEX_NORMAL); 319 } 320 321 /* 322 * Unlock a file handle/inode 323 */ 324 static inline void 325 fh_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 /* _LINUX_NFSD_NFSFH_H */ 335