summaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1997-07-20 14:56:40 +0000
committerRalf Baechle <ralf@linux-mips.org>1997-07-20 14:56:40 +0000
commite308faf24f68e262d92d294a01ddca7a17e76762 (patch)
tree22c47cb315811834861f013067878ff664e95abd /fs/nfs
parent30c6397ce63178fcb3e7963ac247f0a03132aca9 (diff)
Sync with Linux 2.1.46.
Diffstat (limited to 'fs/nfs')
-rw-r--r--fs/nfs/dir.c546
-rw-r--r--fs/nfs/file.c7
-rw-r--r--fs/nfs/inode.c31
-rw-r--r--fs/nfs/nfsroot.c15
-rw-r--r--fs/nfs/read.c2
-rw-r--r--fs/nfs/symlink.c36
-rw-r--r--fs/nfs/write.c5
7 files changed, 218 insertions, 424 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 71835c255..b10331c6a 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -42,16 +42,15 @@ struct nfs_dirent {
static int nfs_dir_open(struct inode * inode, struct file * file);
static long nfs_dir_read(struct inode *, struct file *, char *, unsigned long);
static int nfs_readdir(struct inode *, struct file *, void *, filldir_t);
-static int nfs_lookup(struct inode *, const char *, int, struct inode **);
-static int nfs_create(struct inode *, const char *, int, int, struct inode **);
-static int nfs_mkdir(struct inode *, const char *, int, int);
-static int nfs_rmdir(struct inode *, const char *, int);
-static int nfs_unlink(struct inode *, const char *, int);
-static int nfs_symlink(struct inode *, const char *, int, const char *);
-static int nfs_link(struct inode *, struct inode *, const char *, int);
-static int nfs_mknod(struct inode *, const char *, int, int, int);
-static int nfs_rename(struct inode *, const char *, int,
- struct inode *, const char *, int);
+static int nfs_lookup(struct inode *, struct dentry *);
+static int nfs_create(struct inode *, struct dentry *, int);
+static int nfs_mkdir(struct inode *, struct dentry *, int);
+static int nfs_rmdir(struct inode *, struct dentry *);
+static int nfs_unlink(struct inode *, struct dentry *);
+static int nfs_symlink(struct inode *, struct dentry *, const char *);
+static int nfs_link(struct inode *, struct inode *, struct dentry *);
+static int nfs_mknod(struct inode *, struct dentry *, int, int);
+static int nfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *);
static struct file_operations nfs_dir_operations = {
NULL, /* lseek - default */
@@ -78,6 +77,7 @@ struct inode_operations nfs_dir_inode_operations = {
nfs_mknod, /* mknod */
nfs_rename, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
@@ -328,488 +328,267 @@ nfs_free_dircache(void)
}
-/*
- * Lookup caching is a big win for performance but this is just
- * a trial to see how well it works on a small scale.
- * For example, bash does a lookup on ".." 13 times for each path
- * element when running pwd. Yes, hard to believe but true.
- * Try pwd in a filesystem mounted with noac.
- *
- * It trades a little cpu time and memory for a lot of network bandwidth.
- * Since the cache is not hashed yet, it is a good idea not to make it too
- * large because every lookup looks through the entire cache even
- * though most of them will fail.
- *
- * FIXME: The lookup cache should also cache failed lookups. This can
- * be a considerable win on diskless clients.
- */
-
-static struct nfs_lookup_cache_entry {
- kdev_t dev;
- ino_t inode;
- char filename[NFS_MAXNAMLEN + 1];
- struct nfs_fh fhandle;
- struct nfs_fattr fattr;
- unsigned long expiration_date;
-} nfs_lookup_cache[NFS_LOOKUP_CACHE_SIZE];
-
-static struct nfs_lookup_cache_entry *nfs_lookup_cache_index(struct inode *dir,
- const char *filename)
-{
- struct nfs_lookup_cache_entry *entry;
- int i;
-
- for (i = 0; i < NFS_LOOKUP_CACHE_SIZE; i++) {
- entry = nfs_lookup_cache + i;
- if (entry->dev == dir->i_dev
- && entry->inode == dir->i_ino
- && !strncmp(filename, entry->filename, NFS_MAXNAMLEN))
- return entry;
- }
- return NULL;
-}
-
-static int nfs_lookup_cache_lookup(struct inode *dir, const char *filename,
- struct nfs_fh *fhandle,
- struct nfs_fattr *fattr)
-{
- static int nfs_lookup_cache_in_use = 0;
-
- struct nfs_lookup_cache_entry *entry;
-
- dfprintk(LOOKUPCACHE, "NFS: lookup_cache_lookup(%x/%ld, %s)\n",
- dir->i_dev, dir->i_ino, filename);
- if (!nfs_lookup_cache_in_use) {
- memset(nfs_lookup_cache, 0, sizeof(nfs_lookup_cache));
- nfs_lookup_cache_in_use = 1;
- }
- if ((entry = nfs_lookup_cache_index(dir, filename))) {
- if (jiffies > entry->expiration_date) {
- entry->dev = 0;
- return 0;
- }
- *fhandle = entry->fhandle;
- *fattr = entry->fattr;
- return 1;
- }
- return 0;
-}
-
-static void nfs_lookup_cache_add(struct inode *dir, const char *filename,
- struct nfs_fh *fhandle,
- struct nfs_fattr *fattr)
-{
- static int nfs_lookup_cache_pos = 0;
- struct nfs_lookup_cache_entry *entry;
-
- dfprintk(LOOKUPCACHE, "NFS: lookup_cache_add(%x/%ld, %s\n",
- dir->i_dev, dir->i_ino, filename);
-
- /* compensate for bug in SGI NFS server */
- if (fattr->size == -1 || fattr->uid == -1 || fattr->gid == -1
- || fattr->atime.seconds == -1 || fattr->mtime.seconds == -1)
- return;
- if (!(entry = nfs_lookup_cache_index(dir, filename))) {
- entry = nfs_lookup_cache + nfs_lookup_cache_pos++;
- if (nfs_lookup_cache_pos == NFS_LOOKUP_CACHE_SIZE)
- nfs_lookup_cache_pos = 0;
- }
-
- entry->dev = dir->i_dev;
- entry->inode = dir->i_ino;
- strcpy(entry->filename, filename);
- entry->fhandle = *fhandle;
- entry->fattr = *fattr;
- entry->expiration_date = jiffies + (S_ISDIR(fattr->mode)
- ? NFS_SERVER(dir)->acdirmin : NFS_SERVER(dir)->acregmin);
-}
-
-static void nfs_lookup_cache_remove(struct inode *dir, struct inode *inode,
- const char *filename)
-{
- struct nfs_lookup_cache_entry *entry;
- kdev_t dev;
- ino_t fileid;
- int i;
-
- if (inode) {
- dev = inode->i_dev;
- fileid = inode->i_ino;
- }
- else if ((entry = nfs_lookup_cache_index(dir, filename))) {
- dev = entry->dev;
- fileid = entry->fattr.fileid;
- }
- else
- return;
-
- dfprintk(LOOKUPCACHE, "NFS: lookup_cache_remove(%x/%ld)\n",
- dev, (long)fileid);
-
- for (i = 0; i < NFS_LOOKUP_CACHE_SIZE; i++) {
- entry = nfs_lookup_cache + i;
- if (entry->dev == dev && entry->fattr.fileid == fileid)
- entry->dev = 0;
- }
-}
-
-static void nfs_lookup_cache_refresh(struct inode *file,
- struct nfs_fattr *fattr)
-{
- struct nfs_lookup_cache_entry *entry;
- kdev_t dev = file->i_dev;
- int fileid = file->i_ino;
- int i;
-
- for (i = 0; i < NFS_LOOKUP_CACHE_SIZE; i++) {
- entry = nfs_lookup_cache + i;
- if (entry->dev == dev && entry->fattr.fileid == fileid)
- entry->fattr = *fattr;
- }
-}
-
-static int nfs_lookup(struct inode *dir, const char *__name, int len,
- struct inode **result)
+static int nfs_lookup(struct inode *dir, struct dentry * dentry)
{
+ struct inode *inode;
struct nfs_fh fhandle;
struct nfs_fattr fattr;
- char name[len > NFS_MAXNAMLEN? 1 : len+1];
+ int len = dentry->d_name.len;
int error;
dfprintk(VFS, "NFS: lookup(%x/%ld, %.*s)\n",
- dir->i_dev, dir->i_ino, len, __name);
+ dir->i_dev, dir->i_ino, len, dentry->d_name.name);
- *result = NULL;
if (!dir || !S_ISDIR(dir->i_mode)) {
printk("nfs_lookup: inode is NULL or not a directory\n");
- iput(dir);
return -ENOENT;
}
- if (len > NFS_MAXNAMLEN) {
- iput(dir);
+
+ if (len > NFS_MAXNAMLEN)
return -ENAMETOOLONG;
- }
- memcpy(name,__name,len);
- name[len] = '\0';
- if (len == 0 || (len == 1 && name[0] == '.')) { /* cheat for "" and "." */
- *result = dir;
- return 0;
- }
- if ((NFS_SERVER(dir)->flags & NFS_MOUNT_NOAC)
- || !nfs_lookup_cache_lookup(dir, name, &fhandle, &fattr)) {
- if ((error = nfs_proc_lookup(NFS_SERVER(dir), NFS_FH(dir),
- name, &fhandle, &fattr))) {
- iput(dir);
- return error;
- }
- nfs_lookup_cache_add(dir, name, &fhandle, &fattr);
- }
- if (!(*result = nfs_fhget(dir->i_sb, &fhandle, &fattr))) {
- iput(dir);
- return -EACCES;
- }
- iput(dir);
+
+ error = nfs_proc_lookup(NFS_SERVER(dir), NFS_FH(dir), dentry->d_name.name, &fhandle, &fattr);
+
+ inode = NULL;
+ if (!error) {
+ error = -ENOENT;
+ inode = nfs_fhget(dir->i_sb, &fhandle, &fattr);
+ if (!inode)
+ return -EACCES;
+ } else if (error != -ENOENT)
+ return error;
+
+ d_add(dentry, inode);
return 0;
}
-static int nfs_create(struct inode *dir, const char *name, int len, int mode,
- struct inode **result)
+static int nfs_create(struct inode *dir, struct dentry * dentry, int mode)
{
struct nfs_sattr sattr;
struct nfs_fattr fattr;
struct nfs_fh fhandle;
+ struct inode *inode;
int error;
dfprintk(VFS, "NFS: create(%x/%ld, %s\n",
- dir->i_dev, dir->i_ino, name);
+ dir->i_dev, dir->i_ino, dentry->d_name.name);
- *result = NULL;
if (!dir || !S_ISDIR(dir->i_mode)) {
printk("nfs_create: inode is NULL or not a directory\n");
- iput(dir);
return -ENOENT;
}
- if (len > NFS_MAXNAMLEN) {
- iput(dir);
+
+ if (dentry->d_name.len > NFS_MAXNAMLEN)
return -ENAMETOOLONG;
- }
+
sattr.mode = mode;
sattr.uid = sattr.gid = sattr.size = (unsigned) -1;
sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;
- if ((error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dir),
- name, &sattr, &fhandle, &fattr))) {
- iput(dir);
+ error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dir),
+ dentry->d_name.name, &sattr, &fhandle, &fattr);
+
+ if (error)
return error;
- }
- if (!(*result = nfs_fhget(dir->i_sb, &fhandle, &fattr))) {
- iput(dir);
+
+ inode = nfs_fhget(dir->i_sb, &fhandle, &fattr);
+ if (!inode)
return -EACCES;
- }
- nfs_lookup_cache_add(dir, name, &fhandle, &fattr);
- nfs_invalidate_dircache(dir);
- iput(dir);
+
+ d_instantiate(dentry, inode);
return 0;
}
-static int nfs_mknod(struct inode *dir, const char *name, int len,
- int mode, int rdev)
+static int nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rdev)
{
struct nfs_sattr sattr;
struct nfs_fattr fattr;
struct nfs_fh fhandle;
+ struct inode *inode;
int error;
dfprintk(VFS, "NFS: mknod(%x/%ld, %s\n",
- dir->i_dev, dir->i_ino, name);
+ dir->i_dev, dir->i_ino, dentry->d_name.name);
if (!dir || !S_ISDIR(dir->i_mode)) {
printk("nfs_mknod: inode is NULL or not a directory\n");
- iput(dir);
return -ENOENT;
}
- if (len > NFS_MAXNAMLEN) {
- iput(dir);
+
+ if (dentry->d_name.len > NFS_MAXNAMLEN)
return -ENAMETOOLONG;
- }
+
sattr.mode = mode;
- sattr.uid = sattr.gid = (unsigned) -1;
+ sattr.uid = sattr.gid = sattr.size = (unsigned) -1;
if (S_ISCHR(mode) || S_ISBLK(mode))
sattr.size = rdev; /* get out your barf bag */
- else
- sattr.size = (unsigned) -1;
+
sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;
error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dir),
- name, &sattr, &fhandle, &fattr);
- if (!error)
- nfs_lookup_cache_add(dir, name, &fhandle, &fattr);
- nfs_invalidate_dircache(dir);
- iput(dir);
- return error;
+ dentry->d_name.name, &sattr, &fhandle, &fattr);
+
+ if (error)
+ return error;
+
+ inode = nfs_fhget(dir->i_sb, &fhandle, &fattr);
+ if (!inode)
+ return -EACCES;
+
+ d_instantiate(dentry, inode);
+ return 0;
}
-static int nfs_mkdir(struct inode *dir, const char *name, int len, int mode)
+static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
{
struct nfs_sattr sattr;
struct nfs_fattr fattr;
struct nfs_fh fhandle;
+ struct inode * inode;
int error;
dfprintk(VFS, "NFS: mkdir(%x/%ld, %s\n",
- dir->i_dev, dir->i_ino, name);
+ dir->i_dev, dir->i_ino, dentry->d_name.name);
if (!dir || !S_ISDIR(dir->i_mode)) {
printk("nfs_mkdir: inode is NULL or not a directory\n");
- iput(dir);
return -ENOENT;
}
- if (len > NFS_MAXNAMLEN) {
- iput(dir);
+
+ if (dentry->d_name.len > NFS_MAXNAMLEN)
return -ENAMETOOLONG;
- }
+
sattr.mode = mode;
sattr.uid = sattr.gid = sattr.size = (unsigned) -1;
sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;
+
error = nfs_proc_mkdir(NFS_SERVER(dir), NFS_FH(dir),
- name, &sattr, &fhandle, &fattr);
- if (!error)
- nfs_lookup_cache_add(dir, name, &fhandle, &fattr);
- nfs_invalidate_dircache(dir);
- iput(dir);
- return error;
+ dentry->d_name.name, &sattr, &fhandle, &fattr);
+
+ if (error)
+ return error;
+
+ inode = nfs_fhget(dir->i_sb, &fhandle, &fattr);
+ if (!inode)
+ return -EACCES;
+
+ d_instantiate(dentry, inode);
+ return 0;
}
-static int nfs_rmdir(struct inode *dir, const char *name, int len)
+static int nfs_rmdir(struct inode *dir, struct dentry *dentry)
{
int error;
dfprintk(VFS, "NFS: rmdir(%x/%ld, %s\n",
- dir->i_dev, dir->i_ino, name);
+ dir->i_dev, dir->i_ino, dentry->d_name.name);
if (!dir || !S_ISDIR(dir->i_mode)) {
printk("nfs_rmdir: inode is NULL or not a directory\n");
- iput(dir);
return -ENOENT;
}
- if (len > NFS_MAXNAMLEN) {
- iput(dir);
- return -ENAMETOOLONG;
- }
- error = nfs_proc_rmdir(NFS_SERVER(dir), NFS_FH(dir), name);
- if (!error)
- nfs_lookup_cache_remove(dir, NULL, name);
- nfs_invalidate_dircache(dir);
- iput(dir);
- return error;
-}
-
-static int nfs_sillyrename(struct inode *dir, const char *name, int len)
-{
- struct inode *inode;
- char silly[16];
- int slen, ret;
-
- atomic_inc(&dir->i_count);
- if (nfs_lookup(dir, name, len, &inode) < 0)
- return -EIO; /* arbitrary */
-
- if (atomic_read(&inode->i_count) == 1) {
- iput(inode);
- return -EIO;
- }
- if (NFS_RENAMED_DIR(inode)) {
- iput(NFS_RENAMED_DIR(inode));
- NFS_RENAMED_DIR(inode) = NULL;
- iput(inode);
- return -EIO;
- }
- slen = sprintf(silly, ".nfs%ld", inode->i_ino);
- if (len == slen && !strncmp(name, silly, len)) {
- iput(inode);
- return -EIO; /* DWIM */
- }
+ if (dentry->d_name.len > NFS_MAXNAMLEN)
+ return -ENAMETOOLONG;
- dfprintk(VFS, "NFS: sillyrename(%x/%ld, %s)\n",
- dir->i_dev, dir->i_ino, name);
+ error = nfs_proc_rmdir(NFS_SERVER(dir), NFS_FH(dir), dentry->d_name.name);
+ if (error)
+ return error;
- ret = nfs_proc_rename(NFS_SERVER(dir), NFS_FH(dir), name,
- NFS_FH(dir), silly);
- if (ret >= 0) {
- nfs_lookup_cache_remove(dir, NULL, name);
- nfs_lookup_cache_remove(dir, NULL, silly);
- NFS_RENAMED_DIR(inode) = dir;
- atomic_inc(&dir->i_count);
- }
- nfs_invalidate_dircache(dir);
- iput(inode);
- return ret;
+ d_delete(dentry);
+ return 0;
}
/*
- * When releasing the inode, finally remove any unlinked but open files.
- * Note that we have to clear the set of pending signals temporarily;
- * otherwise the RPC call will fail.
+ * We should do silly-rename here, but I'm too lazy to fix
+ * up the directory entry implications of it..
*/
-void nfs_sillyrename_cleanup(struct inode *inode)
-{
- unsigned long oldsig;
- struct inode *dir = NFS_RENAMED_DIR(inode);
- char silly[14];
- int error, slen;
-
- dfprintk(VFS, "NFS: sillyrename cleanup(%x/%ld)\n",
- inode->i_dev, inode->i_ino);
-
- oldsig = current->signal;
- current->signal = 0;
-
- slen = sprintf(silly, ".nfs%ld", inode->i_ino);
- error = nfs_proc_remove(NFS_SERVER(dir), NFS_FH(dir), silly);
- if (error < 0)
- printk("NFS: silly_rename cleanup failed (err %d)\n", -error);
-
- nfs_lookup_cache_remove(dir, NULL, silly);
- nfs_invalidate_dircache(dir);
- NFS_RENAMED_DIR(inode) = NULL;
- iput(dir);
-
- current->signal |= oldsig;
-}
-
-static int nfs_unlink(struct inode *dir, const char *name, int len)
+static int nfs_unlink(struct inode *dir, struct dentry *dentry)
{
int error;
dfprintk(VFS, "NFS: unlink(%x/%ld, %s)\n",
- dir->i_dev, dir->i_ino, name);
+ dir->i_dev, dir->i_ino, dentry->d_name.name);
if (!dir || !S_ISDIR(dir->i_mode)) {
printk("nfs_unlink: inode is NULL or not a directory\n");
- iput(dir);
return -ENOENT;
}
- if (len > NFS_MAXNAMLEN) {
- iput(dir);
+
+ if (dentry->d_name.len > NFS_MAXNAMLEN)
return -ENAMETOOLONG;
- }
- if ((error = nfs_sillyrename(dir, name, len)) < 0) {
- error = nfs_proc_remove(NFS_SERVER(dir), NFS_FH(dir), name);
- if (!error)
- nfs_lookup_cache_remove(dir, NULL, name);
- }
- nfs_invalidate_dircache(dir);
- iput(dir);
- return error;
+
+ error = nfs_proc_remove(NFS_SERVER(dir), NFS_FH(dir), dentry->d_name.name);
+ if (error)
+ return error;
+
+ d_delete(dentry);
+ return 0;
}
-static int nfs_symlink(struct inode *dir, const char *name, int len,
- const char *symname)
+static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
{
struct nfs_sattr sattr;
+ struct nfs_fattr fattr;
+ struct nfs_fh fhandle;
+ struct inode * inode;
int error;
dfprintk(VFS, "NFS: symlink(%x/%ld, %s, %s)\n",
- dir->i_dev, dir->i_ino, name, symname);
+ dir->i_dev, dir->i_ino, dentry->d_name.name, symname);
if (!dir || !S_ISDIR(dir->i_mode)) {
printk("nfs_symlink: inode is NULL or not a directory\n");
- iput(dir);
return -ENOENT;
}
- if (len > NFS_MAXNAMLEN) {
- iput(dir);
+
+ if (dentry->d_name.len > NFS_MAXNAMLEN)
return -ENAMETOOLONG;
- }
- if (strlen(symname) > NFS_MAXPATHLEN) {
- iput(dir);
+
+ if (strlen(symname) > NFS_MAXPATHLEN)
return -ENAMETOOLONG;
- }
+
sattr.mode = S_IFLNK | S_IRWXUGO; /* SunOS 4.1.2 crashes without this! */
sattr.uid = sattr.gid = sattr.size = (unsigned) -1;
sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;
+
error = nfs_proc_symlink(NFS_SERVER(dir), NFS_FH(dir),
- name, symname, &sattr);
- nfs_invalidate_dircache(dir);
- iput(dir);
- return error;
+ dentry->d_name.name, symname, &sattr);
+
+ if (error)
+ return error;
+
+ inode = nfs_fhget(dir->i_sb, &fhandle, &fattr);
+ if (!inode)
+ return -EACCES;
+
+ d_instantiate(dentry, inode);
+ return 0;
}
-static int nfs_link(struct inode *oldinode, struct inode *dir,
- const char *name, int len)
+static int nfs_link(struct inode *inode, struct inode *dir, struct dentry *dentry)
{
int error;
dfprintk(VFS, "NFS: link(%x/%ld -> %x/%ld, %s)\n",
- oldinode->i_dev, oldinode->i_ino,
- dir->i_dev, dir->i_ino, name);
+ inode->i_dev, inode->i_ino,
+ dir->i_dev, dir->i_ino, dentry->d_name.name);
- if (!oldinode) {
- printk("nfs_link: old inode is NULL\n");
- iput(oldinode);
- iput(dir);
- return -ENOENT;
- }
if (!dir || !S_ISDIR(dir->i_mode)) {
printk("nfs_link: dir is NULL or not a directory\n");
- iput(oldinode);
- iput(dir);
return -ENOENT;
}
- if (len > NFS_MAXNAMLEN) {
- iput(oldinode);
- iput(dir);
+
+ if (dentry->d_name.len > NFS_MAXNAMLEN)
return -ENAMETOOLONG;
- }
- error = nfs_proc_link(NFS_SERVER(oldinode), NFS_FH(oldinode),
- NFS_FH(dir), name);
- if (!error) {
- nfs_lookup_cache_remove(dir, oldinode, NULL);
- NFS_READTIME(oldinode) = 0; /* force getattr */
- }
- nfs_invalidate_dircache(dir);
- iput(oldinode);
- iput(dir);
- return error;
+
+ error = nfs_proc_link(NFS_SERVER(inode), NFS_FH(inode),
+ NFS_FH(dir), dentry->d_name.name);
+
+ if (error)
+ return error;
+
+ inode->i_count++;
+ d_instantiate(dentry, inode);
+ return 0;
}
/*
@@ -821,45 +600,39 @@ static int nfs_link(struct inode *oldinode, struct inode *dir,
* rename the old file using the silly_rename stuff. This way, the original
* file in old_dir will go away when the last process iput()s the inode.
*/
-static int nfs_rename(struct inode *old_dir, const char *old_name, int old_len,
- struct inode *new_dir, const char *new_name, int new_len)
+static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
+ struct inode *new_dir, struct dentry *new_dentry)
{
int error;
dfprintk(VFS, "NFS: rename(%x/%ld, %s -> %x/%ld, %s)\n",
- old_dir->i_dev, old_dir->i_ino, old_name,
- new_dir->i_dev, new_dir->i_ino, new_name);
+ old_dir->i_dev, old_dir->i_ino, old_dentry->d_name.name,
+ new_dir->i_dev, new_dir->i_ino, new_dentry->d_name.name);
if (!old_dir || !S_ISDIR(old_dir->i_mode)) {
printk("nfs_rename: old inode is NULL or not a directory\n");
- iput(old_dir);
- iput(new_dir);
return -ENOENT;
}
+
if (!new_dir || !S_ISDIR(new_dir->i_mode)) {
printk("nfs_rename: new inode is NULL or not a directory\n");
- iput(old_dir);
- iput(new_dir);
return -ENOENT;
}
- if (old_len > NFS_MAXNAMLEN || new_len > NFS_MAXNAMLEN) {
- iput(old_dir);
- iput(new_dir);
+
+ if (old_dentry->d_name.len > NFS_MAXNAMLEN || new_dentry->d_name.len > NFS_MAXNAMLEN)
return -ENAMETOOLONG;
- }
error = nfs_proc_rename(NFS_SERVER(old_dir),
- NFS_FH(old_dir), old_name,
- NFS_FH(new_dir), new_name);
- if (!error) {
- nfs_lookup_cache_remove(old_dir, NULL, old_name);
- nfs_lookup_cache_remove(new_dir, NULL, new_name);
- }
- nfs_invalidate_dircache(old_dir);
- nfs_invalidate_dircache(new_dir);
- iput(old_dir);
- iput(new_dir);
- return error;
+ NFS_FH(old_dir), old_dentry->d_name.name,
+ NFS_FH(new_dir), new_dentry->d_name.name);
+
+ if (error)
+ return error;
+
+ /* Update the dcache */
+ d_move(old_dentry, new_dentry->d_parent, &new_dentry->d_name);
+ d_delete(new_dentry);
+ return 0;
}
/*
@@ -873,8 +646,7 @@ void nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
int was_empty;
dfprintk(VFS, "NFS: refresh_inode(%x/%ld ct=%d)\n",
- inode->i_dev, inode->i_ino,
- atomic_read(&inode->i_count));
+ inode->i_dev, inode->i_ino, inode->i_count);
if (!inode || !fattr) {
printk("nfs_refresh_inode: inode or fattr is NULL\n");
@@ -925,6 +697,4 @@ void nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
init_fifo(inode);
} else
inode->i_op = NULL;
- nfs_lookup_cache_refresh(inode, fattr);
}
-
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index 56540bbdc..eb4735a6d 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -69,6 +69,7 @@ struct inode_operations nfs_file_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
nfs_readpage, /* readpage */
nfs_writepage, /* writepage */
NULL, /* bmap */
@@ -142,7 +143,7 @@ nfs_file_write(struct inode *inode, struct file *file,
int result;
dfprintk(VFS, "nfs: write(%x/%ld (%d), %lu@%lu)\n",
- inode->i_dev, inode->i_ino, atomic_read(&inode->i_count),
+ inode->i_dev, inode->i_ino, inode->i_count,
count, (unsigned long) file->f_pos);
if (!inode) {
@@ -179,11 +180,11 @@ nfs_lock(struct inode *inode, struct file *filp, int cmd, struct file_lock *fl)
int status;
dprintk("NFS: nfs_lock(f=%4x/%ld, t=%x, fl=%x, r=%ld:%ld)\n",
- filp->f_inode->i_dev, filp->f_inode->i_ino,
+ filp->f_dentry->d_inode->i_dev, filp->f_dentry->d_inode->i_ino,
fl->fl_type, fl->fl_flags,
fl->fl_start, fl->fl_end);
- if (!(inode = filp->f_inode))
+ if (!(inode = filp->f_dentry->d_inode))
return -EINVAL;
/* No mandatory locks over NFS */
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 5ab9600e9..cf52a0d56 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -36,15 +36,17 @@
static int nfs_notify_change(struct inode *, struct iattr *);
static void nfs_put_inode(struct inode *);
+static void nfs_delete_inode(struct inode *);
static void nfs_put_super(struct super_block *);
static void nfs_read_inode(struct inode *);
-static void nfs_statfs(struct super_block *, struct statfs *, int bufsiz);
+static int nfs_statfs(struct super_block *, struct statfs *, int bufsiz);
static struct super_operations nfs_sops = {
nfs_read_inode, /* read inode */
- nfs_notify_change, /* notify change */
NULL, /* write inode */
nfs_put_inode, /* put inode */
+ nfs_delete_inode, /* delete inode */
+ nfs_notify_change, /* notify change */
nfs_put_super, /* put superblock */
NULL, /* write superblock */
nfs_statfs, /* stat filesystem */
@@ -73,11 +75,16 @@ static void
nfs_put_inode(struct inode * inode)
{
dprintk("NFS: put_inode(%x/%ld)\n", inode->i_dev, inode->i_ino);
+}
- if (NFS_RENAMED_DIR(inode))
- nfs_sillyrename_cleanup(inode);
- if (inode->i_pipe)
- clear_inode(inode);
+/*
+ * This should do any silly-rename cleanups once we
+ * get silly-renaming working again..
+ */
+static void
+nfs_delete_inode(struct inode * inode)
+{
+ dprintk("NFS: delete_inode(%x/%ld)\n", inode->i_dev, inode->i_ino);
}
void
@@ -230,7 +237,8 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent)
/* Unlock super block and try to get root fh attributes */
unlock_super(sb);
- if ((sb->s_mounted = nfs_fhget(sb, &data->root, NULL)) != NULL) {
+ sb->s_root = d_alloc_root(nfs_fhget(sb, &data->root, NULL), NULL);
+ if (sb->s_root != NULL) {
/* We're airborne */
if (!(server->flags & NFS_MOUNT_NONLM))
lockd_up();
@@ -250,7 +258,7 @@ failure:
return NULL;
}
-static void
+static int
nfs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
{
int error;
@@ -271,7 +279,7 @@ nfs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
tmp.f_files = 0;
tmp.f_ffree = 0;
tmp.f_namelen = NAME_MAX;
- copy_to_user(buf, &tmp, bufsiz);
+ return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
}
/*
@@ -317,7 +325,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fhandle,
}
dprintk("NFS: fhget(%x/%ld ct=%d)\n",
inode->i_dev, inode->i_ino,
- atomic_read(&inode->i_count));
+ inode->i_count);
return inode;
}
@@ -364,7 +372,6 @@ nfs_notify_change(struct inode *inode, struct iattr *attr)
nfs_truncate_dirty_pages(inode, sattr.size);
nfs_refresh_inode(inode, &fattr);
}
- inode->i_dirt = 0;
return error;
}
@@ -435,7 +442,7 @@ done:
*/
static struct file_system_type nfs_fs_type = {
"nfs",
- FS_NO_DCACHE,
+ 0 /* FS_NO_DCACHE - this doesn't work right now*/,
nfs_read_super,
NULL
};
diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c
index add3309f3..51cca7c48 100644
--- a/fs/nfs/nfsroot.c
+++ b/fs/nfs/nfsroot.c
@@ -1,5 +1,5 @@
/*
- * $Id: nfsroot.c,v 1.37 1997/06/04 08:28:10 davem Exp $
+ * $Id: nfsroot.c,v 1.3 1997/06/17 13:26:56 ralf Exp $
*
* Copyright (C) 1995, 1996 Gero Kuhlmann <gero@gkminix.han.de>
*
@@ -78,7 +78,6 @@
#include <asm/param.h>
#include <linux/utsname.h>
-#include <linux/nametrans.h>
#include <linux/in.h>
#include <linux/if.h>
#include <linux/inet.h>
@@ -833,9 +832,6 @@ __initfunc(static void root_do_bootp_ext(u8 *ext))
root_bootp_string(nfs_path, ext+1, *ext, NFS_MAXPATHLEN);
break;
}
-#ifdef CONFIG_TRANS_NAMES
- translations_dirty = 1;
-#endif
}
@@ -1258,9 +1254,6 @@ __initfunc(static void root_nfs_addrs(char *addrs))
system_utsname.domainname[0] = '\0';
user_dev_name[0] = '\0';
bootp_flag = rarp_flag = 1;
-#ifdef CONFIG_TRANS_NAMES
- translations_dirty = 1;
-#endif
/* The following is just a shortcut for automatic IP configuration */
if (!strcmp(addrs, "bootp")) {
@@ -1306,9 +1299,6 @@ __initfunc(static void root_nfs_addrs(char *addrs))
}
strncpy(system_utsname.nodename, ip, __NEW_UTS_LEN);
system_utsname.nodename[__NEW_UTS_LEN] = '\0';
-#ifdef CONFIG_TRANS_NAMES
- translations_dirty = 1;
-#endif
break;
case 5:
strncpy(user_dev_name, ip, IFNAMSIZ);
@@ -1342,9 +1332,6 @@ __initfunc(static int root_nfs_setup(void))
if (!system_utsname.nodename[0]) {
strncpy(system_utsname.nodename, in_ntoa(myaddr), __NEW_UTS_LEN);
system_utsname.nodename[__NEW_UTS_LEN] = '\0';
-#ifdef CONFIG_TRANS_NAMES
- translations_dirty = 1;
-#endif
}
/* Set the correct netmask */
diff --git a/fs/nfs/read.c b/fs/nfs/read.c
index 2c3b59036..4ce61f731 100644
--- a/fs/nfs/read.c
+++ b/fs/nfs/read.c
@@ -150,7 +150,6 @@ nfs_readpage_result(struct rpc_task *task)
fail++;
dprintk("NFS: %d successful reads, %d failures\n", succ, fail);
}
- iput(req->ra_inode);
clear_bit(PG_locked, &page->flags);
wake_up(&page->wait);
@@ -188,7 +187,6 @@ nfs_readpage_async(struct inode *inode, struct page *page)
nfs_readpage_result, req);
if (result >= 0) {
- atomic_inc(&inode->i_count);
atomic_inc(&page->count);
return 0;
}
diff --git a/fs/nfs/symlink.c b/fs/nfs/symlink.c
index a22f96239..3d545f7d8 100644
--- a/fs/nfs/symlink.c
+++ b/fs/nfs/symlink.c
@@ -19,6 +19,7 @@
#include <asm/uaccess.h>
static int nfs_readlink(struct inode *, char *, int);
+static struct dentry *nfs_follow_link(struct inode *, struct dentry *);
/*
* symlinks can't do much...
@@ -35,6 +36,7 @@ struct inode_operations nfs_symlink_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
nfs_readlink, /* readlink */
+ nfs_follow_link, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
@@ -55,7 +57,6 @@ static int nfs_readlink(struct inode *inode, char *buffer, int buflen)
buflen = NFS_MAXPATHLEN;
error = nfs_proc_readlink(NFS_SERVER(inode), NFS_FH(inode), &mem,
&res, &len, buflen);
- iput(inode);
if (! error) {
copy_to_user(buffer, res, len);
put_user('\0', buffer + len);
@@ -64,3 +65,36 @@ static int nfs_readlink(struct inode *inode, char *buffer, int buflen)
kfree(mem);
return error;
}
+
+static struct dentry * nfs_follow_link(struct inode * inode, struct dentry *base)
+{
+ int error;
+ unsigned int len;
+ char *res;
+ void *mem;
+ char *path;
+
+ dfprintk(VFS, "nfs: follow_link(%x/%ld)\n", inode->i_dev, inode->i_ino);
+
+ error = nfs_proc_readlink(NFS_SERVER(inode), NFS_FH(inode), &mem,
+ &res, &len, NFS_MAXPATHLEN);
+
+ if (error) {
+ dput(base);
+ kfree(mem);
+ return ERR_PTR(error);
+ }
+ path = kmalloc(len + 1, GFP_KERNEL);
+ if (!path) {
+ dput(base);
+ kfree(mem);
+ return ERR_PTR(-ENOMEM);
+ }
+ memcpy(path, res, len);
+ path[len] = 0;
+ kfree(mem);
+
+ base = lookup_dentry(path, base, 1);
+ kfree(path);
+ return base;
+}
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index f27d083e4..9241c679e 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -338,7 +338,7 @@ create_write_request(struct inode *inode, struct page *page,
wreq->wb_page = page;
wreq->wb_offset = offset;
wreq->wb_bytes = bytes;
- atomic_inc(&inode->i_count);
+
atomic_inc(&page->count);
append_write_request(&NFS_WRITEBACK(inode), wreq);
@@ -695,7 +695,6 @@ nfs_check_error(struct inode *inode)
status = req->wb_task.tk_status;
remove_write_request(&nfs_failed_requests, req);
- iput(req->wb_inode);
kfree(req);
return status;
}
@@ -788,7 +787,6 @@ nfs_wback_result(struct rpc_task *task)
dprintk("NFS: %4d saving write failure code\n",
task->tk_pid);
append_write_request(&nfs_failed_requests, req);
- atomic_inc(&inode->i_count);
}
clear_bit(PG_uptodate, &page->flags);
} else if (!WB_CANCELLED(req)) {
@@ -818,6 +816,5 @@ nfs_wback_result(struct rpc_task *task)
kfree(req);
free_page(page_address(page));
- iput(inode);
nr_write_requests--;
}