inode.c 22.5 KB
Newer Older
1 2 3 4 5 6
/*
 *  linux/fs/nfs/inode.c
 *
 *  Copyright (C) 1992  Rick Sladkey
 *
 *  nfs inode and superblock handling functions
Linus Torvalds's avatar
Linus Torvalds committed
7 8 9
 *
 *  Modularised by Alan Cox <Alan.Cox@linux.org>, while hacking some
 *  experimental NFS changes. Modularisation taken straight from SYS5 fs.
Linus Torvalds's avatar
Linus Torvalds committed
10 11 12 13
 *
 *  Change to nfs_read_super() to permit NFS mounts to multi-homed hosts.
 *  J.S.Peatfield@damtp.cam.ac.uk
 *
14 15
 */

Linus Torvalds's avatar
Linus Torvalds committed
16
#include <linux/config.h>
Linus Torvalds's avatar
Linus Torvalds committed
17
#include <linux/module.h>
Linus Torvalds's avatar
Linus Torvalds committed
18

19 20 21 22 23 24 25
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/stat.h>
#include <linux/errno.h>
#include <linux/locks.h>
Linus Torvalds's avatar
Linus Torvalds committed
26 27
#include <linux/unistd.h>
#include <linux/sunrpc/clnt.h>
Linus Torvalds's avatar
Linus Torvalds committed
28
#include <linux/sunrpc/stats.h>
Linus Torvalds's avatar
Linus Torvalds committed
29 30
#include <linux/nfs_fs.h>
#include <linux/lockd/bind.h>
31

Linus Torvalds's avatar
Linus Torvalds committed
32
#include <asm/system.h>
Linus Torvalds's avatar
Linus Torvalds committed
33
#include <asm/uaccess.h>
Linus Torvalds's avatar
Linus Torvalds committed
34

Linus Torvalds's avatar
Linus Torvalds committed
35
#define CONFIG_NFS_SNAPSHOT 1
Linus Torvalds's avatar
Linus Torvalds committed
36
#define NFSDBG_FACILITY		NFSDBG_VFS
Linus Torvalds's avatar
Linus Torvalds committed
37
#define NFS_PARANOIA 1
38

Linus Torvalds's avatar
Linus Torvalds committed
39 40
static struct inode * __nfs_fhget(struct super_block *, struct nfs_fattr *);

Linus Torvalds's avatar
Linus Torvalds committed
41
static void nfs_read_inode(struct inode *);
42
static void nfs_put_inode(struct inode *);
Linus Torvalds's avatar
Linus Torvalds committed
43
static void nfs_delete_inode(struct inode *);
Linus Torvalds's avatar
Linus Torvalds committed
44
static int  nfs_notify_change(struct dentry *, struct iattr *);
45
static void nfs_put_super(struct super_block *);
Linus Torvalds's avatar
Linus Torvalds committed
46
static void nfs_umount_begin(struct super_block *);
Linus Torvalds's avatar
Linus Torvalds committed
47
static int  nfs_statfs(struct super_block *, struct statfs *, int);
48

Linus Torvalds's avatar
Linus Torvalds committed
49
static struct super_operations nfs_sops = { 
Linus Torvalds's avatar
Linus Torvalds committed
50
	nfs_read_inode,		/* read inode */
51
	NULL,			/* write inode */
52
	nfs_put_inode,		/* put inode */
Linus Torvalds's avatar
Linus Torvalds committed
53 54
	nfs_delete_inode,	/* delete inode */
	nfs_notify_change,	/* notify change */
55 56
	nfs_put_super,		/* put superblock */
	NULL,			/* write superblock */
57
	nfs_statfs,		/* stat filesystem */
Linus Torvalds's avatar
Linus Torvalds committed
58 59 60
	NULL,			/* no remount */
	NULL,			/* no clear inode */
	nfs_umount_begin	/* umount attempt begin */
61 62
};

Linus Torvalds's avatar
Linus Torvalds committed
63
struct rpc_stat			nfs_rpcstat = { &nfs_program };
Linus Torvalds's avatar
Linus Torvalds committed
64

Linus Torvalds's avatar
Linus Torvalds committed
65 66 67
/*
 * The "read_inode" function doesn't actually do anything:
 * the real data is filled in later in nfs_fhget. Here we
Linus Torvalds's avatar
Linus Torvalds committed
68
 * just mark the cache times invalid, and zero out i_mode
Linus Torvalds's avatar
Linus Torvalds committed
69 70
 * (the latter makes "nfs_refresh_inode" do the right thing
 * wrt pipe inodes)
Linus Torvalds's avatar
Linus Torvalds committed
71
 */
Linus Torvalds's avatar
Linus Torvalds committed
72 73
static void
nfs_read_inode(struct inode * inode)
Linus Torvalds's avatar
Linus Torvalds committed
74
{
Linus Torvalds's avatar
Linus Torvalds committed
75
	inode->i_blksize = inode->i_sb->s_blocksize;
Linus Torvalds's avatar
Linus Torvalds committed
76
	inode->i_mode = 0;
Linus Torvalds's avatar
Linus Torvalds committed
77
	inode->i_rdev = 0;
Linus Torvalds's avatar
Linus Torvalds committed
78
	inode->i_op = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
79
	NFS_CACHEINV(inode);
Linus Torvalds's avatar
Linus Torvalds committed
80
	NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
Linus Torvalds's avatar
Linus Torvalds committed
81 82
}

Linus Torvalds's avatar
Linus Torvalds committed
83 84
static void
nfs_put_inode(struct inode * inode)
85
{
Linus Torvalds's avatar
Linus Torvalds committed
86
	dprintk("NFS: put_inode(%x/%ld)\n", inode->i_dev, inode->i_ino);
Linus Torvalds's avatar
Linus Torvalds committed
87 88 89 90 91
	/*
	 * We want to get rid of unused inodes ...
	 */
	if (inode->i_count == 1)
		inode->i_nlink = 0;
Linus Torvalds's avatar
Linus Torvalds committed
92
}
Linus Torvalds's avatar
Linus Torvalds committed
93

Linus Torvalds's avatar
Linus Torvalds committed
94 95 96
static void
nfs_delete_inode(struct inode * inode)
{
Linus Torvalds's avatar
Linus Torvalds committed
97 98
	int failed;

Linus Torvalds's avatar
Linus Torvalds committed
99
	dprintk("NFS: delete_inode(%x/%ld)\n", inode->i_dev, inode->i_ino);
Linus Torvalds's avatar
Linus Torvalds committed
100 101 102 103 104
	/*
	 * Flush out any pending write requests ...
	 */
	if (NFS_WRITEBACK(inode) != NULL) {
		unsigned long timeout = jiffies + 5*HZ;
Linus Torvalds's avatar
Linus Torvalds committed
105 106 107
#ifdef NFS_DEBUG_VERBOSE
printk("nfs_delete_inode: inode %ld has pending RPC requests\n", inode->i_ino);
#endif
Linus Torvalds's avatar
Linus Torvalds committed
108
		nfs_inval(inode);
109 110
		while (NFS_WRITEBACK(inode) != NULL &&
		       time_before(jiffies, timeout)) {
Linus Torvalds's avatar
Linus Torvalds committed
111
			current->state = TASK_INTERRUPTIBLE;
112
			schedule_timeout(HZ/10);
Linus Torvalds's avatar
Linus Torvalds committed
113 114 115 116 117 118
		}
		current->state = TASK_RUNNING;
		if (NFS_WRITEBACK(inode) != NULL)
			printk("NFS: Arghhh, stuck RPC requests!\n");
	}

Linus Torvalds's avatar
Linus Torvalds committed
119
	failed = nfs_check_failed_request(inode);
Linus Torvalds's avatar
Linus Torvalds committed
120 121 122
	if (failed)
		printk("NFS: inode %ld had %d failed requests\n",
			inode->i_ino, failed);
Linus Torvalds's avatar
Linus Torvalds committed
123
	clear_inode(inode);
124 125
}

Linus Torvalds's avatar
Linus Torvalds committed
126 127
void
nfs_put_super(struct super_block *sb)
128
{
Linus Torvalds's avatar
Linus Torvalds committed
129
	struct nfs_server *server = &sb->u.nfs_sb.s_server;
Linus Torvalds's avatar
Linus Torvalds committed
130 131
	struct rpc_clnt	*rpc;

Linus Torvalds's avatar
Linus Torvalds committed
132
	if ((rpc = server->client) != NULL)
Linus Torvalds's avatar
Linus Torvalds committed
133 134
		rpc_shutdown_client(rpc);

Linus Torvalds's avatar
Linus Torvalds committed
135 136
	if (!(server->flags & NFS_MOUNT_NONLM))
		lockd_down();	/* release rpc.lockd */
Linus Torvalds's avatar
Linus Torvalds committed
137
	rpciod_down();		/* release rpciod */
Linus Torvalds's avatar
Linus Torvalds committed
138 139 140 141 142
	/*
	 * Invalidate the dircache for this superblock.
	 */
	nfs_invalidate_dircache_sb(sb);

Linus Torvalds's avatar
Linus Torvalds committed
143
	kfree(server->hostname);
Linus Torvalds's avatar
Linus Torvalds committed
144

Linus Torvalds's avatar
Linus Torvalds committed
145
	MOD_DEC_USE_COUNT;
146 147
}

Linus Torvalds's avatar
Linus Torvalds committed
148 149 150 151 152 153 154 155 156 157 158
void
nfs_umount_begin(struct super_block *sb)
{
	struct nfs_server *server = &sb->u.nfs_sb.s_server;
	struct rpc_clnt	*rpc;

	/* -EIO all pending I/O */
	if ((rpc = server->client) != NULL)
		rpc_killall_tasks(rpc);
}

159
/*
Linus Torvalds's avatar
Linus Torvalds committed
160
 * Compute and set NFS server blocksize
161
 */
Linus Torvalds's avatar
Linus Torvalds committed
162 163
static unsigned int
nfs_block_size(unsigned int bsize, unsigned char *nrbitsp)
164
{
Linus Torvalds's avatar
Linus Torvalds committed
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
	if (bsize < 1024)
		bsize = NFS_DEF_FILE_IO_BUFFER_SIZE;
	else if (bsize >= NFS_MAX_FILE_IO_BUFFER_SIZE)
		bsize = NFS_MAX_FILE_IO_BUFFER_SIZE;

	/* make sure blocksize is a power of two */
	if ((bsize & (bsize - 1)) || nrbitsp) {
		unsigned int	nrbits;

		for (nrbits = 31; nrbits && !(bsize & (1 << nrbits)); nrbits--)
			;
		bsize = 1 << nrbits;
		if (nrbitsp)
			*nrbitsp = nrbits;
		if (bsize < NFS_DEF_FILE_IO_BUFFER_SIZE)
			bsize = NFS_DEF_FILE_IO_BUFFER_SIZE;
	}
Linus Torvalds's avatar
Linus Torvalds committed
182

Linus Torvalds's avatar
Linus Torvalds committed
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
	return bsize;
}

/*
 * The way this works is that the mount process passes a structure
 * in the data argument which contains the server's IP address
 * and the root file handle obtained from the server's mount
 * daemon. We stash these away in the private superblock fields.
 */
struct super_block *
nfs_read_super(struct super_block *sb, void *raw_data, int silent)
{
	struct nfs_mount_data	*data = (struct nfs_mount_data *) raw_data;
	struct nfs_server	*server;
	struct rpc_xprt		*xprt;
	struct rpc_clnt		*clnt;
Linus Torvalds's avatar
Linus Torvalds committed
199 200
	struct nfs_fh		*root_fh;
	struct inode		*root_inode;
Linus Torvalds's avatar
Linus Torvalds committed
201 202
	unsigned int		authflavor;
	int			tcp;
Linus Torvalds's avatar
Linus Torvalds committed
203 204
	struct sockaddr_in	srvaddr;
	struct rpc_timeout	timeparms;
Linus Torvalds's avatar
Linus Torvalds committed
205
	struct nfs_fattr	fattr;
206

Linus Torvalds's avatar
Linus Torvalds committed
207
	MOD_INC_USE_COUNT;
Linus Torvalds's avatar
Linus Torvalds committed
208 209 210
	if (!data)
		goto out_miss_args;

211 212 213
	if (data->version != NFS_MOUNT_VERSION) {
		printk("nfs warning: mount version %s than kernel\n",
			data->version < NFS_MOUNT_VERSION ? "older" : "newer");
Linus Torvalds's avatar
Linus Torvalds committed
214 215 216 217
		if (data->version < 2)
			data->namlen = 0;
		if (data->version < 3)
			data->bsize  = 0;
218
	}
Linus Torvalds's avatar
Linus Torvalds committed
219

Linus Torvalds's avatar
Linus Torvalds committed
220 221 222 223 224
	/* We now require that the mount process passes the remote address */
	memcpy(&srvaddr, &data->addr, sizeof(srvaddr));
	if (srvaddr.sin_addr.s_addr == INADDR_ANY)
		goto out_no_remote;

225
	lock_super(sb);
Linus Torvalds's avatar
Linus Torvalds committed
226

Linus Torvalds's avatar
Linus Torvalds committed
227 228 229
	sb->s_magic      = NFS_SUPER_MAGIC;
	sb->s_op         = &nfs_sops;
	sb->s_blocksize  = nfs_block_size(data->bsize, &sb->s_blocksize_bits);
Linus Torvalds's avatar
Linus Torvalds committed
230 231
	sb->u.nfs_sb.s_root = data->root;
	server           = &sb->u.nfs_sb.s_server;
Linus Torvalds's avatar
Linus Torvalds committed
232 233 234
	server->rsize    = nfs_block_size(data->rsize, NULL);
	server->wsize    = nfs_block_size(data->wsize, NULL);
	server->flags    = data->flags;
235 236 237 238
	server->acregmin = data->acregmin*HZ;
	server->acregmax = data->acregmax*HZ;
	server->acdirmin = data->acdirmin*HZ;
	server->acdirmax = data->acdirmax*HZ;
Linus Torvalds's avatar
Linus Torvalds committed
239 240 241 242

	server->hostname = kmalloc(strlen(data->hostname) + 1, GFP_KERNEL);
	if (!server->hostname)
		goto out_unlock;
243
	strcpy(server->hostname, data->hostname);
Linus Torvalds's avatar
Linus Torvalds committed
244 245 246 247 248 249 250 251 252 253 254 255 256

	/* Which protocol do we use? */
	tcp   = (data->flags & NFS_MOUNT_TCP);

	/* Initialize timeout values */
	timeparms.to_initval = data->timeo * HZ / 10;
	timeparms.to_retries = data->retrans;
	timeparms.to_maxval  = tcp? RPC_MAX_TCP_TIMEOUT : RPC_MAX_UDP_TIMEOUT;
	timeparms.to_exponential = 1;

	/* Now create transport and client */
	xprt = xprt_create_proto(tcp? IPPROTO_TCP : IPPROTO_UDP,
						&srvaddr, &timeparms);
Linus Torvalds's avatar
Linus Torvalds committed
257 258
	if (xprt == NULL)
		goto out_no_xprt;
Linus Torvalds's avatar
Linus Torvalds committed
259

Linus Torvalds's avatar
Linus Torvalds committed
260 261 262 263 264 265 266
	/* Choose authentication flavor */
	authflavor = RPC_AUTH_UNIX;
	if (data->flags & NFS_MOUNT_SECURE)
		authflavor = RPC_AUTH_DES;
	else if (data->flags & NFS_MOUNT_KERBEROS)
		authflavor = RPC_AUTH_KRB;

Linus Torvalds's avatar
Linus Torvalds committed
267 268
	clnt = rpc_create_client(xprt, server->hostname, &nfs_program,
						NFS_VERSION, authflavor);
Linus Torvalds's avatar
Linus Torvalds committed
269 270
	if (clnt == NULL)
		goto out_no_client;
Linus Torvalds's avatar
Linus Torvalds committed
271 272 273 274 275 276 277

	clnt->cl_intr     = (data->flags & NFS_MOUNT_INTR)? 1 : 0;
	clnt->cl_softrtry = (data->flags & NFS_MOUNT_SOFT)? 1 : 0;
	clnt->cl_chatty   = 1;
	server->client    = clnt;

	/* Fire up rpciod if not yet running */
Linus Torvalds's avatar
Linus Torvalds committed
278
	if (rpciod_up() != 0)
Linus Torvalds's avatar
Linus Torvalds committed
279 280 281 282 283 284
		goto out_no_iod;

	/*
	 * Keep the super block locked while we try to get 
	 * the root fh attributes.
	 */
Linus Torvalds's avatar
Linus Torvalds committed
285 286 287 288 289
	root_fh = kmalloc(sizeof(struct nfs_fh), GFP_KERNEL);
	if (!root_fh)
		goto out_no_fh;
	*root_fh = data->root;

Linus Torvalds's avatar
Linus Torvalds committed
290 291 292 293
	if (nfs_proc_getattr(server, root_fh, &fattr) != 0)
		goto out_no_fattr;

	root_inode = __nfs_fhget(sb, &fattr);
Linus Torvalds's avatar
Linus Torvalds committed
294 295 296 297 298
	if (!root_inode)
		goto out_no_root;
	sb->s_root = d_alloc_root(root_inode, NULL);
	if (!sb->s_root)
		goto out_no_root;
Linus Torvalds's avatar
Linus Torvalds committed
299 300 301
	sb->s_root->d_op = &nfs_dentry_operations;
	sb->s_root->d_fsdata = root_fh;

Linus Torvalds's avatar
Linus Torvalds committed
302
	/* We're airborne */
303
	unlock_super(sb);
Linus Torvalds's avatar
Linus Torvalds committed
304

Linus Torvalds's avatar
Linus Torvalds committed
305 306 307 308
	/* Check whether to start the lockd process */
	if (!(server->flags & NFS_MOUNT_NONLM))
		lockd_up();
	return sb;
Linus Torvalds's avatar
Linus Torvalds committed
309 310

	/* Yargs. It didn't work out. */
Linus Torvalds's avatar
Linus Torvalds committed
311
out_no_root:
Linus Torvalds's avatar
Linus Torvalds committed
312
	printk("nfs_read_super: get root inode failed\n");
Linus Torvalds's avatar
Linus Torvalds committed
313
	iput(root_inode);
Linus Torvalds's avatar
Linus Torvalds committed
314 315 316 317 318
	goto out_free_fh;

out_no_fattr:
	printk("nfs_read_super: get root fattr failed\n");
out_free_fh:
Linus Torvalds's avatar
Linus Torvalds committed
319 320
	kfree(root_fh);
out_no_fh:
Linus Torvalds's avatar
Linus Torvalds committed
321
	rpciod_down();
Linus Torvalds's avatar
Linus Torvalds committed
322
	goto out_shutdown;
Linus Torvalds's avatar
Linus Torvalds committed
323

Linus Torvalds's avatar
Linus Torvalds committed
324
out_no_iod:
Linus Torvalds's avatar
Linus Torvalds committed
325
	printk(KERN_WARNING "NFS: couldn't start rpciod!\n");
Linus Torvalds's avatar
Linus Torvalds committed
326 327
out_shutdown:
	rpc_shutdown_client(server->client);
Linus Torvalds's avatar
Linus Torvalds committed
328
	goto out_free_host;
Linus Torvalds's avatar
Linus Torvalds committed
329 330

out_no_client:
Linus Torvalds's avatar
Linus Torvalds committed
331
	printk(KERN_WARNING "NFS: cannot create RPC client.\n");
Linus Torvalds's avatar
Linus Torvalds committed
332
	xprt_destroy(xprt);
Linus Torvalds's avatar
Linus Torvalds committed
333
	goto out_free_host;
Linus Torvalds's avatar
Linus Torvalds committed
334 335

out_no_xprt:
Linus Torvalds's avatar
Linus Torvalds committed
336 337 338
	printk(KERN_WARNING "NFS: cannot create RPC transport.\n");

out_free_host:
Linus Torvalds's avatar
Linus Torvalds committed
339
	kfree(server->hostname);
Linus Torvalds's avatar
Linus Torvalds committed
340 341 342 343 344 345 346 347 348 349 350 351
out_unlock:
	unlock_super(sb);
	goto out_fail;

out_no_remote:
	printk("NFS: mount program didn't pass remote address!\n");
	goto out_fail;

out_miss_args:
	printk("nfs_read_super: missing data argument\n");

out_fail:
Linus Torvalds's avatar
Linus Torvalds committed
352
	sb->s_dev = 0;
Linus Torvalds's avatar
Linus Torvalds committed
353
	MOD_DEC_USE_COUNT;
Linus Torvalds's avatar
Linus Torvalds committed
354
	return NULL;
355 356
}

Linus Torvalds's avatar
Linus Torvalds committed
357
static int
Linus Torvalds's avatar
Linus Torvalds committed
358
nfs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
359 360 361
{
	int error;
	struct nfs_fsinfo res;
Linus Torvalds's avatar
Linus Torvalds committed
362
	struct statfs tmp;
363 364 365 366

	error = nfs_proc_statfs(&sb->u.nfs_sb.s_server, &sb->u.nfs_sb.s_root,
		&res);
	if (error) {
367
		printk("nfs_statfs: statfs error = %d\n", -error);
368 369
		res.bsize = res.blocks = res.bfree = res.bavail = 0;
	}
Linus Torvalds's avatar
Linus Torvalds committed
370 371 372 373 374 375 376 377
	tmp.f_type = NFS_SUPER_MAGIC;
	tmp.f_bsize = res.bsize;
	tmp.f_blocks = res.blocks;
	tmp.f_bfree = res.bfree;
	tmp.f_bavail = res.bavail;
	tmp.f_files = 0;
	tmp.f_ffree = 0;
	tmp.f_namelen = NAME_MAX;
Linus Torvalds's avatar
Linus Torvalds committed
378
	return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
379 380
}

Linus Torvalds's avatar
Linus Torvalds committed
381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397
/*
 * Free all unused dentries in an inode's alias list.
 *
 * Subtle note: we have to be very careful not to cause
 * any IO operations with the stale dentries, as this
 * could cause file corruption. But since the dentry
 * count is 0 and all pending IO for a dentry has been
 * flushed when the count went to 0, we're safe here.
 */
void nfs_free_dentries(struct inode *inode)
{
	struct list_head *tmp, *head = &inode->i_dentry;

restart:
	tmp = head;
	while ((tmp = tmp->next) != head) {
		struct dentry *dentry = list_entry(tmp, struct dentry, d_alias);
Linus Torvalds's avatar
Linus Torvalds committed
398 399 400
printk("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));
Linus Torvalds's avatar
Linus Torvalds committed
401 402 403 404 405 406 407 408 409
		if (!dentry->d_count) {
			dget(dentry);
			d_drop(dentry);
			dput(dentry);
			goto restart;
		}
	}
}

Linus Torvalds's avatar
Linus Torvalds committed
410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448
/*
 * Fill in inode information from the fattr.
 */
static void
nfs_fill_inode(struct inode *inode, struct nfs_fattr *fattr)
{
	/*
	 * 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;
		/*
		 * Preset the size and mtime, as there's no need
		 * to invalidate the caches.
		 */ 
		inode->i_size  = fattr->size;
		inode->i_mtime = fattr->mtime.seconds;
		NFS_OLDMTIME(inode) = fattr->mtime.seconds;
	}
	nfs_refresh_inode(inode, fattr);
}

449 450 451 452 453
/*
 * This is our own version of iget that looks up inodes by file handle
 * instead of inode number.  We use this technique instead of using
 * the vfs read_inode function because there is no way to pass the
 * file handle or current attributes into the read_inode function.
Linus Torvalds's avatar
Linus Torvalds committed
454
 *
Linus Torvalds's avatar
Linus Torvalds committed
455 456 457 458 459 460 461 462 463 464 465 466 467
 * We provide a special check for NetApp .snapshot directories to avoid
 * inode aliasing problems. All snapshot inodes are anonymous (unhashed).
 */
struct inode *
nfs_fhget(struct dentry *dentry, struct nfs_fh *fhandle,
				 struct nfs_fattr *fattr)
{
	struct super_block *sb = dentry->d_sb;

	dprintk("NFS: nfs_fhget(%s/%s fileid=%d)\n",
		dentry->d_parent->d_name.name, dentry->d_name.name,
		fattr->fileid);

Linus Torvalds's avatar
Linus Torvalds committed
468
	/* Install the file handle in the dentry */
Linus Torvalds's avatar
Linus Torvalds committed
469 470 471 472 473 474 475 476 477 478 479 480 481 482 483
	*((struct nfs_fh *) dentry->d_fsdata) = *fhandle;

#ifdef CONFIG_NFS_SNAPSHOT
	/*
	 * Check for NetApp snapshot dentries, and get an 
	 * unhashed inode to avoid aliasing problems.
	 */
	if ((dentry->d_parent->d_inode->u.nfs_i.flags & NFS_IS_SNAPSHOT) ||
	    (IS_ROOT(dentry->d_parent) && dentry->d_name.len == 9 &&
	     memcmp(dentry->d_name.name, ".snapshot", 9) == 0)) {
		struct inode *inode = get_empty_inode();
		if (!inode)
			goto out;	
		inode->i_sb = sb;
		inode->i_dev = sb->s_dev;
Linus Torvalds's avatar
Linus Torvalds committed
484
		inode->i_flags = 0;
Linus Torvalds's avatar
Linus Torvalds committed
485 486 487 488 489 490 491 492 493 494 495 496 497 498 499
		inode->i_ino = fattr->fileid;
		nfs_read_inode(inode);
		nfs_fill_inode(inode, fattr);
		inode->u.nfs_i.flags |= NFS_IS_SNAPSHOT;
		dprintk("NFS: nfs_fhget(snapshot ino=%ld)\n", inode->i_ino);
	out:
		return inode;
	}
#endif
	return __nfs_fhget(sb, fattr);
}

/*
 * Look up the inode by super block and fattr->fileid.
 *
Linus Torvalds's avatar
Linus Torvalds committed
500
 * Note carefully the special handling of busy inodes (i_count > 1).
Linus Torvalds's avatar
Linus Torvalds committed
501
 * With the kernel 2.1.xx dcache all inodes except hard links must
Linus Torvalds's avatar
Linus Torvalds committed
502 503
 * have i_count == 1 after iget(). Otherwise, it indicates that the
 * server has reused a fileid (i_ino) and we have a stale inode.
504
 */
Linus Torvalds's avatar
Linus Torvalds committed
505 506
static struct inode *
__nfs_fhget(struct super_block *sb, struct nfs_fattr *fattr)
507
{
Linus Torvalds's avatar
Linus Torvalds committed
508 509
	struct inode *inode;
	int max_count;
Linus Torvalds's avatar
Linus Torvalds committed
510 511

retry:
Linus Torvalds's avatar
Linus Torvalds committed
512 513 514
	inode = iget(sb, fattr->fileid);
	if (!inode)
		goto out_no_inode;
Linus Torvalds's avatar
Linus Torvalds committed
515
	/* N.B. This should be impossible ... */
Linus Torvalds's avatar
Linus Torvalds committed
516 517
	if (inode->i_ino != fattr->fileid)
		goto out_bad_id;
Linus Torvalds's avatar
Linus Torvalds committed
518

Linus Torvalds's avatar
Linus Torvalds committed
519 520 521 522 523 524 525 526 527 528 529
	/*
	 * Check for busy inodes, and attempt to get rid of any
	 * unused local references. If successful, we release the
	 * inode and try again.
	 *
	 * Note that the busy test uses the values in the fattr,
	 * as the inode may have become a different object.
	 * (We can probably handle modes changes here, too.)
	 */
	max_count = S_ISDIR(fattr->mode) ? 1 : fattr->nlink;
	if (inode->i_count > max_count) {
Linus Torvalds's avatar
Linus Torvalds committed
530
printk("__nfs_fhget: inode %ld busy, i_count=%d, i_nlink=%d\n",
Linus Torvalds's avatar
Linus Torvalds committed
531 532 533
inode->i_ino, inode->i_count, inode->i_nlink);
		nfs_free_dentries(inode);
		if (inode->i_count > max_count) {
Linus Torvalds's avatar
Linus Torvalds committed
534
printk("__nfs_fhget: inode %ld still busy, i_count=%d\n",
Linus Torvalds's avatar
Linus Torvalds committed
535 536 537 538 539
inode->i_ino, inode->i_count);
			if (!list_empty(&inode->i_dentry)) {
				struct dentry *dentry;
				dentry = list_entry(inode->i_dentry.next,
						 struct dentry, d_alias);
Linus Torvalds's avatar
Linus Torvalds committed
540
printk("__nfs_fhget: killing %s/%s filehandle\n",
Linus Torvalds's avatar
Linus Torvalds committed
541
dentry->d_parent->d_name.name, dentry->d_name.name);
Linus Torvalds's avatar
Linus Torvalds committed
542 543
				memset(dentry->d_fsdata, 0, 
					sizeof(struct nfs_fh));
Linus Torvalds's avatar
Linus Torvalds committed
544 545 546 547 548 549 550 551 552
			} else
				printk("NFS: inode %ld busy, no aliases?\n",
					inode->i_ino);
			make_bad_inode(inode);
			remove_inode_hash(inode);
		}
		iput(inode);
		goto retry;
	}
Linus Torvalds's avatar
Linus Torvalds committed
553 554 555
	nfs_fill_inode(inode, fattr);
	dprintk("NFS: __nfs_fhget(%x/%ld ct=%d)\n",
		inode->i_dev, inode->i_ino, inode->i_count);
Linus Torvalds's avatar
Linus Torvalds committed
556

Linus Torvalds's avatar
Linus Torvalds committed
557
out:
558
	return inode;
Linus Torvalds's avatar
Linus Torvalds committed
559 560

out_no_inode:
Linus Torvalds's avatar
Linus Torvalds committed
561
	printk("__nfs_fhget: iget failed\n");
Linus Torvalds's avatar
Linus Torvalds committed
562 563
	goto out;
out_bad_id:
Linus Torvalds's avatar
Linus Torvalds committed
564
	printk("__nfs_fhget: unexpected inode from iget\n");
Linus Torvalds's avatar
Linus Torvalds committed
565
	goto out;
566 567
}

Linus Torvalds's avatar
Linus Torvalds committed
568
int
Linus Torvalds's avatar
Linus Torvalds committed
569
nfs_notify_change(struct dentry *dentry, struct iattr *attr)
570
{
Linus Torvalds's avatar
Linus Torvalds committed
571 572
	struct inode *inode = dentry->d_inode;
	int error;
573 574 575
	struct nfs_sattr sattr;
	struct nfs_fattr fattr;

Linus Torvalds's avatar
Linus Torvalds committed
576 577 578
	/*
	 * Make sure the inode is up-to-date.
	 */
Linus Torvalds's avatar
Linus Torvalds committed
579
	error = nfs_revalidate(dentry);
Linus Torvalds's avatar
Linus Torvalds committed
580 581 582 583 584 585 586
	if (error) {
#ifdef NFS_PARANOIA
printk("nfs_notify_change: revalidate failed, error=%d\n", error);
#endif
		goto out;
	}

Linus Torvalds's avatar
Linus Torvalds committed
587 588
	sattr.mode = (u32) -1;
	if (attr->ia_valid & ATTR_MODE) 
Linus Torvalds's avatar
Linus Torvalds committed
589 590
		sattr.mode = attr->ia_mode;

Linus Torvalds's avatar
Linus Torvalds committed
591
	sattr.uid = (u32) -1;
Linus Torvalds's avatar
Linus Torvalds committed
592 593 594
	if (attr->ia_valid & ATTR_UID)
		sattr.uid = attr->ia_uid;

Linus Torvalds's avatar
Linus Torvalds committed
595
	sattr.gid = (u32) -1;
Linus Torvalds's avatar
Linus Torvalds committed
596 597 598
	if (attr->ia_valid & ATTR_GID)
		sattr.gid = attr->ia_gid;

Linus Torvalds's avatar
Linus Torvalds committed
599 600 601
	sattr.size = (u32) -1;
	if ((attr->ia_valid & ATTR_SIZE) && S_ISREG(inode->i_mode))
		sattr.size = attr->ia_size;
Linus Torvalds's avatar
Linus Torvalds committed
602

Linus Torvalds's avatar
Linus Torvalds committed
603
	sattr.mtime.seconds = sattr.mtime.useconds = (u32) -1;
Linus Torvalds's avatar
Linus Torvalds committed
604
	if (attr->ia_valid & ATTR_MTIME) {
Linus Torvalds's avatar
Linus Torvalds committed
605
		sattr.mtime.seconds = attr->ia_mtime;
606
		sattr.mtime.useconds = 0;
Linus Torvalds's avatar
Linus Torvalds committed
607
	}
Linus Torvalds's avatar
Linus Torvalds committed
608

Linus Torvalds's avatar
Linus Torvalds committed
609
	sattr.atime.seconds = sattr.atime.useconds = (u32) -1;
Linus Torvalds's avatar
Linus Torvalds committed
610
	if (attr->ia_valid & ATTR_ATIME) {
Linus Torvalds's avatar
Linus Torvalds committed
611 612
		sattr.atime.seconds = attr->ia_atime;
		sattr.atime.useconds = 0;
Linus Torvalds's avatar
Linus Torvalds committed
613
	}
Linus Torvalds's avatar
Linus Torvalds committed
614

Linus Torvalds's avatar
Linus Torvalds committed
615
	error = nfs_proc_setattr(NFS_DSERVER(dentry), NFS_FH(dentry),
Linus Torvalds's avatar
Linus Torvalds committed
616 617 618 619 620 621 622 623 624 625 626
				&sattr, &fattr);
	if (error)
		goto out;
	/*
	 * If we changed the size or mtime, update the inode
	 * now to avoid invalidating the page cache.
	 */
	if (sattr.size != (u32) -1) {
		if (sattr.size != fattr.size)
			printk("nfs_notify_change: sattr=%d, fattr=%d??\n",
				sattr.size, fattr.size);
Linus Torvalds's avatar
Linus Torvalds committed
627
		nfs_truncate_dirty_pages(inode, sattr.size);
Linus Torvalds's avatar
Linus Torvalds committed
628 629
		inode->i_size  = sattr.size;
		inode->i_mtime = fattr.mtime.seconds;
Linus Torvalds's avatar
Linus Torvalds committed
630
	}
Linus Torvalds's avatar
Linus Torvalds committed
631 632 633 634
	if (sattr.mtime.seconds != (u32) -1)
		inode->i_mtime = fattr.mtime.seconds;
	error = nfs_refresh_inode(inode, &fattr);
out:
635 636
	return error;
}
Linus Torvalds's avatar
Linus Torvalds committed
637

Linus Torvalds's avatar
Linus Torvalds committed
638 639 640 641
/*
 * Externally visible revalidation function
 */
int
Linus Torvalds's avatar
Linus Torvalds committed
642
nfs_revalidate(struct dentry *dentry)
Linus Torvalds's avatar
Linus Torvalds committed
643
{
Linus Torvalds's avatar
Linus Torvalds committed
644
	return nfs_revalidate_inode(NFS_DSERVER(dentry), dentry);
Linus Torvalds's avatar
Linus Torvalds committed
645
}
Linus Torvalds's avatar
Linus Torvalds committed
646

Linus Torvalds's avatar
Linus Torvalds committed
647
/*
Linus Torvalds's avatar
Linus Torvalds committed
648 649
 * This function is called whenever some part of NFS notices that
 * the cached attributes have to be refreshed.
Linus Torvalds's avatar
Linus Torvalds committed
650
 */
Linus Torvalds's avatar
Linus Torvalds committed
651
int
Linus Torvalds's avatar
Linus Torvalds committed
652
_nfs_revalidate_inode(struct nfs_server *server, struct dentry *dentry)
Linus Torvalds's avatar
Linus Torvalds committed
653
{
Linus Torvalds's avatar
Linus Torvalds committed
654
	struct inode	*inode = dentry->d_inode;
Linus Torvalds's avatar
Linus Torvalds committed
655
	int		 status = 0;
Linus Torvalds's avatar
Linus Torvalds committed
656
	struct nfs_fattr fattr;
Linus Torvalds's avatar
Linus Torvalds committed
657

Linus Torvalds's avatar
Linus Torvalds committed
658
	/* Don't bother revalidating if we've done it recently */
Linus Torvalds's avatar
Linus Torvalds committed
659
	if (jiffies - NFS_READTIME(inode) < NFS_ATTRTIMEO(inode))
Linus Torvalds's avatar
Linus Torvalds committed
660
		goto out;
Linus Torvalds's avatar
Linus Torvalds committed
661

Linus Torvalds's avatar
Linus Torvalds committed
662 663 664 665
	dfprintk(PAGECACHE, "NFS: revalidating %s/%s, ino=%ld\n",
		dentry->d_parent->d_name.name, dentry->d_name.name,
		inode->i_ino);
	status = nfs_proc_getattr(server, NFS_FH(dentry), &fattr);
Linus Torvalds's avatar
Linus Torvalds committed
666
	if (status) {
667 668 669
		int error;
		u32 *fh;
		struct nfs_fh fhandle;
Linus Torvalds's avatar
Linus Torvalds committed
670
#ifdef NFS_PARANOIA
Linus Torvalds's avatar
Linus Torvalds committed
671 672
printk("nfs_revalidate_inode: %s/%s getattr failed, ino=%ld, error=%d\n",
dentry->d_parent->d_name.name, dentry->d_name.name, inode->i_ino, status);
Linus Torvalds's avatar
Linus Torvalds committed
673
#endif
674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691
		if (status != -ESTALE)
			goto out;
		/*
		 * A "stale filehandle" error ... show the current fh
		 * and find out what the filehandle should be.
		 */
		fh = (u32 *) NFS_FH(dentry);
		printk("NFS: bad fh %08x%08x%08x%08x%08x%08x%08x%08x\n",
			fh[0],fh[1],fh[2],fh[3],fh[4],fh[5],fh[6],fh[7]);
		error = nfs_proc_lookup(server, NFS_FH(dentry->d_parent), 
					dentry->d_name.name, &fhandle, &fattr);
		if (error) {
			printk("NFS: lookup failed, error=%d\n", error);
			goto out;
		}
		fh = (u32 *) &fhandle;
		printk("            %08x%08x%08x%08x%08x%08x%08x%08x\n",
			fh[0],fh[1],fh[2],fh[3],fh[4],fh[5],fh[6],fh[7]);
Linus Torvalds's avatar
Linus Torvalds committed
692
		goto out;
Linus Torvalds's avatar
Linus Torvalds committed
693
	}
Linus Torvalds's avatar
Linus Torvalds committed
694

Linus Torvalds's avatar
Linus Torvalds committed
695
	status = nfs_refresh_inode(inode, &fattr);
Linus Torvalds's avatar
Linus Torvalds committed
696 697 698 699 700 701 702
	if (status) {
#ifdef NFS_PARANOIA
printk("nfs_revalidate_inode: %s/%s refresh failed, ino=%ld, error=%d\n",
dentry->d_parent->d_name.name, dentry->d_name.name, inode->i_ino, status);
#endif
		goto out;
	}
Linus Torvalds's avatar
Linus Torvalds committed
703
	if (fattr.mtime.seconds == NFS_OLDMTIME(inode)) {
Linus Torvalds's avatar
Linus Torvalds committed
704 705 706 707
		/* Update attrtimeo value */
		if ((NFS_ATTRTIMEO(inode) <<= 1) > NFS_MAXATTRTIMEO(inode))
			NFS_ATTRTIMEO(inode) = NFS_MAXATTRTIMEO(inode);
	}
Linus Torvalds's avatar
Linus Torvalds committed
708
	NFS_OLDMTIME(inode) = fattr.mtime.seconds;
Linus Torvalds's avatar
Linus Torvalds committed
709 710
	dfprintk(PAGECACHE, "NFS: %s/%s revalidation complete\n",
		dentry->d_parent->d_name.name, dentry->d_name.name);
Linus Torvalds's avatar
Linus Torvalds committed
711
out:
Linus Torvalds's avatar
Linus Torvalds committed
712
	return status;
Linus Torvalds's avatar
Linus Torvalds committed
713 714
}

Linus Torvalds's avatar
Linus Torvalds committed
715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740
/*
 * Many nfs protocol calls return the new file attributes after
 * an operation.  Here we update the inode to reflect the state
 * of the server's inode.
 *
 * This is a bit tricky because we have to make sure all dirty pages
 * have been sent off to the server before calling invalidate_inode_pages.
 * To make sure no other process adds more write requests while we try
 * our best to flush them, we make them sleep during the attribute refresh.
 *
 * A very similar scenario holds for the dir cache.
 */
int
nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
{
	int invalid = 0;
	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");
		goto out;
	}
	if (inode->i_ino != fattr->fileid) {
Linus Torvalds's avatar
Linus Torvalds committed
741 742
		printk("nfs_refresh_inode: mismatch, ino=%ld, fattr=%d\n",
			inode->i_ino, fattr->fileid);
Linus Torvalds's avatar
Linus Torvalds committed
743 744 745 746 747 748 749 750 751
		goto out;
	}

	/*
	 * Make sure the inode's type hasn't changed.
	 */
	if ((inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT))
		goto out_changed;

Linus Torvalds's avatar
Linus Torvalds committed
752 753 754 755 756 757 758 759 760
	inode->i_mode = fattr->mode;
	inode->i_nlink = fattr->nlink;
	inode->i_uid = fattr->uid;
	inode->i_gid = fattr->gid;

	inode->i_blocks = fattr->blocks;
	inode->i_atime = fattr->atime.seconds;
	inode->i_ctime = fattr->ctime.seconds;

Linus Torvalds's avatar
Linus Torvalds committed
761
	/*
Linus Torvalds's avatar
Linus Torvalds committed
762
	 * Update the read time so we don't revalidate too often.
Linus Torvalds's avatar
Linus Torvalds committed
763
	 */
Linus Torvalds's avatar
Linus Torvalds committed
764 765
	NFS_READTIME(inode) = jiffies;
	error = 0;
Linus Torvalds's avatar
Linus Torvalds committed
766

Linus Torvalds's avatar
Linus Torvalds committed
767
	/*
Linus Torvalds's avatar
Linus Torvalds committed
768 769 770
	 * If we have pending write-back entries, we don't want
	 * to look at the size or the mtime the server sends us
	 * too closely, as we're in the middle of modifying them.
Linus Torvalds's avatar
Linus Torvalds committed
771
	 */
Linus Torvalds's avatar
Linus Torvalds committed
772 773 774
	if (NFS_WRITEBACK(inode))
		goto out;

Linus Torvalds's avatar
Linus Torvalds committed
775 776 777 778
	if (inode->i_size != fattr->size) {
#ifdef NFS_DEBUG_VERBOSE
printk("NFS: size change on %x/%ld\n", inode->i_dev, inode->i_ino);
#endif
Linus Torvalds's avatar
Linus Torvalds committed
779
		inode->i_size = fattr->size;
Linus Torvalds's avatar
Linus Torvalds committed
780 781
		invalid = 1;
	}
Linus Torvalds's avatar
Linus Torvalds committed
782

Linus Torvalds's avatar
Linus Torvalds committed
783 784 785 786
	if (inode->i_mtime != fattr->mtime.seconds) {
#ifdef NFS_DEBUG_VERBOSE
printk("NFS: mtime change on %x/%ld\n", inode->i_dev, inode->i_ino);
#endif
Linus Torvalds's avatar
Linus Torvalds committed
787
		inode->i_mtime = fattr->mtime.seconds;
Linus Torvalds's avatar
Linus Torvalds committed
788 789 790 791 792 793 794 795 796 797 798 799 800
		invalid = 1;
	}

	if (invalid)
		goto out_invalid;
out:
	return error;

out_changed:
	/*
	 * Big trouble! The inode has become a different object.
	 */
#ifdef NFS_PARANOIA
Linus Torvalds's avatar
Linus Torvalds committed
801 802
printk("nfs_refresh_inode: inode %ld mode changed, %07o to %07o\n",
inode->i_ino, inode->i_mode, fattr->mode);
Linus Torvalds's avatar
Linus Torvalds committed
803 804 805
#endif
	fattr->mode = inode->i_mode; /* save mode */
	make_bad_inode(inode);
Linus Torvalds's avatar
Linus Torvalds committed
806
	nfs_inval(inode);
Linus Torvalds's avatar
Linus Torvalds committed
807 808 809 810 811 812 813 814 815 816 817 818 819 820
	inode->i_mode = fattr->mode; /* restore mode */
	/*
	 * No need to worry about unhashing the dentry, as the
	 * lookup validation will know that the inode is bad.
	 * (But we fall through to invalidate the caches.)
	 */

out_invalid:
	/*
	 * Invalidate the local caches
	 */
#ifdef NFS_DEBUG_VERBOSE
printk("nfs_refresh_inode: invalidating %ld pages\n", inode->i_nrpages);
#endif
Linus Torvalds's avatar
Linus Torvalds committed
821
	if (!S_ISDIR(inode->i_mode))
Linus Torvalds's avatar
Linus Torvalds committed
822
		invalidate_inode_pages(inode);
Linus Torvalds's avatar
Linus Torvalds committed
823
	else
Linus Torvalds's avatar
Linus Torvalds committed
824 825 826 827 828 829
		nfs_invalidate_dircache(inode);
	NFS_CACHEINV(inode);
	NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
	goto out;
}

Linus Torvalds's avatar
Linus Torvalds committed
830 831 832 833
/*
 * File system information
 */
static struct file_system_type nfs_fs_type = {
Linus Torvalds's avatar
Linus Torvalds committed
834
	"nfs",
Linus Torvalds's avatar
Linus Torvalds committed
835
	0 /* FS_NO_DCACHE - this doesn't work right now*/,
Linus Torvalds's avatar
Linus Torvalds committed
836 837
	nfs_read_super,
	NULL
Linus Torvalds's avatar
Linus Torvalds committed
838 839 840 841 842 843 844
};

/*
 * Initialize NFS
 */
int
init_nfs_fs(void)
Linus Torvalds's avatar
Linus Torvalds committed
845
{
Linus Torvalds's avatar
Linus Torvalds committed
846
#ifdef CONFIG_PROC_FS
Linus Torvalds's avatar
Linus Torvalds committed
847 848
	rpc_register_sysctl();
	rpc_proc_init();
Linus Torvalds's avatar
Linus Torvalds committed
849
	rpc_proc_register(&nfs_rpcstat);
Linus Torvalds's avatar
Linus Torvalds committed
850
#endif
Linus Torvalds's avatar
Linus Torvalds committed
851 852 853
        return register_filesystem(&nfs_fs_type);
}

Linus Torvalds's avatar
Linus Torvalds committed
854 855 856
/*
 * Every kernel module contains stuff like this.
 */
Linus Torvalds's avatar
Linus Torvalds committed
857
#ifdef MODULE
Linus Torvalds's avatar
Linus Torvalds committed
858

Linus Torvalds's avatar
Linus Torvalds committed
859
EXPORT_NO_SYMBOLS;
Linus Torvalds's avatar
Linus Torvalds committed
860 861
/* Not quite true; I just maintain it */
MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>");
Linus Torvalds's avatar
Linus Torvalds committed
862

Linus Torvalds's avatar
Linus Torvalds committed
863 864
int
init_module(void)
Linus Torvalds's avatar
Linus Torvalds committed
865
{
Linus Torvalds's avatar
Linus Torvalds committed
866
	return init_nfs_fs();
Linus Torvalds's avatar
Linus Torvalds committed
867 868
}

Linus Torvalds's avatar
Linus Torvalds committed
869 870
void
cleanup_module(void)
Linus Torvalds's avatar
Linus Torvalds committed
871
{
Linus Torvalds's avatar
Linus Torvalds committed
872
#ifdef CONFIG_PROC_FS
Linus Torvalds's avatar
Linus Torvalds committed
873
	rpc_proc_unregister("nfs");
Linus Torvalds's avatar
Linus Torvalds committed
874
#endif
Linus Torvalds's avatar
Linus Torvalds committed
875
	unregister_filesystem(&nfs_fs_type);
Linus Torvalds's avatar
Linus Torvalds committed
876
	nfs_free_dircache();
Linus Torvalds's avatar
Linus Torvalds committed
877 878
}
#endif