Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

nfsd: define xattr functions to call into their vfs counterparts

This adds the filehandle based functions for the xattr operations
that call in to the vfs layer to do the actual work.

Signed-off-by: Frank van der Linden <fllinden@amazon.com>
[ cel: address checkpatch.pl complaint ]
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>

authored by

Frank van der Linden and committed by
Chuck Lever
32119446 4dd05fce

+237
+227
fs/nfsd/vfs.c
··· 2065 2065 return nfsexp_flags(rqstp, exp) & NFSEXP_READONLY; 2066 2066 } 2067 2067 2068 + #ifdef CONFIG_NFSD_V4 2069 + /* 2070 + * Helper function to translate error numbers. In the case of xattr operations, 2071 + * some error codes need to be translated outside of the standard translations. 2072 + * 2073 + * ENODATA needs to be translated to nfserr_noxattr. 2074 + * E2BIG to nfserr_xattr2big. 2075 + * 2076 + * Additionally, vfs_listxattr can return -ERANGE. This means that the 2077 + * file has too many extended attributes to retrieve inside an 2078 + * XATTR_LIST_MAX sized buffer. This is a bug in the xattr implementation: 2079 + * filesystems will allow the adding of extended attributes until they hit 2080 + * their own internal limit. This limit may be larger than XATTR_LIST_MAX. 2081 + * So, at that point, the attributes are present and valid, but can't 2082 + * be retrieved using listxattr, since the upper level xattr code enforces 2083 + * the XATTR_LIST_MAX limit. 2084 + * 2085 + * This bug means that we need to deal with listxattr returning -ERANGE. The 2086 + * best mapping is to return TOOSMALL. 2087 + */ 2088 + static __be32 2089 + nfsd_xattr_errno(int err) 2090 + { 2091 + switch (err) { 2092 + case -ENODATA: 2093 + return nfserr_noxattr; 2094 + case -E2BIG: 2095 + return nfserr_xattr2big; 2096 + case -ERANGE: 2097 + return nfserr_toosmall; 2098 + } 2099 + return nfserrno(err); 2100 + } 2101 + 2102 + /* 2103 + * Retrieve the specified user extended attribute. To avoid always 2104 + * having to allocate the maximum size (since we are not getting 2105 + * a maximum size from the RPC), do a probe + alloc. Hold a reader 2106 + * lock on i_rwsem to prevent the extended attribute from changing 2107 + * size while we're doing this. 2108 + */ 2109 + __be32 2110 + nfsd_getxattr(struct svc_rqst *rqstp, struct svc_fh *fhp, char *name, 2111 + void **bufp, int *lenp) 2112 + { 2113 + ssize_t len; 2114 + __be32 err; 2115 + char *buf; 2116 + struct inode *inode; 2117 + struct dentry *dentry; 2118 + 2119 + err = fh_verify(rqstp, fhp, 0, NFSD_MAY_READ); 2120 + if (err) 2121 + return err; 2122 + 2123 + err = nfs_ok; 2124 + dentry = fhp->fh_dentry; 2125 + inode = d_inode(dentry); 2126 + 2127 + inode_lock_shared(inode); 2128 + 2129 + len = vfs_getxattr(dentry, name, NULL, 0); 2130 + 2131 + /* 2132 + * Zero-length attribute, just return. 2133 + */ 2134 + if (len == 0) { 2135 + *bufp = NULL; 2136 + *lenp = 0; 2137 + goto out; 2138 + } 2139 + 2140 + if (len < 0) { 2141 + err = nfsd_xattr_errno(len); 2142 + goto out; 2143 + } 2144 + 2145 + if (len > *lenp) { 2146 + err = nfserr_toosmall; 2147 + goto out; 2148 + } 2149 + 2150 + buf = kvmalloc(len, GFP_KERNEL | GFP_NOFS); 2151 + if (buf == NULL) { 2152 + err = nfserr_jukebox; 2153 + goto out; 2154 + } 2155 + 2156 + len = vfs_getxattr(dentry, name, buf, len); 2157 + if (len <= 0) { 2158 + kvfree(buf); 2159 + buf = NULL; 2160 + err = nfsd_xattr_errno(len); 2161 + } 2162 + 2163 + *lenp = len; 2164 + *bufp = buf; 2165 + 2166 + out: 2167 + inode_unlock_shared(inode); 2168 + 2169 + return err; 2170 + } 2171 + 2172 + /* 2173 + * Retrieve the xattr names. Since we can't know how many are 2174 + * user extended attributes, we must get all attributes here, 2175 + * and have the XDR encode filter out the "user." ones. 2176 + * 2177 + * While this could always just allocate an XATTR_LIST_MAX 2178 + * buffer, that's a waste, so do a probe + allocate. To 2179 + * avoid any changes between the probe and allocate, wrap 2180 + * this in inode_lock. 2181 + */ 2182 + __be32 2183 + nfsd_listxattr(struct svc_rqst *rqstp, struct svc_fh *fhp, char **bufp, 2184 + int *lenp) 2185 + { 2186 + ssize_t len; 2187 + __be32 err; 2188 + char *buf; 2189 + struct inode *inode; 2190 + struct dentry *dentry; 2191 + 2192 + err = fh_verify(rqstp, fhp, 0, NFSD_MAY_READ); 2193 + if (err) 2194 + return err; 2195 + 2196 + dentry = fhp->fh_dentry; 2197 + inode = d_inode(dentry); 2198 + *lenp = 0; 2199 + 2200 + inode_lock_shared(inode); 2201 + 2202 + len = vfs_listxattr(dentry, NULL, 0); 2203 + if (len <= 0) { 2204 + err = nfsd_xattr_errno(len); 2205 + goto out; 2206 + } 2207 + 2208 + if (len > XATTR_LIST_MAX) { 2209 + err = nfserr_xattr2big; 2210 + goto out; 2211 + } 2212 + 2213 + /* 2214 + * We're holding i_rwsem - use GFP_NOFS. 2215 + */ 2216 + buf = kvmalloc(len, GFP_KERNEL | GFP_NOFS); 2217 + if (buf == NULL) { 2218 + err = nfserr_jukebox; 2219 + goto out; 2220 + } 2221 + 2222 + len = vfs_listxattr(dentry, buf, len); 2223 + if (len <= 0) { 2224 + kvfree(buf); 2225 + err = nfsd_xattr_errno(len); 2226 + goto out; 2227 + } 2228 + 2229 + *lenp = len; 2230 + *bufp = buf; 2231 + 2232 + err = nfs_ok; 2233 + out: 2234 + inode_unlock_shared(inode); 2235 + 2236 + return err; 2237 + } 2238 + 2239 + /* 2240 + * Removexattr and setxattr need to call fh_lock to both lock the inode 2241 + * and set the change attribute. Since the top-level vfs_removexattr 2242 + * and vfs_setxattr calls already do their own inode_lock calls, call 2243 + * the _locked variant. Pass in a NULL pointer for delegated_inode, 2244 + * and let the client deal with NFS4ERR_DELAY (same as with e.g. 2245 + * setattr and remove). 2246 + */ 2247 + __be32 2248 + nfsd_removexattr(struct svc_rqst *rqstp, struct svc_fh *fhp, char *name) 2249 + { 2250 + int err, ret; 2251 + 2252 + err = fh_verify(rqstp, fhp, 0, NFSD_MAY_WRITE); 2253 + if (err) 2254 + return err; 2255 + 2256 + ret = fh_want_write(fhp); 2257 + if (ret) 2258 + return nfserrno(ret); 2259 + 2260 + fh_lock(fhp); 2261 + 2262 + ret = __vfs_removexattr_locked(fhp->fh_dentry, name, NULL); 2263 + 2264 + fh_unlock(fhp); 2265 + fh_drop_write(fhp); 2266 + 2267 + return nfsd_xattr_errno(ret); 2268 + } 2269 + 2270 + __be32 2271 + nfsd_setxattr(struct svc_rqst *rqstp, struct svc_fh *fhp, char *name, 2272 + void *buf, u32 len, u32 flags) 2273 + { 2274 + int err, ret; 2275 + 2276 + err = fh_verify(rqstp, fhp, 0, NFSD_MAY_WRITE); 2277 + if (err) 2278 + return err; 2279 + 2280 + ret = fh_want_write(fhp); 2281 + if (ret) 2282 + return nfserrno(ret); 2283 + fh_lock(fhp); 2284 + 2285 + ret = __vfs_setxattr_locked(fhp->fh_dentry, name, buf, len, flags, 2286 + NULL); 2287 + 2288 + fh_unlock(fhp); 2289 + fh_drop_write(fhp); 2290 + 2291 + return nfsd_xattr_errno(ret); 2292 + } 2293 + #endif 2294 + 2068 2295 /* 2069 2296 * Check for a user's access permissions to this inode. 2070 2297 */
+10
fs/nfsd/vfs.h
··· 76 76 __be32 nfsd_commit(struct svc_rqst *, struct svc_fh *, 77 77 loff_t, unsigned long, __be32 *verf); 78 78 #endif /* CONFIG_NFSD_V3 */ 79 + #ifdef CONFIG_NFSD_V4 80 + __be32 nfsd_getxattr(struct svc_rqst *rqstp, struct svc_fh *fhp, 81 + char *name, void **bufp, int *lenp); 82 + __be32 nfsd_listxattr(struct svc_rqst *rqstp, struct svc_fh *fhp, 83 + char **bufp, int *lenp); 84 + __be32 nfsd_removexattr(struct svc_rqst *rqstp, struct svc_fh *fhp, 85 + char *name); 86 + __be32 nfsd_setxattr(struct svc_rqst *rqstp, struct svc_fh *fhp, 87 + char *name, void *buf, u32 len, u32 flags); 88 + #endif 79 89 int nfsd_open_break_lease(struct inode *, int); 80 90 __be32 nfsd_open(struct svc_rqst *, struct svc_fh *, umode_t, 81 91 int, struct file **);