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