J. Bruce Fields | 1557aca | 2009-12-04 19:36:06 -0500 | [diff] [blame] | 1 | /* Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de> */ |
| 2 | |
| 3 | #ifndef _LINUX_NFSD_FH_INT_H |
| 4 | #define _LINUX_NFSD_FH_INT_H |
| 5 | |
| 6 | #include <linux/nfsd/nfsfh.h> |
| 7 | |
| 8 | enum nfsd_fsid { |
| 9 | FSID_DEV = 0, |
| 10 | FSID_NUM, |
| 11 | FSID_MAJOR_MINOR, |
| 12 | FSID_ENCODE_DEV, |
| 13 | FSID_UUID4_INUM, |
| 14 | FSID_UUID8, |
| 15 | FSID_UUID16, |
| 16 | FSID_UUID16_INUM, |
| 17 | }; |
| 18 | |
| 19 | enum fsid_source { |
| 20 | FSIDSOURCE_DEV, |
| 21 | FSIDSOURCE_FSID, |
| 22 | FSIDSOURCE_UUID, |
| 23 | }; |
| 24 | extern enum fsid_source fsid_source(struct svc_fh *fhp); |
| 25 | |
| 26 | |
| 27 | /* This might look a little large to "inline" but in all calls except |
| 28 | * one, 'vers' is constant so moste of the function disappears. |
| 29 | */ |
| 30 | static inline void mk_fsid(int vers, u32 *fsidv, dev_t dev, ino_t ino, |
| 31 | u32 fsid, unsigned char *uuid) |
| 32 | { |
| 33 | u32 *up; |
| 34 | switch(vers) { |
| 35 | case FSID_DEV: |
| 36 | fsidv[0] = htonl((MAJOR(dev)<<16) | |
| 37 | MINOR(dev)); |
| 38 | fsidv[1] = ino_t_to_u32(ino); |
| 39 | break; |
| 40 | case FSID_NUM: |
| 41 | fsidv[0] = fsid; |
| 42 | break; |
| 43 | case FSID_MAJOR_MINOR: |
| 44 | fsidv[0] = htonl(MAJOR(dev)); |
| 45 | fsidv[1] = htonl(MINOR(dev)); |
| 46 | fsidv[2] = ino_t_to_u32(ino); |
| 47 | break; |
| 48 | |
| 49 | case FSID_ENCODE_DEV: |
| 50 | fsidv[0] = new_encode_dev(dev); |
| 51 | fsidv[1] = ino_t_to_u32(ino); |
| 52 | break; |
| 53 | |
| 54 | case FSID_UUID4_INUM: |
| 55 | /* 4 byte fsid and inode number */ |
| 56 | up = (u32*)uuid; |
| 57 | fsidv[0] = ino_t_to_u32(ino); |
| 58 | fsidv[1] = up[0] ^ up[1] ^ up[2] ^ up[3]; |
| 59 | break; |
| 60 | |
| 61 | case FSID_UUID8: |
| 62 | /* 8 byte fsid */ |
| 63 | up = (u32*)uuid; |
| 64 | fsidv[0] = up[0] ^ up[2]; |
| 65 | fsidv[1] = up[1] ^ up[3]; |
| 66 | break; |
| 67 | |
| 68 | case FSID_UUID16: |
| 69 | /* 16 byte fsid - NFSv3+ only */ |
| 70 | memcpy(fsidv, uuid, 16); |
| 71 | break; |
| 72 | |
| 73 | case FSID_UUID16_INUM: |
| 74 | /* 8 byte inode and 16 byte fsid */ |
| 75 | *(u64*)fsidv = (u64)ino; |
| 76 | memcpy(fsidv+2, uuid, 16); |
| 77 | break; |
| 78 | default: BUG(); |
| 79 | } |
| 80 | } |
| 81 | |
| 82 | static inline int key_len(int type) |
| 83 | { |
| 84 | switch(type) { |
| 85 | case FSID_DEV: return 8; |
| 86 | case FSID_NUM: return 4; |
| 87 | case FSID_MAJOR_MINOR: return 12; |
| 88 | case FSID_ENCODE_DEV: return 8; |
| 89 | case FSID_UUID4_INUM: return 8; |
| 90 | case FSID_UUID8: return 8; |
| 91 | case FSID_UUID16: return 16; |
| 92 | case FSID_UUID16_INUM: return 24; |
| 93 | default: return 0; |
| 94 | } |
| 95 | } |
| 96 | |
| 97 | /* |
| 98 | * Shorthand for dprintk()'s |
| 99 | */ |
| 100 | extern char * SVCFH_fmt(struct svc_fh *fhp); |
| 101 | |
| 102 | /* |
| 103 | * Function prototypes |
| 104 | */ |
| 105 | __be32 fh_verify(struct svc_rqst *, struct svc_fh *, int, int); |
| 106 | __be32 fh_compose(struct svc_fh *, struct svc_export *, struct dentry *, struct svc_fh *); |
| 107 | __be32 fh_update(struct svc_fh *); |
| 108 | void fh_put(struct svc_fh *); |
| 109 | |
| 110 | static __inline__ struct svc_fh * |
| 111 | fh_copy(struct svc_fh *dst, struct svc_fh *src) |
| 112 | { |
| 113 | WARN_ON(src->fh_dentry || src->fh_locked); |
| 114 | |
| 115 | *dst = *src; |
| 116 | return dst; |
| 117 | } |
| 118 | |
| 119 | static inline void |
| 120 | fh_copy_shallow(struct knfsd_fh *dst, struct knfsd_fh *src) |
| 121 | { |
| 122 | dst->fh_size = src->fh_size; |
| 123 | memcpy(&dst->fh_base, &src->fh_base, src->fh_size); |
| 124 | } |
| 125 | |
| 126 | static __inline__ struct svc_fh * |
| 127 | fh_init(struct svc_fh *fhp, int maxsize) |
| 128 | { |
| 129 | memset(fhp, 0, sizeof(*fhp)); |
| 130 | fhp->fh_maxsize = maxsize; |
| 131 | return fhp; |
| 132 | } |
| 133 | |
| 134 | #ifdef CONFIG_NFSD_V3 |
| 135 | /* |
| 136 | * Fill in the pre_op attr for the wcc data |
| 137 | */ |
| 138 | static inline void |
| 139 | fill_pre_wcc(struct svc_fh *fhp) |
| 140 | { |
| 141 | struct inode *inode; |
| 142 | |
| 143 | inode = fhp->fh_dentry->d_inode; |
| 144 | if (!fhp->fh_pre_saved) { |
| 145 | fhp->fh_pre_mtime = inode->i_mtime; |
| 146 | fhp->fh_pre_ctime = inode->i_ctime; |
| 147 | fhp->fh_pre_size = inode->i_size; |
| 148 | fhp->fh_pre_change = inode->i_version; |
| 149 | fhp->fh_pre_saved = 1; |
| 150 | } |
| 151 | } |
| 152 | |
| 153 | extern void fill_post_wcc(struct svc_fh *); |
| 154 | #else |
| 155 | #define fill_pre_wcc(ignored) |
| 156 | #define fill_post_wcc(notused) |
| 157 | #endif /* CONFIG_NFSD_V3 */ |
| 158 | |
| 159 | |
| 160 | /* |
| 161 | * Lock a file handle/inode |
| 162 | * NOTE: both fh_lock and fh_unlock are done "by hand" in |
| 163 | * vfs.c:nfsd_rename as it needs to grab 2 i_mutex's at once |
| 164 | * so, any changes here should be reflected there. |
| 165 | */ |
| 166 | |
| 167 | static inline void |
| 168 | fh_lock_nested(struct svc_fh *fhp, unsigned int subclass) |
| 169 | { |
| 170 | struct dentry *dentry = fhp->fh_dentry; |
| 171 | struct inode *inode; |
| 172 | |
| 173 | BUG_ON(!dentry); |
| 174 | |
| 175 | if (fhp->fh_locked) { |
| 176 | printk(KERN_WARNING "fh_lock: %s/%s already locked!\n", |
| 177 | dentry->d_parent->d_name.name, dentry->d_name.name); |
| 178 | return; |
| 179 | } |
| 180 | |
| 181 | inode = dentry->d_inode; |
| 182 | mutex_lock_nested(&inode->i_mutex, subclass); |
| 183 | fill_pre_wcc(fhp); |
| 184 | fhp->fh_locked = 1; |
| 185 | } |
| 186 | |
| 187 | static inline void |
| 188 | fh_lock(struct svc_fh *fhp) |
| 189 | { |
| 190 | fh_lock_nested(fhp, I_MUTEX_NORMAL); |
| 191 | } |
| 192 | |
| 193 | /* |
| 194 | * Unlock a file handle/inode |
| 195 | */ |
| 196 | static inline void |
| 197 | fh_unlock(struct svc_fh *fhp) |
| 198 | { |
J. Bruce Fields | 1557aca | 2009-12-04 19:36:06 -0500 | [diff] [blame] | 199 | if (fhp->fh_locked) { |
| 200 | fill_post_wcc(fhp); |
| 201 | mutex_unlock(&fhp->fh_dentry->d_inode->i_mutex); |
| 202 | fhp->fh_locked = 0; |
| 203 | } |
| 204 | } |
| 205 | |
| 206 | #endif /* _LINUX_NFSD_FH_INT_H */ |