diff -urN nfsd-ref/fs/nfsd/vfs.c nfsd/fs/nfsd/vfs.c --- nfsd-ref/fs/nfsd/vfs.c Sun Dec 24 17:10:50 2000 +++ nfsd/fs/nfsd/vfs.c Sun Dec 24 17:14:10 2000 @@ -157,15 +157,12 @@ dparent = fhp->fh_dentry; exp = fhp->fh_export; -#if 0 - err = nfsd_permission(exp, dparent, MAY_EXEC); - if (err) - goto out; -#endif err = nfserr_acces; /* Lookup the name, but don't follow links */ - if (strcmp(name, "..")==0) { + if (strcmp(name, ".")==0) { + dchild = dget(dparent); + } else if (strcmp(name, "..")==0) { /* checking mountpoint crossing is very different when stepping up */ if (dparent == exp->ex_dentry) { if (!EX_CROSSMNT(exp)) @@ -283,11 +280,11 @@ if (delta<0) delta = -delta; if (delta < MAX_TOUCH_TIME_ERROR) { /* turn off ATTR_[AM]TIME_SET but leave ATTR_[AM]TIME - * this will cause notify_change to setthese times to "now" + * this will cause notify_change to set these times to "now" */ iap->ia_valid &= ~BOTH_TIME_SET; err = inode_change_ok(inode, iap); - } + } } if (err) @@ -295,8 +292,6 @@ /* The size case is special. It changes the file as well as the attributes. */ if (iap->ia_valid & ATTR_SIZE) { -if (!S_ISREG(inode->i_mode)) -printk("nfsd_setattr: size change??\n"); if (iap->ia_size < inode->i_size) { err = nfsd_permission(fhp->fh_export, dentry, MAY_TRUNC); if (err) @@ -433,7 +428,7 @@ struct svc_export *export; struct dentry *dentry; u32 query, result = 0; - int error; + unsigned int error; error = fh_verify(rqstp, fhp, 0, MAY_NOP); if (error) @@ -442,16 +437,16 @@ export = fhp->fh_export; dentry = fhp->fh_dentry; - if (S_ISREG(dentry->d_inode->i_mode)) { + if (S_ISREG(dentry->d_inode->i_mode)) map = nfs3_regaccess; - } else if (S_ISDIR(dentry->d_inode->i_mode)) { + else if (S_ISDIR(dentry->d_inode->i_mode)) map = nfs3_diraccess; - } else { + else map = nfs3_anyaccess; - } + query = *access; - while (map->access) { + for (; map->access; map++) { if (map->access & query) { error = nfsd_permission(export, dentry, (map->how | NO_OWNER_OVERRIDE)); if (error == 0) @@ -469,14 +464,13 @@ goto out; } } - map++; } *access = result; out: return error; } -#endif +#endif /* CONFIG_NFSD_V3 */ @@ -561,9 +555,8 @@ dentry->d_parent->d_name.name, dentry->d_name.name); if (filp->f_op && filp->f_op->release) filp->f_op->release(inode, filp); - if (filp->f_mode & FMODE_WRITE) { + if (filp->f_mode & FMODE_WRITE) put_write_access(inode); - } } /* @@ -646,7 +639,7 @@ goto out_close; /* Get readahead parameters */ - ra = nfsd_get_raparms(fhp->fh_handle.fh_dev, fhp->fh_handle.fh_ino); + ra = nfsd_get_raparms(fhp->fh_export->ex_dev, fhp->fh_dentry->d_inode->i_ino); if (ra) { file.f_reada = ra->p_reada; file.f_ramax = ra->p_ramax; @@ -821,8 +814,8 @@ #ifdef CONFIG_NFSD_V3 /* - * Commit all pendig writes to stable storage. - * Strictly speaking, we could sync just indicated the file region here, + * Commit all pending writes to stable storage. + * Strictly speaking, we could sync just the indicated file region here, * but there's currently no way we can ask the VFS to do so. * * We lock the file to make sure we return full WCC data to the client. @@ -871,6 +864,9 @@ err = nfserr_perm; if (!flen) goto out; + err = nfserr_exist; + if (isdotent(fname, flen)) + goto out; err = fh_verify(rqstp, fhp, S_IFDIR, MAY_CREATE); if (err) @@ -882,10 +878,6 @@ err = nfserr_notdir; if(!dirp->i_op || !dirp->i_op->lookup) goto out; - - err = nfserr_exist; - if (isdotent(fname, flen)) - goto out; /* * Check whether the response file handle has been verified yet. * If it has, the parent directory should already be locked. @@ -910,7 +902,7 @@ dentry->d_name.name); err = -EIO; goto out; - } + } } /* * Make sure the child dentry is still negative ... @@ -922,6 +914,10 @@ goto out; } + if (!(iap->ia_valid & ATTR_MODE)) + iap->ia_mode = 0; + iap->ia_mode = (iap->ia_mode & S_IALLUGO) | type; + /* * Get the dir op function pointer. */ @@ -968,10 +964,6 @@ write_inode_now(dchild->d_inode); } - /* - * Update the file handle to get the new inode info. - */ - fh_update(resfhp); /* Set file attributes. Mode has already been set and * setting uid/gid works only for root. Irix appears to @@ -981,6 +973,10 @@ err = 0; if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID|ATTR_MODE)) != 0) err = nfsd_setattr(rqstp, resfhp, iap); + /* + * Update the file handle to get the new inode info. + */ + fh_update(resfhp); out: return err; @@ -1001,10 +997,15 @@ struct dentry *dentry, *dchild; struct inode *dirp; int err; + __u32 v_mtime=0, v_atime=0; + int v_mode=0; err = nfserr_perm; if (!flen) goto out; + err = nfserr_exist; + if (isdotent(fname, flen)) + goto out; if (!(iap->ia_valid & ATTR_MODE)) iap->ia_mode = 0; err = fh_verify(rqstp, fhp, S_IFDIR, MAY_CREATE); @@ -1023,9 +1024,6 @@ if(!dirp->i_op->create) goto out; - err = nfserr_exist; - if (isdotent(fname, flen)) - goto out; /* * Compose the response file handle. */ @@ -1042,6 +1040,19 @@ if (err) goto out; + if (createmode == NFS3_CREATE_EXCLUSIVE) { + /* while the verifier would fit in mtime+atime, + * solaris7 gets confused (bugid 4218508) if these have + * the high bit set, so we use the mode as well + */ + v_mtime = verifier[0]&0x7fffffff; + v_atime = verifier[1]&0x7fffffff; + v_mode = S_IFREG + | ((verifier[0]&0x80000000) >> (32-7)) /* u+x */ + | ((verifier[1]&0x80000000) >> (32-9)) /* u+r */ + ; + } + if (dchild->d_inode) { err = 0; @@ -1059,10 +1070,10 @@ } break; case NFS3_CREATE_EXCLUSIVE: - if ( dchild->d_inode->i_mtime == verifier[0] - && dchild->d_inode->i_atime == verifier[1] - && dchild->d_inode->i_mode == S_IFREG - && dchild->d_inode->i_size == 0 ) + if ( dchild->d_inode->i_mtime == v_mtime + && dchild->d_inode->i_atime == v_atime + && dchild->d_inode->i_mode == v_mode + && dchild->d_inode->i_size == 0 ) break; /* fallthru */ case NFS3_CREATE_GUARDED: @@ -1087,16 +1098,20 @@ err = 0; if (createmode == NFS3_CREATE_EXCLUSIVE) { - /* Cram the verifier into atime/mtime */ - iap->ia_valid = ATTR_MTIME|ATTR_ATIME|ATTR_MTIME_SET|ATTR_ATIME_SET; - iap->ia_mtime = verifier[0]; - iap->ia_atime = verifier[1]; + /* Cram the verifier into atime/mtime/mode */ + iap->ia_valid = ATTR_MTIME|ATTR_ATIME + | ATTR_MTIME_SET|ATTR_ATIME_SET + | ATTR_MODE; + iap->ia_mtime = v_mtime; + iap->ia_atime = v_atime; + iap->ia_mode = v_mode; } - /* Set file attributes. Mode has already been set and - * setting uid/gid works only for root. Irix appears to - * send along the gid when it tries to implement setgid - * directories via NFS. Clear out all that cruft. + /* Set file attributes. + * Mode has already been set but we might need to reset it + * for CREATE_EXCLUSIVE + * Irix appears to send along the gid when it tries to + * implement setgid directories via NFS. Clear out all that cruft. */ set_attr: if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID|ATTR_MODE)) != 0) @@ -1113,62 +1128,6 @@ #endif /* CONFIG_NFSD_V3 */ /* - * Truncate a file. - * The calling routines must make sure to update the ctime - * field and call notify_change. - * - * XXX Nobody calls this thing? -DaveM - * N.B. After this call fhp needs an fh_put - */ -int -nfsd_truncate(struct svc_rqst *rqstp, struct svc_fh *fhp, unsigned long size) -{ - struct dentry *dentry; - struct inode *inode; - struct iattr newattrs; - int err; - kernel_cap_t saved_cap = 0; - - err = fh_verify(rqstp, fhp, S_IFREG, MAY_WRITE | MAY_TRUNC); - if (err) - goto out; - - dentry = fhp->fh_dentry; - inode = dentry->d_inode; - - err = get_write_access(inode); - if (err) - goto out_nfserr; - - /* Things look sane, lock and do it. */ - fh_lock(fhp); - DQUOT_INIT(inode); - newattrs.ia_size = size; - newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME; - if (current->fsuid != 0) { - saved_cap = current->cap_effective; - cap_clear(current->cap_effective); - } - err = notify_change(dentry, &newattrs); - if (!err) { - vmtruncate(inode, size); - if (inode->i_op && inode->i_op->truncate) - inode->i_op->truncate(inode); - } - if (current->fsuid != 0) - current->cap_effective = saved_cap; - put_write_access(inode); - if (EX_ISSYNC(fhp->fh_export)) - nfsd_sync_dir(dentry); - fh_unlock(fhp); -out_nfserr: - if (err) - err = nfserrno(-err); -out: - return err; -} - -/* * Read a symlink. On entry, *lenp must contain the maximum path length that * fits into the buffer. On return, it contains the true length. * N.B. After this call fhp needs an fh_put @@ -1181,7 +1140,7 @@ mm_segment_t oldfs; int err; - err = fh_verify(rqstp, fhp, S_IFLNK, MAY_READ); + err = fh_verify(rqstp, fhp, S_IFLNK, MAY_NOP); if (err) goto out; @@ -1232,15 +1191,15 @@ if (!flen || !plen) goto out; + err = nfserr_exist; + if (isdotent(fname, flen)) + goto out; + err = fh_verify(rqstp, fhp, S_IFDIR, MAY_CREATE); if (err) goto out; dentry = fhp->fh_dentry; - err = nfserr_exist; - if (isdotent(fname, flen)) - goto out; - err = nfserr_perm; dirp = dentry->d_inode; if (!dirp->i_op || !dirp->i_op->symlink) @@ -1308,6 +1267,11 @@ err = fh_verify(rqstp, ffhp, S_IFDIR, MAY_CREATE); if (err) goto out; + + err = nfserr_exist; + if (isdotent(fname, flen)) + goto out; + err = fh_verify(rqstp, tfhp, -S_IFDIR, MAY_NOP); if (err) goto out; @@ -1316,10 +1280,6 @@ if (!flen) goto out; - err = nfserr_exist; - if (isdotent(fname, flen)) - goto out; - ddir = ffhp->fh_dentry; dirp = ddir->d_inode; @@ -1503,13 +1463,14 @@ struct inode *dirp; int err; - err = fh_verify(rqstp, fhp, S_IFDIR, MAY_REMOVE); - if (err) - goto out; err = nfserr_acces; if (!flen || isdotent(fname, flen)) goto out; + err = fh_verify(rqstp, fhp, S_IFDIR, MAY_REMOVE); + if (err) + goto out; + dentry = fhp->fh_dentry; dirp = dentry->d_inode; @@ -1619,6 +1580,7 @@ * may choose to do less. */ inode = file.f_dentry->d_inode; + down(&inode->i_sem); while (1) { oldlen = cd.buflen; @@ -1627,9 +1589,7 @@ file.f_inode->i_dev, file.f_inode->i_ino, (int) file.f_pos, (int) oldlen, (int) cd.buflen); */ - down(&inode->i_sem); err = file.f_op->readdir(&file, &cd, (filldir_t) func); - up(&inode->i_sem); if (err < 0) goto out_nfserr; if (oldlen == cd.buflen) @@ -1637,16 +1597,15 @@ if (cd.eob) break; } + up(&inode->i_sem); /* If we didn't fill the buffer completely, we're at EOF */ eof = !cd.eob; if (cd.offset) { -#ifdef CONFIG_NFSD_V3 if (rqstp->rq_vers == 3) (void)enc64(cd.offset, file.f_pos); else -#endif /* CONFIG_NFSD_V3 */ *cd.offset = htonl(file.f_pos); }