diff -u --recursive --new-file linux-2.2.14-nfsv3-0.20.10/fs/nfs/dir.c linux-2.2.14-nfsv3/fs/nfs/dir.c --- linux-2.2.14-nfsv3-0.20.10/fs/nfs/dir.c Tue May 23 15:36:37 2000 +++ linux-2.2.14-nfsv3/fs/nfs/dir.c Tue May 23 18:18:49 2000 @@ -809,14 +809,14 @@ * select the appropriate create strategy. Currently open_namei * does not pass the create flags. */ + nfs_zap_caches(dir_i); error = NFS_CALL(create, dir_i, (dir, &dir_attr, &dentry->d_name, &attr, 0, &fhandle, &fattr)); + nfs_refresh_inode(dir_i, &dir_attr); if (!error && fhandle.size != 0) error = nfs_instantiate(dentry, &fhandle, &fattr); if (error || fhandle.size == 0) d_drop(dentry); - nfs_refresh_inode(dir_i, &dir_attr); - nfs_zap_caches(dir_i); return error; } @@ -845,14 +845,14 @@ #endif + nfs_zap_caches(dir_i); error = NFS_CALL(mknod, dir_i, (dir, &dir_attr, &dentry->d_name, &attr, rdev, &fhandle, &fattr)); + nfs_refresh_inode(dir_i, &dir_attr); if (!error && fhandle.size != 0) error = nfs_instantiate(dentry, &fhandle, &fattr); if (error || fhandle.size == 0) d_drop(dentry); - nfs_refresh_inode(dir_i, &dir_attr); - nfs_zap_caches(dir_i); return error; } @@ -880,16 +880,15 @@ attr.ia_mode = mode | S_IFDIR; #endif + nfs_zap_caches(dir_i); error = NFS_CALL(mkdir, dir_i, (dir, &dir_attr, &dentry->d_name, &attr, &fhandle, &fattr)); - if (!error && fhandle.size != 0) { - dir_i->i_nlink ++; + nfs_refresh_inode(dir_i, &dir_attr); + if (!error && fhandle.size != 0) error = nfs_instantiate(dentry, &fhandle, &fattr); - } + if (error || fhandle.size == 0) d_drop(dentry); - nfs_refresh_inode(dir_i, &dir_attr); - nfs_zap_caches(dir_i); return error; } @@ -902,17 +901,14 @@ dfprintk(VFS, "NFS: rmdir(%x/%ld, %s\n", dir_i->i_dev, dir_i->i_ino, dentry->d_name.name); + nfs_zap_caches(dir_i); error = NFS_CALL(rmdir, dir_i, (dir, &dir_attr, &dentry->d_name)); + nfs_refresh_inode(dir_i, &dir_attr); - /* Update i_nlink and invalidate dentry. */ - if (!error) { + /* Free the inode */ + if (!error) d_delete(dentry); - if (dir_i->i_nlink) - dir_i->i_nlink --; - } - nfs_refresh_inode(dir_i, &dir_attr); - nfs_zap_caches(dir_i); return error; } @@ -1033,10 +1029,12 @@ goto out; } while(sdentry->d_inode != NULL); /* need negative lookup */ + nfs_zap_caches(dir_i); qsilly.name = silly; qsilly.len = strlen(silly); error = NFS_CALL(rename, dir_i, (dir, &dir_attr, &dentry->d_name, dir, &dir_attr, &qsilly)); + nfs_refresh_inode(dir_i, &dir_attr); if (!error) { nfs_renew_times(dentry); d_move(dentry, sdentry); @@ -1044,8 +1042,6 @@ NFS_DENTRY(dentry)->cred = rpcauth_lookupcred(NFS_CLIENT(dentry->d_inode)->cl_auth, 0); /* If we return 0 we don't unlink */ } - nfs_refresh_inode(dir_i, &dir_attr); - nfs_zap_caches(dir_i); dput(sdentry); out: return error; @@ -1066,6 +1062,14 @@ *inode = dentry->d_inode; int error, rehash = 0; + /* + * Unhash the dentry while we remove the file ... + */ + if (!list_empty(&dentry->d_hash)) { + d_drop(dentry); + rehash = 1; + } + dfprintk(VFS, "NFS: safe_remove(%s/%s, %ld)\n", dentry->d_parent->d_name.name, dentry->d_name.name, inode->i_ino); @@ -1087,34 +1091,23 @@ goto out; } - /* - * Unhash the dentry while we remove the file ... - */ - if (!list_empty(&dentry->d_hash)) { - d_drop(dentry); - rehash = 1; - } - + nfs_zap_caches(dir_i); + NFS_CACHEINV(inode); error = NFS_CALL(remove, dir_i, (dir, &dir_attr, &dentry->d_name, cred)); nfs_refresh_inode(dir_i, &dir_attr); - nfs_zap_caches(dir_i); if (error < 0) goto out; /* - * Update i_nlink and free the inode before unlinking. + * Free the inode */ - if (inode) { - if (inode->i_nlink) - inode->i_nlink --; - d_delete(dentry); - } + d_delete(dentry); +out: /* * Rehash the negative dentry if the operation succeeded. */ if (rehash) d_rehash(dentry); -out: return error; } @@ -1190,11 +1183,11 @@ qsymname.name = symname; qsymname.len = strlen(symname); + nfs_zap_caches(dir_i); error = NFS_CALL(symlink, dir_i, (dir, &dir_attr, &dentry->d_name, &qsymname, &attr, &sym_fh, &sym_attr)); nfs_refresh_inode(dir_i, &dir_attr); - nfs_zap_caches(dir_i); if (!error && sym_fh.size != 0 && (sym_attr.valid & NFS_ATTR_FATTR)) { error = nfs_instantiate(dentry, &sym_fh, &sym_attr); } else { @@ -1227,18 +1220,12 @@ * we can't use the existing dentry. */ d_drop(dentry); + nfs_zap_caches(dir_i); + NFS_CACHEINV(inode); error = NFS_CALL(link, inode, (old_dentry, &old_attr, dir, &dir_attr, &dentry->d_name)); - if (!error) { - /* - * Update the link count immediately, as some apps - * (e.g. pine) test this after making a link. - */ - inode->i_nlink++; - } nfs_refresh_inode(inode, &old_attr); nfs_refresh_inode(dir_i, &dir_attr); - nfs_zap_caches(dir_i); return error; } @@ -1276,8 +1263,17 @@ struct nfs_fattr old_attr, new_attr; struct inode * old_inode = old_dentry->d_inode; struct inode * new_inode = new_dentry->d_inode; - struct dentry * dentry = NULL; - int error, rehash = 0; + struct dentry * dentry = NULL, *rehash = NULL; + int error; + + /* + * To prevent any new references to the target during the rename, + * we unhash the dentry and free the inode in advance. + */ + if (!list_empty(&new_dentry->d_hash)) { + d_drop(new_dentry); + rehash = new_dentry; + } dfprintk(VFS, "NFS: rename(%s/%s -> %s/%s, ct=%d)\n", old_dentry->d_parent->d_name.name, old_dentry->d_name.name, @@ -1308,10 +1304,10 @@ /* silly-rename the existing target ... */ err = nfs_sillyrename(new_dir, new_dentry); if (!err) { - new_dentry = dentry; + new_dentry = rehash = dentry; new_inode = NULL; /* hash the replacement target */ - d_add(new_dentry, NULL); + d_instantiate(new_dentry, NULL); } /* dentry still busy? */ @@ -1341,32 +1337,23 @@ goto out; } - /* - * To prevent any new references to the target during the rename, - * we unhash the dentry and free the inode in advance. - */ - if (!list_empty(&new_dentry->d_hash)) { - d_drop(new_dentry); - rehash = 1; - } - if (new_inode) d_delete(new_dentry); + nfs_zap_caches(new_dir); + nfs_zap_caches(old_dir); error = NFS_CALL(rename, old_dir, (old_dentry->d_parent, &old_attr, &old_dentry->d_name, new_dentry->d_parent, &new_attr, &new_dentry->d_name)); nfs_refresh_inode(old_dir, &old_attr); - nfs_zap_caches(old_dir); nfs_refresh_inode(new_dir, &new_attr); - nfs_zap_caches(new_dir); +out: /* Update the dcache if needed */ if (rehash) - d_rehash(new_dentry); + d_rehash(rehash); if (!error && !S_ISDIR(old_inode->i_mode)) d_move(old_dentry, new_dentry); -out: /* new dentry created? */ if (dentry) dput(dentry); @@ -1378,11 +1365,22 @@ { struct nfs_fattr fattr; struct dentry *de = NULL; - int err; + int err = unix_permission(i, msk); struct list_head *start, *tmp; if (!NFS_PROTO(i)->access) - return unix_permission(i, msk); + goto out; + /* + * Trust UNIX mode bits except: + * + * 1) When override capabilities may have been invoked + * 2) When root squashing may be involved + * 3) When ACLs may overturn a negative answer */ + if (!capable(CAP_DAC_OVERRIDE) && !capable(CAP_DAC_READ_SEARCH) + && (current->fsuid != 0) && (current->fsgid != 0) + && err != -EACCES) + goto out; + tmp = start = &i->i_dentry; while ((tmp = tmp->next) != start) { de = list_entry(tmp, struct dentry, d_alias); @@ -1397,6 +1395,7 @@ current->fsgid != current->gid)) err = NFS_CALL(access, i, (de, msk, &fattr, 1)); nfs_refresh_inode(i, &fattr); + out: return err; } diff -u --recursive --new-file linux-2.2.14-nfsv3-0.20.10/fs/nfs/inode.c linux-2.2.14-nfsv3/fs/nfs/inode.c --- linux-2.2.14-nfsv3-0.20.10/fs/nfs/inode.c Tue May 23 15:36:37 2000 +++ linux-2.2.14-nfsv3/fs/nfs/inode.c Tue May 23 18:15:25 2000 @@ -602,23 +602,25 @@ int unhashed; restart: - tmp = head; + tmp = head->next; unhashed = 0; - while ((tmp = tmp->next) != head) { + while (tmp != head) { struct dentry *dentry = list_entry(tmp, struct dentry, d_alias); + dget(dentry); + if (!list_empty(&dentry->d_subdirs)) + shrink_dcache_parent(dentry); dprintk("nfs_free_dentries: found %s/%s, d_count=%d, hashed=%d\n", dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_count, !list_empty(&dentry->d_hash)); - if (!list_empty(&dentry->d_subdirs)) - shrink_dcache_parent(dentry); - if (!dentry->d_count) { - dget(dentry); + if (dentry->d_count == 1) { d_drop(dentry); dput(dentry); goto restart; } if (list_empty(&dentry->d_hash)) unhashed++; + tmp = tmp->next; + dput(dentry); } return unhashed; } diff -u --recursive --new-file linux-2.2.14-nfsv3-0.20.10/fs/nfs/nfs2xdr.c linux-2.2.14-nfsv3/fs/nfs/nfs2xdr.c --- linux-2.2.14-nfsv3-0.20.10/fs/nfs/nfs2xdr.c Tue May 23 15:36:37 2000 +++ linux-2.2.14-nfsv3/fs/nfs/nfs2xdr.c Tue May 23 18:15:25 2000 @@ -487,13 +487,6 @@ break; } } - p++; /* EOF flag */ - - if (p > end) { - printk(KERN_NOTICE - "NFS: short packet in readdir reply!\n"); - return -errno_NFSERR_IO; - } return nr; } diff -u --recursive --new-file linux-2.2.14-nfsv3-0.20.10/fs/nfs/write.c linux-2.2.14-nfsv3/fs/nfs/write.c --- linux-2.2.14-nfsv3-0.20.10/fs/nfs/write.c Tue May 23 15:36:37 2000 +++ linux-2.2.14-nfsv3/fs/nfs/write.c Tue May 23 18:15:25 2000 @@ -491,9 +491,6 @@ /* Deal with hard/soft limits. */ do { - /* If we're over the soft limit, flush out old requests */ - if (nfs_nr_requests >= MAX_REQUEST_SOFT) - nfs_wb_file(inode, file); /* If we're still over the soft limit, wake up some requests */ if (nfs_nr_requests >= MAX_REQUEST_SOFT) { @@ -506,7 +503,7 @@ /* If we haven't reached the hard limit yet, * try to allocate the request struct */ - if (nfs_nr_requests < MAX_REQUEST_HARD) { + if (cache->nr_requests < MAX_REQUEST_HARD) { req = nfs_page_alloc(); if (req != NULL) break; @@ -538,11 +535,6 @@ atomic_inc(&page->count); req->wb_offset = offset; req->wb_bytes = count; - /* If the region is locked, adjust the timeout */ - if (region_locked(inode, req)) - req->wb_timeout = jiffies + NFS_WRITEBACK_LOCKDELAY; - else - req->wb_timeout = jiffies + NFS_WRITEBACK_DELAY; req->wb_file = file; req->wb_cred = nfs_file_cred(file); file->f_count++; @@ -860,12 +852,17 @@ } spin_unlock(&nfs_wreq_lock); - /* Create the request. It's safe to sleep in this call because - * we only get here if the page is locked. - */ + /* If we're over the soft limit, flush out old requests */ + if (nfs_nr_requests >= MAX_REQUEST_SOFT) + nfs_wb_file(inode, file); new = nfs_create_request(inode, file, page, offset, bytes); if (!new) return ERR_PTR(-ENOMEM); + /* If the region is locked, adjust the timeout */ + if (region_locked(inode, new)) + new->wb_timeout = jiffies + NFS_WRITEBACK_LOCKDELAY; + else + new->wb_timeout = jiffies + NFS_WRITEBACK_DELAY; } /* We have a request for our page. @@ -920,27 +917,29 @@ */ #define NFS_STRATEGY_PAGES 8 static void -nfs_strategy(struct file *file) +nfs_strategy(struct inode *inode) { - struct inode *inode = file->f_dentry->d_inode; unsigned int dirty, wpages; dirty = inode->u.nfs_i.ndirty; wpages = NFS_SERVER(inode)->wpages; if (NFS_PROTO(inode)->version == 2) { if (dirty >= NFS_STRATEGY_PAGES * wpages) - nfs_flush_file(inode, file, 0, 0, 0); + nfs_flush_file(inode, NULL, 0, 0, 0); } else { if (dirty >= wpages) - nfs_flush_file(inode, file, 0, 0, 0); + nfs_flush_file(inode, NULL, 0, 0, 0); + if (inode->u.nfs_i.ncommit > NFS_STRATEGY_PAGES * wpages && + nfs_nr_requests > MAX_REQUEST_SOFT) + nfs_commit_file(inode, NULL, 0, 0, 0); } /* * If we're running out of requests, flush out everything * in order to reduce memory useage... */ - if (nfs_nr_requests > MAX_REQUEST_SOFT) - nfs_wb_file(inode, file); + if (inode->u.nfs_i.npages > MAX_REQUEST_SOFT) + nfs_wb_all(inode); } /* @@ -1032,7 +1031,7 @@ * of requests. */ if (req->wb_offset == 0 && req->wb_bytes == PAGE_CACHE_SIZE) - nfs_strategy(file); + nfs_strategy(inode); } nfs_release_request(req); done: