patch-2.1.58 linux/fs/nfs/dir.c
Next file: linux/fs/nfs/inode.c
Previous file: linux/fs/namei.c
Back to the patch index
Back to the overall index
- Lines: 733
- Date:
Sun Oct 12 10:15:56 1997
- Orig file:
v2.1.57/linux/fs/nfs/dir.c
- Orig date:
Wed Sep 24 20:05:48 1997
diff -u --recursive --new-file v2.1.57/linux/fs/nfs/dir.c linux/fs/nfs/dir.c
@@ -29,6 +29,11 @@
#include <asm/segment.h> /* for fs functions */
+/* needed by smbfs as well ... move to dcache? */
+extern void nfs_renew_times(struct dentry *);
+extern void nfs_invalidate_dircache_sb(struct super_block *);
+#define NFS_PARANOIA 1
+
/*
* Head for a dircache entry. Currently still very simple; when
* the cache grows larger, we will need a LRU list.
@@ -36,14 +41,14 @@
struct nfs_dirent {
dev_t dev; /* device number */
ino_t ino; /* inode number */
- u32 cookie; /* cooke of first entry */
+ u32 cookie; /* cookie of first entry */
unsigned short valid : 1, /* data is valid */
locked : 1; /* entry locked */
unsigned int size; /* # of entries */
unsigned long age; /* last used */
unsigned long mtime; /* last attr stamp */
struct wait_queue * wait;
- struct nfs_entry * entry;
+ __u32 * entry; /* three __u32's per entry */
};
static int nfs_dir_open(struct inode * inode, struct file * file);
@@ -123,15 +128,16 @@
static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
+ struct inode *inode = filp->f_dentry->d_inode;
static struct wait_queue *readdir_wait = NULL;
struct wait_queue **waitp = NULL;
struct nfs_dirent *cache, *free;
- struct nfs_entry *entry;
unsigned long age, dead;
u32 cookie;
int ismydir, result;
int i, j, index = 0;
- struct inode *inode = filp->f_dentry->d_inode;
+ __u32 *entry;
+ char *name, *start;
dfprintk(VFS, "NFS: nfs_readdir(%x/%ld)\n", inode->i_dev, inode->i_ino);
if (!inode || !S_ISDIR(inode->i_mode)) {
@@ -194,17 +200,15 @@
break;
}
for (j = 0; j < cache->size; j++) {
- /*
- dprintk("NFS: examing entry %.*s @%d\n",
- (int) cache->entry[j].length,
- cache->entry[j].name,
- cache->entry[j].cookie);
- */
- if (cache->entry[j].cookie != cookie)
+ __u32 *this_ent = cache->entry + j*3;
+
+ if (*(this_ent+1) != cookie)
continue;
if (j < cache->size - 1) {
- entry = cache->entry + (index = j + 1);
- } else if (cache->entry[j].eof) {
+ index = j + 1;
+ entry = this_ent + 3;
+ } else if (*(this_ent+2) >> 16) {
+ /* eof */
return 0;
}
break;
@@ -235,12 +239,10 @@
cache->dev = inode->i_dev;
cache->ino = inode->i_ino;
if (!cache->entry) {
- cache->entry = (struct nfs_entry *)
- get_free_page(GFP_KERNEL);
- if (!cache->entry) {
- result = -ENOMEM;
+ result = -ENOMEM;
+ cache->entry = (__u32 *) get_free_page(GFP_KERNEL);
+ if (!cache->entry)
goto done;
- }
}
result = nfs_proc_readdir(NFS_SERVER(inode), NFS_FH(inode),
@@ -257,25 +259,29 @@
/*
* Yowza! We have a cache entry...
*/
+ start = (char *) cache->entry;
while (index < cache->size) {
- int nextpos = entry->cookie;
+ __u32 fileid = *entry++;
+ __u32 nextpos = *entry++; /* cookie */
+ __u32 length = *entry++;
/*
+ * Unpack the eof flag, offset, and length
+ */
+ result = length & (1 << 15); /* eof flag */
+ name = start + ((length >> 16) & 0xFFFF);
+ length &= 0x7FFF;
+ /*
dprintk("NFS: filldir(%p, %.*s, %d, %d, %x, eof %x)\n", entry,
- (int) entry->length, entry->name, entry->length,
+ (int) length, name, length,
(unsigned int) filp->f_pos,
- entry->fileid, entry->eof);
+ fileid, result);
*/
- if (filldir(dirent, entry->name, entry->length, cookie, entry->fileid) < 0)
+ if (filldir(dirent, name, length, cookie, fileid) < 0)
break;
cookie = nextpos;
- if (nextpos != entry->cookie) {
- printk("nfs_readdir: shouldn't happen!\n");
- break;
- }
index++;
- entry++;
}
filp->f_pos = cookie;
result = 0;
@@ -293,44 +299,73 @@
}
/*
- * Invalidate dircache entries for inode
+ * Invalidate dircache entries for an inode.
*/
void
nfs_invalidate_dircache(struct inode *inode)
{
- struct nfs_dirent *cache;
+ struct nfs_dirent *cache = dircache;
dev_t dev = inode->i_dev;
ino_t ino = inode->i_ino;
int i;
dfprintk(DIRCACHE, "NFS: invalidate dircache for %x/%ld\n", dev, (long)ino);
- for (i = 0, cache = dircache; i < NFS_MAX_DIRCACHE; i++, cache++) {
- if (!cache->locked && cache->dev == dev && cache->ino == ino)
- cache->valid = 0; /* brute force */
+ for (i = NFS_MAX_DIRCACHE; i--; cache++) {
+ if (cache->ino != ino)
+ continue;
+ if (cache->dev != dev)
+ continue;
+ if (cache->locked) {
+ printk("NFS: cache locked for %s/%ld\n",
+ kdevname(dev), ino);
+ continue;
+ }
+ cache->valid = 0; /* brute force */
}
}
/*
- * Free directory cache memory
- * Called from cleanup_module
+ * Invalidate the dircache for a super block (or all caches),
+ * and release the cache memory.
*/
void
-nfs_free_dircache(void)
+nfs_invalidate_dircache_sb(struct super_block *sb)
{
- struct nfs_dirent *cache;
+ struct nfs_dirent *cache = dircache;
int i;
+ int freed = 0;
- dfprintk(DIRCACHE, "NFS: freeing dircache\n");
- for (i = 0, cache = dircache; i < NFS_MAX_DIRCACHE; i++, cache++) {
- cache->valid = 0;
+ for (i = NFS_MAX_DIRCACHE; i--; cache++) {
+ if (sb && sb->s_dev != cache->dev)
+ continue;
if (cache->locked) {
- printk("nfs_kfree_cache: locked entry in dircache!\n");
+ printk("NFS: cache locked at umount %s\n",
+ (cache->entry ? "(lost a page!)" : ""));
continue;
}
- if (cache->entry)
+ cache->valid = 0; /* brute force */
+ if (cache->entry) {
free_page((unsigned long) cache->entry);
- cache->entry = NULL;
+ cache->entry = NULL;
+ freed++;
+ }
}
+#ifdef NFS_PARANOIA
+if (freed)
+printk("nfs_invalidate_dircache_sb: freed %d pages from %s\n",
+freed, kdevname(sb->s_dev));
+#endif
+}
+
+/*
+ * Free directory cache memory
+ * Called from cleanup_module
+ */
+void
+nfs_free_dircache(void)
+{
+ dfprintk(DIRCACHE, "NFS: freeing dircache\n");
+ nfs_invalidate_dircache_sb(NULL);
}
/*
@@ -350,20 +385,46 @@
unsigned long time = jiffies - dentry->d_time;
unsigned long max = 5*HZ;
- if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode))
- max = 10*HZ;
- return time < max;
+ if (dentry->d_inode) {
+ if (is_bad_inode(dentry->d_inode)) {
+#ifdef NFS_PARANOIA
+printk("nfs_lookup_validate: %s/%s has dud inode\n",
+dentry->d_parent->d_name.name, dentry->d_name.name);
+#endif
+ goto bad;
+ }
+ if (S_ISDIR(dentry->d_inode->i_mode))
+ max = 10*HZ;
+ }
+
+ return (time < max) || IS_ROOT(dentry);
+bad:
+ return 0;
}
static void nfs_silly_delete(struct dentry *);
static struct dentry_operations nfs_dentry_operations = {
- nfs_lookup_revalidate,
+ nfs_lookup_revalidate, /* d_validate(struct dentry *) */
0, /* d_hash */
0, /* d_compare */
- nfs_silly_delete,
+ nfs_silly_delete, /* d_delete(struct dentry *) */
};
+/*
+ * Whenever a lookup succeeds, we know the parent directories
+ * are all valid, so we want to update the dentry timestamps.
+ */
+void nfs_renew_times(struct dentry * dentry)
+{
+ for (;;) {
+ dentry->d_time = jiffies;
+ if (dentry == dentry->d_parent)
+ break;
+ dentry = dentry->d_parent;
+ }
+}
+
static int nfs_lookup(struct inode *dir, struct dentry * dentry)
{
struct inode *inode;
@@ -383,20 +444,42 @@
if (len > NFS_MAXNAMLEN)
return -ENAMETOOLONG;
- error = nfs_proc_lookup(NFS_SERVER(dir), NFS_FH(dir), dentry->d_name.name, &fhandle, &fattr);
-
+ error = nfs_proc_lookup(NFS_SERVER(dir), NFS_FH(dir),
+ dentry->d_name.name, &fhandle, &fattr);
inode = NULL;
+ if (error == -ENOENT)
+ goto no_entry;
if (!error) {
+ error = -EACCES;
inode = nfs_fhget(dir->i_sb, &fhandle, &fattr);
- if (!inode)
- return -EACCES;
- } else if (error != -ENOENT)
- return error;
-
- dentry->d_time = jiffies;
- dentry->d_op = &nfs_dentry_operations;
- d_add(dentry, inode);
- return 0;
+ if (inode) {
+ no_entry:
+ dentry->d_op = &nfs_dentry_operations;
+ d_add(dentry, inode);
+ nfs_renew_times(dentry);
+ error = 0;
+ }
+ }
+ return error;
+}
+
+/*
+ * Code common to create, mkdir, and mknod.
+ */
+static int nfs_instantiate(struct inode *dir, struct dentry *dentry,
+ struct nfs_fattr *fattr, struct nfs_fh *fhandle)
+{
+ struct inode *inode;
+ int error = -EACCES;
+
+ inode = nfs_fhget(dir->i_sb, fhandle, fattr);
+ if (inode) {
+ nfs_invalidate_dircache(dir);
+ d_instantiate(dentry, inode);
+ nfs_renew_times(dentry);
+ error = 0;
+ }
+ return error;
}
static int nfs_create(struct inode *dir, struct dentry * dentry, int mode)
@@ -404,7 +487,6 @@
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",
@@ -422,18 +504,10 @@
sattr.uid = sattr.gid = sattr.size = (unsigned) -1;
sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;
error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dir),
- dentry->d_name.name, &sattr, &fhandle, &fattr);
-
- if (error)
- return error;
-
- inode = nfs_fhget(dir->i_sb, &fhandle, &fattr);
- if (!inode)
- return -EACCES;
-
- nfs_invalidate_dircache(dir);
- d_instantiate(dentry, inode);
- return 0;
+ dentry->d_name.name, &sattr, &fhandle, &fattr);
+ if (!error)
+ error = nfs_instantiate(dir, dentry, &fattr, &fhandle);
+ return error;
}
static int nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rdev)
@@ -441,7 +515,6 @@
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",
@@ -462,18 +535,10 @@
sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;
error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dir),
- dentry->d_name.name, &sattr, &fhandle, &fattr);
-
- if (error)
- return error;
-
- inode = nfs_fhget(dir->i_sb, &fhandle, &fattr);
- if (!inode)
- return -EACCES;
-
- nfs_invalidate_dircache(dir);
- d_instantiate(dentry, inode);
- return 0;
+ dentry->d_name.name, &sattr, &fhandle, &fattr);
+ if (!error)
+ error = nfs_instantiate(dir, dentry, &fattr, &fhandle);
+ return error;
}
static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
@@ -481,7 +546,6 @@
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",
@@ -500,20 +564,16 @@
sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;
error = nfs_proc_mkdir(NFS_SERVER(dir), NFS_FH(dir),
- dentry->d_name.name, &sattr, &fhandle, &fattr);
-
- if (error)
- return error;
-
- inode = nfs_fhget(dir->i_sb, &fhandle, &fattr);
- if (!inode)
- return -EACCES;
-
- nfs_invalidate_dircache(dir);
- d_instantiate(dentry, inode);
- return 0;
+ dentry->d_name.name, &sattr, &fhandle, &fattr);
+ if (!error)
+ error = nfs_instantiate(dir, dentry, &fattr, &fhandle);
+ return error;
}
+/*
+ * Update inode->i_nlink immediately after a successful operation.
+ * (See comments for nfs_unlink.)
+ */
static int nfs_rmdir(struct inode *dir, struct dentry *dentry)
{
int error;
@@ -530,12 +590,14 @@
return -ENAMETOOLONG;
error = nfs_proc_rmdir(NFS_SERVER(dir), NFS_FH(dir), dentry->d_name.name);
- if (error)
- return error;
-
- nfs_invalidate_dircache(dir);
- d_delete(dentry);
- return 0;
+ if (!error) {
+ if (dentry->d_inode->i_nlink)
+ dentry->d_inode->i_nlink --;
+ nfs_invalidate_dircache(dir);
+ nfs_renew_times(dentry);
+ d_delete(dentry);
+ }
+ return error;
}
@@ -642,16 +704,15 @@
error = nfs_proc_rename(NFS_SERVER(dir),
NFS_FH(dir), dentry->d_name.name,
NFS_FH(dir), silly);
- if (error) {
- dput(sdentry);
- return error;
+ if (!error) {
+ nfs_invalidate_dircache(dir);
+ nfs_renew_times(dentry);
+ d_move(dentry, sdentry);
+ dentry->d_flags |= DCACHE_NFSFS_RENAMED;
+ /* If we return 0 we don't unlink */
}
- nfs_invalidate_dircache(dir);
- d_move(dentry, sdentry);
dput(sdentry);
- dentry->d_flags |= DCACHE_NFSFS_RENAMED;
-
- return 0; /* don't unlink */
+ return error;
}
static void nfs_silly_delete(struct dentry *dentry)
@@ -670,8 +731,18 @@
if (error < 0)
printk("NFS " __FUNCTION__ " failed (err = %d)\n",
-error);
- dentry->d_inode->i_nlink --;
+ if (dentry->d_inode) {
+ if (dentry->d_inode->i_nlink)
+ dentry->d_inode->i_nlink --;
+ } else
+ printk("nfs_silly_delete: negative dentry %s/%s\n",
+ dentry->d_parent->d_name.name,
+ dentry->d_name.name);
nfs_invalidate_dircache(dir);
+ /*
+ * The dentry is unhashed, but we want to make it negative.
+ */
+ d_delete(dentry);
}
}
@@ -680,8 +751,11 @@
*
* If sillyrename() returns 0, we do nothing, otherwise we unlink.
*
- * inode->i_nlink is updated here rather than waiting for the next
- * nfs_refresh_inode() for cosmetic reasons only.
+ * Updating inode->i_nlink here rather than waiting for the next
+ * nfs_refresh_inode() is not merely cosmetic; once an object has
+ * been deleted, we want to get rid of the inode locally. The NFS
+ * server may reuse the fileid for a new inode, and we don't want
+ * that to be confused with this inode.
*/
static int nfs_unlink(struct inode *dir, struct dentry *dentry)
{
@@ -700,20 +774,19 @@
error = nfs_sillyrename(dir, dentry);
- if (error == -EBUSY) {
- return -EBUSY;
- } else if (error < 0) {
+ if (error && error != -EBUSY) {
error = nfs_proc_remove(NFS_SERVER(dir),
NFS_FH(dir), dentry->d_name.name);
- if (error < 0)
- return error;
-
- dentry->d_inode->i_nlink --;
- nfs_invalidate_dircache(dir);
- d_delete(dentry);
+ if (!error) {
+ if (dentry->d_inode->i_nlink)
+ dentry->d_inode->i_nlink --;
+ nfs_invalidate_dircache(dir);
+ nfs_renew_times(dentry);
+ d_delete(dentry);
+ }
}
- return 0;
+ return error;
}
static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
@@ -740,22 +813,21 @@
sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;
error = nfs_proc_symlink(NFS_SERVER(dir), NFS_FH(dir),
- dentry->d_name.name, symname, &sattr);
-
- if (error)
- return error;
-
- nfs_invalidate_dircache(dir);
- /* this looks _funny_ doesn't it? But: nfs_proc_symlink()
- * only fills in sattr, not fattr. Thus nfs_fhget() cannot be
- * called, it would be pointless, without a valid fattr
- * argument. Other possibility: call nfs_proc_lookup()
- * HERE. But why? If somebody wants to reference this
- * symlink, the cached_lookup() will fail, and
- * nfs_proc_symlink() will be called anyway.
- */
- d_drop(dentry);
- return 0;
+ dentry->d_name.name, symname, &sattr);
+ if (!error) {
+ nfs_invalidate_dircache(dir);
+ nfs_renew_times(dentry->d_parent);
+ /* this looks _funny_ doesn't it? But: nfs_proc_symlink()
+ * only fills in sattr, not fattr. Thus nfs_fhget() cannot be
+ * called, it would be pointless, without a valid fattr
+ * argument. Other possibility: call nfs_proc_lookup()
+ * HERE. But why? If somebody wants to reference this
+ * symlink, the cached_lookup() will fail, and
+ * nfs_proc_symlink() will be called anyway.
+ */
+ d_drop(dentry);
+ }
+ return error;
}
static int nfs_link(struct inode *inode, struct inode *dir, struct dentry *dentry)
@@ -774,17 +846,16 @@
if (dentry->d_name.len > NFS_MAXNAMLEN)
return -ENAMETOOLONG;
- error = nfs_proc_link(NFS_SERVER(inode), NFS_FH(inode),
- NFS_FH(dir), dentry->d_name.name);
-
- if (error)
- return error;
-
- nfs_invalidate_dircache(dir);
- inode->i_count ++;
- inode->i_nlink ++; /* no need to wait for nfs_refresh_inode() */
- d_instantiate(dentry, inode);
- return 0;
+ error = nfs_proc_link(NFS_SERVER(inode), NFS_FH(inode), NFS_FH(dir),
+ dentry->d_name.name);
+ if (!error) {
+ nfs_invalidate_dircache(dir);
+ inode->i_count ++;
+ inode->i_nlink ++; /* no need to wait for nfs_refresh_inode() */
+ d_instantiate(dentry, inode);
+ error = 0;
+ }
+ return error;
}
/*
@@ -843,15 +914,19 @@
error = nfs_proc_rename(NFS_SERVER(old_dir),
NFS_FH(old_dir), old_dentry->d_name.name,
NFS_FH(new_dir), new_dentry->d_name.name);
- if (error)
- return error;
-
- nfs_invalidate_dircache(old_dir);
- nfs_invalidate_dircache(new_dir);
+ if (!error) {
+ nfs_invalidate_dircache(old_dir);
+ nfs_invalidate_dircache(new_dir);
+ /*
+ * We know these paths are still valid ...
+ */
+ nfs_renew_times(old_dentry);
+ nfs_renew_times(new_dentry->d_parent);
- /* Update the dcache */
- d_move(old_dentry, new_dentry);
- return 0;
+ /* Update the dcache */
+ d_move(old_dentry, new_dentry);
+ }
+ return error;
}
/*
@@ -860,23 +935,68 @@
* of the server's inode.
*/
-void nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
+int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
{
- int was_empty;
+ int error = -EIO;
dfprintk(VFS, "NFS: refresh_inode(%x/%ld ct=%d)\n",
inode->i_dev, inode->i_ino, inode->i_count);
if (!inode || !fattr) {
printk("nfs_refresh_inode: inode or fattr is NULL\n");
- return;
+ goto out;
}
if (inode->i_ino != fattr->fileid) {
printk("nfs_refresh_inode: inode number mismatch\n");
- return;
+ goto out;
}
- was_empty = (inode->i_mode == 0);
- inode->i_mode = fattr->mode;
+ /*
+ * Check whether the mode has been set, as we only want to
+ * do this once. (We don't allow inodes to change types.)
+ */
+ if (inode->i_mode == 0) {
+ inode->i_mode = fattr->mode;
+ if (S_ISREG(inode->i_mode))
+ inode->i_op = &nfs_file_inode_operations;
+ else if (S_ISDIR(inode->i_mode))
+ inode->i_op = &nfs_dir_inode_operations;
+ else if (S_ISLNK(inode->i_mode))
+ inode->i_op = &nfs_symlink_inode_operations;
+ else if (S_ISCHR(inode->i_mode)) {
+ inode->i_op = &chrdev_inode_operations;
+ inode->i_rdev = to_kdev_t(fattr->rdev);
+ } else if (S_ISBLK(inode->i_mode)) {
+ inode->i_op = &blkdev_inode_operations;
+ inode->i_rdev = to_kdev_t(fattr->rdev);
+ } else if (S_ISFIFO(inode->i_mode))
+ init_fifo(inode);
+ else
+ inode->i_op = NULL;
+ } else if ((inode->i_mode & S_IFMT) == (fattr->mode & S_IFMT)) {
+ inode->i_mode = fattr->mode;
+ } else {
+ mode_t old_mode;
+ /*
+ * Big trouble! The inode has become a different object.
+ */
+#if 1
+printk("nfs_refresh_inode: mode changed, %07o to %07o\n",
+inode->i_mode, fattr->mode);
+#endif
+ old_mode = inode->i_mode; /* save mode */
+ make_bad_inode(inode);
+ inode->i_mode = old_mode; /* restore mode */
+ inode->i_nlink = 0;
+ /*
+ * No need to worry about unhashing the dentry, as the
+ * lookup validation will know that the inode is bad.
+ * (But we do want to invalidate the caches.)
+ */
+ invalidate_inode_pages(inode);
+ nfs_invalidate_dircache(inode);
+ goto out;
+ }
+
inode->i_nlink = fattr->nlink;
inode->i_uid = fattr->uid;
inode->i_gid = fattr->gid;
@@ -893,29 +1013,13 @@
NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
}
inode->i_size = fattr->size;
- if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
- inode->i_rdev = to_kdev_t(fattr->rdev);
- else
- inode->i_rdev = 0;
inode->i_blocks = fattr->blocks;
inode->i_atime = fattr->atime.seconds;
inode->i_mtime = fattr->mtime.seconds;
inode->i_ctime = fattr->ctime.seconds;
- if (S_ISREG(inode->i_mode))
- inode->i_op = &nfs_file_inode_operations;
- else if (S_ISDIR(inode->i_mode))
- inode->i_op = &nfs_dir_inode_operations;
- else if (S_ISLNK(inode->i_mode))
- inode->i_op = &nfs_symlink_inode_operations;
- else if (S_ISCHR(inode->i_mode))
- inode->i_op = &chrdev_inode_operations;
- else if (S_ISBLK(inode->i_mode))
- inode->i_op = &blkdev_inode_operations;
- else if (S_ISFIFO(inode->i_mode)) {
- if (was_empty)
- init_fifo(inode);
- } else
- inode->i_op = NULL;
+ error = 0;
+out:
+ return error;
}
/*
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov