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

knfsd: 64 bit ino support for NFS server

Modify the NFS server code to support 64 bit ino's, as
appropriate for the system and the NFS protocol version.

The gist of the changes is to query the underlying file system
for attributes and not just to use the cached attributes in the
inode. For this specific purpose, the inode only contains an
ino field which unsigned long, which is large enough on 64 bit
platforms, but is not large enough on 32 bit platforms.

I haven't been able to find any reason why ->getattr can't be called
while i_mutex. The specification indicates that i_mutex is not
required to be held in order to invoke ->getattr, but it doesn't say
that i_mutex can't be held while invoking ->getattr.

I also haven't come to any conclusions regarding the value of
lease_get_mtime() and whether it should or should not be invoked
by fill_post_wcc() too. I chose not to change this because I
thought that it was safer to leave well enough alone. If we
decide to make a change, it can be done separately.

Signed-off-by: Peter Staubach <staubach@redhat.com>
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Acked-by: Neil Brown <neilb@suse.de>

authored by

Peter Staubach and committed by
J. Bruce Fields
40ee5dc6 21fcd02b

+45 -81
+27 -32
fs/nfsd/nfs3xdr.c
··· 174 174 encode_fattr3(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, 175 175 struct kstat *stat) 176 176 { 177 - struct dentry *dentry = fhp->fh_dentry; 178 - struct timespec time; 179 - 180 177 *p++ = htonl(nfs3_ftypes[(stat->mode & S_IFMT) >> 12]); 181 178 *p++ = htonl((u32) stat->mode); 182 179 *p++ = htonl((u32) stat->nlink); ··· 188 191 *p++ = htonl((u32) MAJOR(stat->rdev)); 189 192 *p++ = htonl((u32) MINOR(stat->rdev)); 190 193 p = encode_fsid(p, fhp); 191 - p = xdr_encode_hyper(p, (u64) stat->ino); 194 + p = xdr_encode_hyper(p, stat->ino); 192 195 p = encode_time3(p, &stat->atime); 193 - lease_get_mtime(dentry->d_inode, &time); 194 - p = encode_time3(p, &time); 196 + p = encode_time3(p, &stat->mtime); 195 197 p = encode_time3(p, &stat->ctime); 196 198 197 199 return p; ··· 199 203 static __be32 * 200 204 encode_saved_post_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp) 201 205 { 202 - struct inode *inode = fhp->fh_dentry->d_inode; 203 - 204 206 /* Attributes to follow */ 205 207 *p++ = xdr_one; 206 - 207 - *p++ = htonl(nfs3_ftypes[(fhp->fh_post_mode & S_IFMT) >> 12]); 208 - *p++ = htonl((u32) fhp->fh_post_mode); 209 - *p++ = htonl((u32) fhp->fh_post_nlink); 210 - *p++ = htonl((u32) nfsd_ruid(rqstp, fhp->fh_post_uid)); 211 - *p++ = htonl((u32) nfsd_rgid(rqstp, fhp->fh_post_gid)); 212 - if (S_ISLNK(fhp->fh_post_mode) && fhp->fh_post_size > NFS3_MAXPATHLEN) { 213 - p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN); 214 - } else { 215 - p = xdr_encode_hyper(p, (u64) fhp->fh_post_size); 216 - } 217 - p = xdr_encode_hyper(p, ((u64)fhp->fh_post_blocks) << 9); 218 - *p++ = fhp->fh_post_rdev[0]; 219 - *p++ = fhp->fh_post_rdev[1]; 220 - p = encode_fsid(p, fhp); 221 - p = xdr_encode_hyper(p, (u64) inode->i_ino); 222 - p = encode_time3(p, &fhp->fh_post_atime); 223 - p = encode_time3(p, &fhp->fh_post_mtime); 224 - p = encode_time3(p, &fhp->fh_post_ctime); 225 - 226 - return p; 208 + return encode_fattr3(rqstp, p, fhp, &fhp->fh_post_attr); 227 209 } 228 210 229 211 /* ··· 220 246 err = vfs_getattr(fhp->fh_export->ex_mnt, dentry, &stat); 221 247 if (!err) { 222 248 *p++ = xdr_one; /* attributes follow */ 249 + lease_get_mtime(dentry->d_inode, &stat.mtime); 223 250 return encode_fattr3(rqstp, p, fhp, &stat); 224 251 } 225 252 } ··· 259 284 return encode_post_op_attr(rqstp, p, fhp); 260 285 } 261 286 287 + /* 288 + * Fill in the post_op attr for the wcc data 289 + */ 290 + void fill_post_wcc(struct svc_fh *fhp) 291 + { 292 + int err; 293 + 294 + if (fhp->fh_post_saved) 295 + printk("nfsd: inode locked twice during operation.\n"); 296 + 297 + err = vfs_getattr(fhp->fh_export->ex_mnt, fhp->fh_dentry, 298 + &fhp->fh_post_attr); 299 + if (err) 300 + fhp->fh_post_saved = 0; 301 + else 302 + fhp->fh_post_saved = 1; 303 + } 262 304 263 305 /* 264 306 * XDR decode functions ··· 635 643 nfs3svc_encode_attrstat(struct svc_rqst *rqstp, __be32 *p, 636 644 struct nfsd3_attrstat *resp) 637 645 { 638 - if (resp->status == 0) 646 + if (resp->status == 0) { 647 + lease_get_mtime(resp->fh.fh_dentry->d_inode, 648 + &resp->stat.mtime); 639 649 p = encode_fattr3(rqstp, p, &resp->fh, &resp->stat); 650 + } 640 651 return xdr_ressize_check(rqstp, p); 641 652 } 642 653 ··· 797 802 798 803 static __be32 * 799 804 encode_entry_baggage(struct nfsd3_readdirres *cd, __be32 *p, const char *name, 800 - int namlen, ino_t ino) 805 + int namlen, u64 ino) 801 806 { 802 807 *p++ = xdr_one; /* mark entry present */ 803 808 p = xdr_encode_hyper(p, ino); /* file id */ ··· 868 873 #define NFS3_ENTRYPLUS_BAGGAGE (1 + 21 + 1 + (NFS3_FHSIZE >> 2)) 869 874 static int 870 875 encode_entry(struct readdir_cd *ccd, const char *name, int namlen, 871 - loff_t offset, ino_t ino, unsigned int d_type, int plus) 876 + loff_t offset, u64 ino, unsigned int d_type, int plus) 872 877 { 873 878 struct nfsd3_readdirres *cd = container_of(ccd, struct nfsd3_readdirres, 874 879 common);
+8 -9
fs/nfsd/nfs4xdr.c
··· 1679 1679 if (bmval0 & FATTR4_WORD0_FILEID) { 1680 1680 if ((buflen -= 8) < 0) 1681 1681 goto out_resource; 1682 - WRITE64((u64) stat.ino); 1682 + WRITE64(stat.ino); 1683 1683 } 1684 1684 if (bmval0 & FATTR4_WORD0_FILES_AVAIL) { 1685 1685 if ((buflen -= 8) < 0) ··· 1821 1821 WRITE32(stat.mtime.tv_nsec); 1822 1822 } 1823 1823 if (bmval1 & FATTR4_WORD1_MOUNTED_ON_FILEID) { 1824 - struct dentry *mnt_pnt, *mnt_root; 1825 - 1826 1824 if ((buflen -= 8) < 0) 1827 1825 goto out_resource; 1828 - mnt_root = exp->ex_mnt->mnt_root; 1829 - if (mnt_root->d_inode == dentry->d_inode) { 1830 - mnt_pnt = exp->ex_mnt->mnt_mountpoint; 1831 - WRITE64((u64) mnt_pnt->d_inode->i_ino); 1832 - } else 1833 - WRITE64((u64) stat.ino); 1826 + if (exp->ex_mnt->mnt_root->d_inode == dentry->d_inode) { 1827 + err = vfs_getattr(exp->ex_mnt->mnt_parent, 1828 + exp->ex_mnt->mnt_mountpoint, &stat); 1829 + if (err) 1830 + goto out_nfserr; 1831 + } 1832 + WRITE64(stat.ino); 1834 1833 } 1835 1834 *attrlenp = htonl((char *)p - (char *)attrlenp - 4); 1836 1835 *countp = p - buffer;
+4
fs/nfsd/nfsxdr.c
··· 523 523 cd->common.err = nfserr_toosmall; 524 524 return -EINVAL; 525 525 } 526 + if (ino > ~((u32) 0)) { 527 + cd->common.err = nfserr_fbig; 528 + return -EINVAL; 529 + } 526 530 *p++ = xdr_one; /* mark entry present */ 527 531 *p++ = htonl((u32) ino); /* file id */ 528 532 p = xdr_encode_array(p, name, namlen);/* name length & name */
+4 -38
include/linux/nfsd/nfsfh.h
··· 150 150 struct timespec fh_pre_ctime; /* ctime before oper */ 151 151 152 152 /* Post-op attributes saved in fh_unlock */ 153 - umode_t fh_post_mode; /* i_mode */ 154 - nlink_t fh_post_nlink; /* i_nlink */ 155 - uid_t fh_post_uid; /* i_uid */ 156 - gid_t fh_post_gid; /* i_gid */ 157 - __u64 fh_post_size; /* i_size */ 158 - unsigned long fh_post_blocks; /* i_blocks */ 159 - unsigned long fh_post_blksize;/* i_blksize */ 160 - __be32 fh_post_rdev[2];/* i_rdev */ 161 - struct timespec fh_post_atime; /* i_atime */ 162 - struct timespec fh_post_mtime; /* i_mtime */ 163 - struct timespec fh_post_ctime; /* i_ctime */ 153 + struct kstat fh_post_attr; /* full attrs after operation */ 164 154 #endif /* CONFIG_NFSD_V3 */ 165 155 166 156 } svc_fh; ··· 287 297 if (!fhp->fh_pre_saved) { 288 298 fhp->fh_pre_mtime = inode->i_mtime; 289 299 fhp->fh_pre_ctime = inode->i_ctime; 290 - fhp->fh_pre_size = inode->i_size; 291 - fhp->fh_pre_saved = 1; 300 + fhp->fh_pre_size = inode->i_size; 301 + fhp->fh_pre_saved = 1; 292 302 } 293 303 } 294 304 295 - /* 296 - * Fill in the post_op attr for the wcc data 297 - */ 298 - static inline void 299 - fill_post_wcc(struct svc_fh *fhp) 300 - { 301 - struct inode *inode = fhp->fh_dentry->d_inode; 302 - 303 - if (fhp->fh_post_saved) 304 - printk("nfsd: inode locked twice during operation.\n"); 305 - 306 - fhp->fh_post_mode = inode->i_mode; 307 - fhp->fh_post_nlink = inode->i_nlink; 308 - fhp->fh_post_uid = inode->i_uid; 309 - fhp->fh_post_gid = inode->i_gid; 310 - fhp->fh_post_size = inode->i_size; 311 - fhp->fh_post_blksize = BLOCK_SIZE; 312 - fhp->fh_post_blocks = inode->i_blocks; 313 - fhp->fh_post_rdev[0] = htonl((u32)imajor(inode)); 314 - fhp->fh_post_rdev[1] = htonl((u32)iminor(inode)); 315 - fhp->fh_post_atime = inode->i_atime; 316 - fhp->fh_post_mtime = inode->i_mtime; 317 - fhp->fh_post_ctime = inode->i_ctime; 318 - fhp->fh_post_saved = 1; 319 - } 305 + extern void fill_post_wcc(struct svc_fh *); 320 306 #else 321 307 #define fill_pre_wcc(ignored) 322 308 #define fill_post_wcc(notused)
+2 -2
include/linux/nfsd/xdr4.h
··· 428 428 cinfo->atomic = 1; 429 429 cinfo->before_ctime_sec = fhp->fh_pre_ctime.tv_sec; 430 430 cinfo->before_ctime_nsec = fhp->fh_pre_ctime.tv_nsec; 431 - cinfo->after_ctime_sec = fhp->fh_post_ctime.tv_sec; 432 - cinfo->after_ctime_nsec = fhp->fh_post_ctime.tv_nsec; 431 + cinfo->after_ctime_sec = fhp->fh_post_attr.ctime.tv_sec; 432 + cinfo->after_ctime_nsec = fhp->fh_post_attr.ctime.tv_nsec; 433 433 } 434 434 435 435 int nfs4svc_encode_voidres(struct svc_rqst *, __be32 *, void *);