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