--- linux-2.6.18.i686/fs/nfsd/vfs.c.orig	2009-07-10 13:45:12.018506000 -0700
+++ linux-2.6.18.i686/fs/nfsd/vfs.c	2009-07-13 16:39:08.626049000 -0700
@@ -1103,6 +1103,32 @@ nfsd_commit(struct svc_rqst *rqstp, stru
 }
 #endif /* CONFIG_NFSD_V3 */
 
+/* 
+ * a wrapper of nfsd_setattr() used only for CREATE.
+ * newfile: '1' for new created file, '0' otherwise.
+ * HPUX client sometimes creates a file in mode 000, and set
+ * size to 0. setting size to 0 may fail for some spcific
+ * file systems by the permission checking which requires
+ * WRITE privilege but the mode is 000.
+ * we ignore setting size to 0 for the creation, since it's
+ * just 0 after created.
+ * */
+static int
+nfsd_create_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp,
+		    struct iattr *iap, int check_guard, time_t guardtime,
+		    int newfile)
+{
+	int err = 0;
+
+	if (newfile && (iap->ia_valid & ATTR_SIZE) && (iap->ia_size == 0))
+		iap->ia_valid &= ~ATTR_SIZE;
+
+	if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID|ATTR_MODE)) != 0) {
+		err = nfsd_setattr(rqstp, fhp, iap, check_guard, guardtime);	
+	}
+
+	return err;
+}
 /*
  * Create a file (regular, directory, device, fifo); UNIX sockets 
  * not yet implemented.
@@ -1119,6 +1145,8 @@ nfsd_create(struct svc_rqst *rqstp, stru
 	struct dentry	*dentry, *dchild = NULL;
 	struct inode	*dirp;
 	int		err;
+	int newfile = 0;
+	int err2;
 
 	err = nfserr_perm;
 	if (!flen)
@@ -1185,6 +1213,7 @@ nfsd_create(struct svc_rqst *rqstp, stru
 	switch (type) {
 	case S_IFREG:
 		err = vfs_create(dirp, dchild, iap->ia_mode, NULL);
+		newfile = 1;
 		break;
 	case S_IFDIR:
 		err = vfs_mkdir(dirp, dchild, iap->ia_mode);
@@ -1213,11 +1242,10 @@ nfsd_create(struct svc_rqst *rqstp, stru
 	 * send along the gid when it tries to implement setgid
 	 * directories via NFS.
 	 */
-	if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID|ATTR_MODE)) != 0) {
-		int err2 = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0);
-		if (err2)
-			err = err2;
-	}
+	err2 = nfsd_create_setattr(rqstp, resfhp, iap, 0, (time_t)0, newfile);
+	if (err2)
+		err = err2;
+
 	/*
 	 * Update the file handle to get the new inode info.
 	 */
@@ -1247,6 +1275,8 @@ nfsd_create_v3(struct svc_rqst *rqstp, s
 	struct inode	*dirp;
 	int		err;
 	__u32		v_mtime=0, v_atime=0;
+	int err2;
+	int newfile = 0;
 
 	err = nfserr_perm;
 	if (!flen)
@@ -1331,6 +1361,8 @@ nfsd_create_v3(struct svc_rqst *rqstp, s
 	if (err < 0)
 		goto out_nfserr;
 
+	newfile = 1;
+
 	if (EX_ISSYNC(fhp->fh_export)) {
 		err = nfserrno(nfsd_sync_dir(dentry));
 		/* setattr will sync the child (or not) */
@@ -1352,11 +1384,9 @@ nfsd_create_v3(struct svc_rqst *rqstp, s
 	 * implement setgid directories via NFS. Clear out all that cruft.
 	 */
  set_attr:
-	if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID|ATTR_MODE)) != 0) {
- 		int err2 = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0);
-		if (err2)
-			err = err2;
-	}
+	err2 = nfsd_create_setattr(rqstp, resfhp, iap, 0, (time_t)0, newfile);
+	if (err2)
+		err = err2;
 
 	/*
 	 * Update the filehandle to get the new inode info.
