From: NeilBrown <neilb@cse.unsw.edu.au>

unlike v2/v3, nfsv4 returns nfserr_inval when attempting to read, write,
commit or test lock a symlink.  nfsv4 does return nfserr_symlink on lookup
and open, so a simple fix in fh_verify() will not work.


---

 fs/nfsd/nfs4proc.c  |   14 +++++++++++---
 fs/nfsd/nfs4state.c |    2 ++
 fs/nfsd/nfs4xdr.c   |    2 ++
 3 files changed, 15 insertions(+), 3 deletions(-)

diff -puN fs/nfsd/nfs4proc.c~knfsd-symlink-fixes fs/nfsd/nfs4proc.c
--- 25/fs/nfsd/nfs4proc.c~knfsd-symlink-fixes	2004-02-25 02:32:15.000000000 -0800
+++ 25-akpm/fs/nfsd/nfs4proc.c	2004-02-25 02:32:15.000000000 -0800
@@ -224,11 +224,16 @@ nfsd4_access(struct svc_rqst *rqstp, str
 static inline int
 nfsd4_commit(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_commit *commit)
 {
+	int status;
+
 	u32 *p = (u32 *)commit->co_verf.data;
 	*p++ = nfssvc_boot.tv_sec;
 	*p++ = nfssvc_boot.tv_usec;
 
-	return nfsd_commit(rqstp, current_fh, commit->co_offset, commit->co_count);
+	status = nfsd_commit(rqstp, current_fh, commit->co_offset, commit->co_count);
+	if (status == nfserr_symlink)
+		status = nfserr_inval;
+	return status;
 }
 
 static inline int
@@ -558,9 +563,12 @@ zero_stateid:
 	*p++ = nfssvc_boot.tv_sec;
 	*p++ = nfssvc_boot.tv_usec;
 
-	return (nfsd_write(rqstp, current_fh, write->wr_offset,
+	status =  nfsd_write(rqstp, current_fh, write->wr_offset,
 			  write->wr_vec, write->wr_vlen, write->wr_buflen,
-			  &write->wr_how_written));
+			  &write->wr_how_written);
+	if (status == nfserr_symlink)
+		status = nfserr_inval;
+	return status;
 out:
 	nfs4_unlock_state();
 	return status;
diff -puN fs/nfsd/nfs4state.c~knfsd-symlink-fixes fs/nfsd/nfs4state.c
--- 25/fs/nfsd/nfs4state.c~knfsd-symlink-fixes	2004-02-25 02:32:15.000000000 -0800
+++ 25-akpm/fs/nfsd/nfs4state.c	2004-02-25 02:32:15.000000000 -0800
@@ -1974,6 +1974,8 @@ nfsd4_lockt(struct svc_rqst *rqstp, stru
 
 	if ((status = fh_verify(rqstp, current_fh, S_IFREG, 0))) {
 		printk("NFSD: nfsd4_lockt: fh_verify() failed!\n");
+		if (status == nfserr_symlink)
+			status = nfserr_inval;
 		goto out;
 	}
 
diff -puN fs/nfsd/nfs4xdr.c~knfsd-symlink-fixes fs/nfsd/nfs4xdr.c
--- 25/fs/nfsd/nfs4xdr.c~knfsd-symlink-fixes	2004-02-25 02:32:15.000000000 -0800
+++ 25-akpm/fs/nfsd/nfs4xdr.c	2004-02-25 02:32:15.000000000 -0800
@@ -2005,6 +2005,8 @@ nfsd4_encode_read(struct nfsd4_compoundr
 			   read->rd_offset,
 			   read->rd_iov, read->rd_vlen,
 			   &maxcount);
+	if (nfserr == nfserr_symlink)
+		nfserr = nfserr_inval;
 	if (nfserr)
 		return nfserr;
 	eof = (read->rd_offset + maxcount >= read->rd_fhp->fh_dentry->d_inode->i_size);

_