vfs_inode.c 30.6 KB
Newer Older
1
2
3
/*
 *  linux/fs/9p/vfs_inode.c
 *
4
 * This file contains vfs inode ops for the 9P2000 protocol.
5
6
7
8
9
 *
 *  Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
 *  Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
 *
 *  This program is free software; you can redistribute it and/or modify
10
11
 *  it under the terms of the GNU General Public License version 2
 *  as published by the Free Software Foundation.
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to:
 *  Free Software Foundation
 *  51 Franklin Street, Fifth Floor
 *  Boston, MA  02111-1301  USA
 *
 */

#include <linux/module.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/file.h>
#include <linux/pagemap.h>
#include <linux/stat.h>
#include <linux/string.h>
#include <linux/inet.h>
#include <linux/namei.h>
#include <linux/idr.h>
Alexey Dobriyan's avatar
Alexey Dobriyan committed
36
#include <linux/sched.h>
37
#include <linux/slab.h>
38
#include <linux/xattr.h>
39
#include <linux/posix_acl.h>
40
41
#include <net/9p/9p.h>
#include <net/9p/client.h>
42
43
44
45

#include "v9fs.h"
#include "v9fs_vfs.h"
#include "fid.h"
46
#include "cache.h"
47
#include "xattr.h"
48
#include "acl.h"
49

50
static const struct inode_operations v9fs_dir_inode_operations;
51
static const struct inode_operations v9fs_dir_inode_operations_dotu;
52
53
static const struct inode_operations v9fs_file_inode_operations;
static const struct inode_operations v9fs_symlink_inode_operations;
54

55
56
57
58
59
60
61
/**
 * unixmode2p9mode - convert unix mode bits to plan 9
 * @v9ses: v9fs session information
 * @mode: mode to convert
 *
 */

62
static int unixmode2p9mode(struct v9fs_session_info *v9ses, int mode)
63
64
65
66
{
	int res;
	res = mode & 0777;
	if (S_ISDIR(mode))
67
		res |= P9_DMDIR;
68
	if (v9fs_proto_dotu(v9ses)) {
69
		if (S_ISLNK(mode))
70
			res |= P9_DMSYMLINK;
71
72
		if (v9ses->nodev == 0) {
			if (S_ISSOCK(mode))
73
				res |= P9_DMSOCKET;
74
			if (S_ISFIFO(mode))
75
				res |= P9_DMNAMEDPIPE;
76
			if (S_ISBLK(mode))
77
				res |= P9_DMDEVICE;
78
			if (S_ISCHR(mode))
79
				res |= P9_DMDEVICE;
80
81
82
		}

		if ((mode & S_ISUID) == S_ISUID)
83
			res |= P9_DMSETUID;
84
		if ((mode & S_ISGID) == S_ISGID)
85
			res |= P9_DMSETGID;
86
87
		if ((mode & S_ISVTX) == S_ISVTX)
			res |= P9_DMSETVTX;
88
89
		if ((mode & P9_DMLINK))
			res |= P9_DMLINK;
90
91
92
93
94
95
96
97
98
99
100
101
	}

	return res;
}

/**
 * p9mode2unixmode- convert plan9 mode bits to unix mode bits
 * @v9ses: v9fs session information
 * @mode: mode to convert
 *
 */

102
static int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode)
103
104
105
106
107
{
	int res;

	res = mode & 0777;

108
	if ((mode & P9_DMDIR) == P9_DMDIR)
109
		res |= S_IFDIR;
110
	else if ((mode & P9_DMSYMLINK) && (v9fs_proto_dotu(v9ses)))
111
		res |= S_IFLNK;
112
	else if ((mode & P9_DMSOCKET) && (v9fs_proto_dotu(v9ses))
113
114
		 && (v9ses->nodev == 0))
		res |= S_IFSOCK;
115
	else if ((mode & P9_DMNAMEDPIPE) && (v9fs_proto_dotu(v9ses))
116
117
		 && (v9ses->nodev == 0))
		res |= S_IFIFO;
118
	else if ((mode & P9_DMDEVICE) && (v9fs_proto_dotu(v9ses))
119
120
121
122
123
		 && (v9ses->nodev == 0))
		res |= S_IFBLK;
	else
		res |= S_IFREG;

124
	if (v9fs_proto_dotu(v9ses)) {
125
		if ((mode & P9_DMSETUID) == P9_DMSETUID)
126
127
			res |= S_ISUID;

128
		if ((mode & P9_DMSETGID) == P9_DMSETGID)
129
			res |= S_ISGID;
130
131
132

		if ((mode & P9_DMSETVTX) == P9_DMSETVTX)
			res |= S_ISVTX;
133
134
135
136
137
	}

	return res;
}

138
139
140
/**
 * v9fs_uflags2omode- convert posix open flags to plan 9 mode bits
 * @uflags: flags to convert
141
 * @extended: if .u extensions are active
142
143
 */

144
int v9fs_uflags2omode(int uflags, int extended)
145
146
147
148
149
150
151
{
	int ret;

	ret = 0;
	switch (uflags&3) {
	default:
	case O_RDONLY:
152
		ret = P9_OREAD;
153
154
155
		break;

	case O_WRONLY:
156
		ret = P9_OWRITE;
157
158
159
		break;

	case O_RDWR:
160
		ret = P9_ORDWR;
161
162
163
164
		break;
	}

	if (uflags & O_TRUNC)
165
		ret |= P9_OTRUNC;
166

167
168
169
170
171
172
173
	if (extended) {
		if (uflags & O_EXCL)
			ret |= P9_OEXCL;

		if (uflags & O_APPEND)
			ret |= P9_OAPPEND;
	}
174
175
176
177

	return ret;
}

178
/**
179
180
 * v9fs_blank_wstat - helper function to setup a 9P stat structure
 * @wstat: structure to initialize
181
182
183
 *
 */

184
void
185
v9fs_blank_wstat(struct p9_wstat *wstat)
186
{
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
	wstat->type = ~0;
	wstat->dev = ~0;
	wstat->qid.type = ~0;
	wstat->qid.version = ~0;
	*((long long *)&wstat->qid.path) = ~0;
	wstat->mode = ~0;
	wstat->atime = ~0;
	wstat->mtime = ~0;
	wstat->length = ~0;
	wstat->name = NULL;
	wstat->uid = NULL;
	wstat->gid = NULL;
	wstat->muid = NULL;
	wstat->n_uid = ~0;
	wstat->n_gid = ~0;
	wstat->n_muid = ~0;
	wstat->extension = NULL;
204
205
}

206
207
208
209
210
211
/**
 * v9fs_alloc_inode - helper function to allocate an inode
 *
 */
struct inode *v9fs_alloc_inode(struct super_block *sb)
{
Aneesh Kumar K.V's avatar
Aneesh Kumar K.V committed
212
213
214
215
	struct v9fs_inode *v9inode;
	v9inode = (struct v9fs_inode *)kmem_cache_alloc(v9fs_inode_cache,
							GFP_KERNEL);
	if (!v9inode)
216
		return NULL;
Aneesh Kumar K.V's avatar
Aneesh Kumar K.V committed
217
218
219
220
221
#ifdef CONFIG_9P_FSCACHE
	v9inode->fscache = NULL;
	v9inode->fscache_key = NULL;
	spin_lock_init(&v9inode->fscache_lock);
#endif
222
	v9inode->writeback_fid = NULL;
223
	v9inode->cache_validity = 0;
Aneesh Kumar K.V's avatar
Aneesh Kumar K.V committed
224
	return &v9inode->vfs_inode;
225
226
227
228
229
230
231
}

/**
 * v9fs_destroy_inode - destroy an inode
 *
 */

Nick Piggin's avatar
Nick Piggin committed
232
static void v9fs_i_callback(struct rcu_head *head)
233
{
Nick Piggin's avatar
Nick Piggin committed
234
235
	struct inode *inode = container_of(head, struct inode, i_rcu);
	INIT_LIST_HEAD(&inode->i_dentry);
Aneesh Kumar K.V's avatar
Aneesh Kumar K.V committed
236
	kmem_cache_free(v9fs_inode_cache, V9FS_I(inode));
237
}
Nick Piggin's avatar
Nick Piggin committed
238
239
240
241
242

void v9fs_destroy_inode(struct inode *inode)
{
	call_rcu(&inode->i_rcu, v9fs_i_callback);
}
243

Aneesh Kumar K.V's avatar
Aneesh Kumar K.V committed
244
245
int v9fs_init_inode(struct v9fs_session_info *v9ses,
		    struct inode *inode, int mode)
246
{
Aneesh Kumar K.V's avatar
Aneesh Kumar K.V committed
247
	int err = 0;
248

249
	inode_init_owner(inode, NULL, mode);
250
251
252
253
254
255
256
257
258
259
	inode->i_blocks = 0;
	inode->i_rdev = 0;
	inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
	inode->i_mapping->a_ops = &v9fs_addr_operations;

	switch (mode & S_IFMT) {
	case S_IFIFO:
	case S_IFBLK:
	case S_IFCHR:
	case S_IFSOCK:
M. Mohan Kumar's avatar
M. Mohan Kumar committed
260
261
262
263
264
265
266
		if (v9fs_proto_dotl(v9ses)) {
			inode->i_op = &v9fs_file_inode_operations_dotl;
			inode->i_fop = &v9fs_file_operations_dotl;
		} else if (v9fs_proto_dotu(v9ses)) {
			inode->i_op = &v9fs_file_inode_operations;
			inode->i_fop = &v9fs_file_operations;
		} else {
267
			P9_DPRINTK(P9_DEBUG_ERROR,
268
269
270
				   "special files without extended mode\n");
			err = -EINVAL;
			goto error;
271
		}
272
273
274
		init_special_inode(inode, inode->i_mode, inode->i_rdev);
		break;
	case S_IFREG:
275
276
		if (v9fs_proto_dotl(v9ses)) {
			inode->i_op = &v9fs_file_inode_operations_dotl;
277
278
279
280
281
			if (v9ses->cache)
				inode->i_fop =
					&v9fs_cached_file_operations_dotl;
			else
				inode->i_fop = &v9fs_file_operations_dotl;
282
283
		} else {
			inode->i_op = &v9fs_file_inode_operations;
284
285
286
287
			if (v9ses->cache)
				inode->i_fop = &v9fs_cached_file_operations;
			else
				inode->i_fop = &v9fs_file_operations;
288
289
		}

290
291
		break;
	case S_IFLNK:
292
293
294
		if (!v9fs_proto_dotu(v9ses) && !v9fs_proto_dotl(v9ses)) {
			P9_DPRINTK(P9_DEBUG_ERROR, "extended modes used with "
						"legacy protocol.\n");
295
296
297
			err = -EINVAL;
			goto error;
		}
298
299
300
301
302
303

		if (v9fs_proto_dotl(v9ses))
			inode->i_op = &v9fs_symlink_inode_operations_dotl;
		else
			inode->i_op = &v9fs_symlink_inode_operations;

304
305
306
		break;
	case S_IFDIR:
		inc_nlink(inode);
307
308
309
310
		if (v9fs_proto_dotl(v9ses))
			inode->i_op = &v9fs_dir_inode_operations_dotl;
		else if (v9fs_proto_dotu(v9ses))
			inode->i_op = &v9fs_dir_inode_operations_dotu;
311
312
		else
			inode->i_op = &v9fs_dir_inode_operations;
313
314
315
316
317
318

		if (v9fs_proto_dotl(v9ses))
			inode->i_fop = &v9fs_dir_operations_dotl;
		else
			inode->i_fop = &v9fs_dir_operations;

319
320
321
322
323
324
		break;
	default:
		P9_DPRINTK(P9_DEBUG_ERROR, "BAD mode 0x%x S_IFMT 0x%x\n",
			   mode, mode & S_IFMT);
		err = -EINVAL;
		goto error;
325
	}
Aneesh Kumar K.V's avatar
Aneesh Kumar K.V committed
326
327
error:
	return err;
328

Aneesh Kumar K.V's avatar
Aneesh Kumar K.V committed
329
}
330

Aneesh Kumar K.V's avatar
Aneesh Kumar K.V committed
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
/**
 * v9fs_get_inode - helper function to setup an inode
 * @sb: superblock
 * @mode: mode to setup inode with
 *
 */

struct inode *v9fs_get_inode(struct super_block *sb, int mode)
{
	int err;
	struct inode *inode;
	struct v9fs_session_info *v9ses = sb->s_fs_info;

	P9_DPRINTK(P9_DEBUG_VFS, "super block: %p mode: %o\n", sb, mode);

	inode = new_inode(sb);
	if (!inode) {
		P9_EPRINTK(KERN_WARNING, "Problem allocating inode\n");
		return ERR_PTR(-ENOMEM);
	}
	err = v9fs_init_inode(v9ses, inode, mode);
	if (err) {
		iput(inode);
		return ERR_PTR(err);
	}
	return inode;
357
358
}

359
/*
360
361
362
363
static struct v9fs_fid*
v9fs_clone_walk(struct v9fs_session_info *v9ses, u32 fid, struct dentry *dentry)
{
	int err;
364
	int nfid;
365
366
367
368
369
	struct v9fs_fid *ret;
	struct v9fs_fcall *fcall;

	nfid = v9fs_get_idpool(&v9ses->fidpool);
	if (nfid < 0) {
370
		eprintk(KERN_WARNING, "no free fids available\n");
371
		return ERR_PTR(-ENOSPC);
372
373
	}

374
375
376
377
	err = v9fs_t_walk(v9ses, fid, nfid, (char *) dentry->d_name.name,
		&fcall);

	if (err < 0) {
378
379
380
		if (fcall && fcall->id == RWALK)
			goto clunk_fid;

381
382
383
		PRINT_FCALL_ERROR("walk error", fcall);
		v9fs_put_idpool(nfid, &v9ses->fidpool);
		goto error;
384
	}
385

386
387
	kfree(fcall);
	fcall = NULL;
388
389
390
391
392
	ret = v9fs_fid_create(v9ses, nfid);
	if (!ret) {
		err = -ENOMEM;
		goto clunk_fid;
	}
393

394
395
396
397
	err = v9fs_fid_insert(ret, dentry);
	if (err < 0) {
		v9fs_fid_destroy(ret);
		goto clunk_fid;
398
	}
399

400
	return ret;
401

402
403
clunk_fid:
	v9fs_t_clunk(v9ses, nfid);
404

405
406
407
408
error:
	kfree(fcall);
	return ERR_PTR(err);
}
409
*/
410

411
412
413
414
415
416

/**
 * v9fs_clear_inode - release an inode
 * @inode: inode to release
 *
 */
417
void v9fs_evict_inode(struct inode *inode)
418
{
419
420
	struct v9fs_inode *v9inode = V9FS_I(inode);

421
422
	truncate_inode_pages(inode->i_mapping, 0);
	end_writeback(inode);
423
424
425
426
427
	filemap_fdatawrite(inode->i_mapping);

#ifdef CONFIG_9P_FSCACHE
	v9fs_cache_inode_put_cookie(inode);
#endif
428
429
430
431
	/* clunk the fid stashed in writeback_fid */
	if (v9inode->writeback_fid) {
		p9_client_clunk(v9inode->writeback_fid);
		v9inode->writeback_fid = NULL;
432
	}
433
434
}

Aneesh Kumar K.V's avatar
Aneesh Kumar K.V committed
435
436
437
static struct inode *v9fs_qid_iget(struct super_block *sb,
				   struct p9_qid *qid,
				   struct p9_wstat *st)
438
{
Aneesh Kumar K.V's avatar
Aneesh Kumar K.V committed
439
440
441
442
	int retval, umode;
	unsigned long i_ino;
	struct inode *inode;
	struct v9fs_session_info *v9ses = sb->s_fs_info;
443

Aneesh Kumar K.V's avatar
Aneesh Kumar K.V committed
444
445
446
447
448
449
450
451
452
453
454
	i_ino = v9fs_qid2ino(qid);
	inode = iget_locked(sb, i_ino);
	if (!inode)
		return ERR_PTR(-ENOMEM);
	if (!(inode->i_state & I_NEW))
		return inode;
	/*
	 * initialize the inode with the stat info
	 * FIXME!! we may need support for stale inodes
	 * later.
	 */
455
	umode = p9mode2unixmode(v9ses, st->mode);
Aneesh Kumar K.V's avatar
Aneesh Kumar K.V committed
456
457
	retval = v9fs_init_inode(v9ses, inode, umode);
	if (retval)
458
		goto error;
459

Aneesh Kumar K.V's avatar
Aneesh Kumar K.V committed
460
	v9fs_stat2inode(st, inode, sb);
461
#ifdef CONFIG_9P_FSCACHE
Aneesh Kumar K.V's avatar
Aneesh Kumar K.V committed
462
	v9fs_fscache_set_key(inode, &st->qid);
Aneesh Kumar K.V's avatar
Aneesh Kumar K.V committed
463
	v9fs_cache_inode_get_cookie(inode);
464
#endif
Aneesh Kumar K.V's avatar
Aneesh Kumar K.V committed
465
466
	unlock_new_inode(inode);
	return inode;
467
error:
Aneesh Kumar K.V's avatar
Aneesh Kumar K.V committed
468
469
470
471
472
473
474
	unlock_new_inode(inode);
	iput(inode);
	return ERR_PTR(retval);

}

struct inode *
Aneesh Kumar K.V's avatar
Aneesh Kumar K.V committed
475
476
v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid,
		    struct super_block *sb)
Aneesh Kumar K.V's avatar
Aneesh Kumar K.V committed
477
478
479
480
481
482
483
484
485
{
	struct p9_wstat *st;
	struct inode *inode = NULL;

	st = p9_client_stat(fid);
	if (IS_ERR(st))
		return ERR_CAST(st);

	inode = v9fs_qid_iget(sb, &st->qid, st);
486
	p9stat_free(st);
487
	kfree(st);
Aneesh Kumar K.V's avatar
Aneesh Kumar K.V committed
488
	return inode;
489
490
491
492
}

/**
 * v9fs_remove - helper function to remove files and directories
493
494
495
 * @dir: directory inode that is being deleted
 * @file:  dentry that is being deleted
 * @rmdir: removing a directory
496
497
498
499
500
 *
 */

static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir)
{
Aneesh Kumar K.V's avatar
Aneesh Kumar K.V committed
501
	int retval;
502
	struct p9_fid *v9fid;
503
	struct inode *file_inode;
504

505
	P9_DPRINTK(P9_DEBUG_VFS, "inode: %p dentry: %p rmdir: %d\n", dir, file,
506
507
508
		rmdir);

	file_inode = file->d_inode;
509
	v9fid = v9fs_fid_clone(file);
Latchesar Ionkov's avatar
Latchesar Ionkov committed
510
	if (IS_ERR(v9fid))
511
		return PTR_ERR(v9fid);
512

Aneesh Kumar K.V's avatar
Aneesh Kumar K.V committed
513
	retval = p9_client_remove(v9fid);
514
515
516
517
518
519
520
521
522
523
	if (!retval) {
		/*
		 * directories on unlink should have zero
		 * link count
		 */
		if (rmdir) {
			clear_nlink(file_inode);
			drop_nlink(dir);
		} else
			drop_nlink(file_inode);
524

525
		v9fs_invalidate_inode_attr(file_inode);
526
		v9fs_invalidate_inode_attr(dir);
527
	}
Aneesh Kumar K.V's avatar
Aneesh Kumar K.V committed
528
	return retval;
529
530
531
}

/**
532
 * v9fs_create - Create a file
533
534
 * @v9ses: session information
 * @dir: directory that dentry is being created in
535
 * @dentry:  dentry that is being created
Abhishek Kulkarni's avatar
Abhishek Kulkarni committed
536
 * @extension: 9p2000.u extension string to support devices, etc.
537
538
 * @perm: create permissions
 * @mode: open mode
539
540
 *
 */
541
542
543
static struct p9_fid *
v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,
		struct dentry *dentry, char *extension, u32 perm, u8 mode)
544
{
545
	int err;
546
547
	char *name;
	struct p9_fid *dfid, *ofid, *fid;
548
549
	struct inode *inode;

550
551
	P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", dentry->d_name.name);

552
553
554
555
	err = 0;
	ofid = NULL;
	fid = NULL;
	name = (char *) dentry->d_name.name;
556
	dfid = v9fs_fid_lookup(dentry->d_parent);
Latchesar Ionkov's avatar
Latchesar Ionkov committed
557
	if (IS_ERR(dfid)) {
558
		err = PTR_ERR(dfid);
559
560
		P9_DPRINTK(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
		return ERR_PTR(err);
561
	}
562

563
564
565
566
	/* clone a fid to use for creation */
	ofid = p9_client_walk(dfid, 0, NULL, 1);
	if (IS_ERR(ofid)) {
		err = PTR_ERR(ofid);
567
		P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err);
568
		return ERR_PTR(err);
569
	}
570

571
	err = p9_client_fcreate(ofid, name, perm, mode, extension);
572
573
	if (err < 0) {
		P9_DPRINTK(P9_DEBUG_VFS, "p9_client_fcreate failed %d\n", err);
574
		goto error;
575
	}
576

577
	/* now walk from the parent so we can get unopened fid */
578
	fid = p9_client_walk(dfid, 1, &name, 1);
579
580
	if (IS_ERR(fid)) {
		err = PTR_ERR(fid);
581
		P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err);
582
		fid = NULL;
583
		goto error;
584
	}
585

586
	/* instantiate inode and assign the unopened fid to the dentry */
Aneesh Kumar K.V's avatar
Aneesh Kumar K.V committed
587
	inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb);
588
589
	if (IS_ERR(inode)) {
		err = PTR_ERR(inode);
590
		P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", err);
591
592
593
		goto error;
	}
	d_instantiate(dentry, inode);
594
595
596
597
	err = v9fs_fid_add(dentry, fid);
	if (err < 0)
		goto error;

598
	return ofid;
599

600
601
602
603
604
605
606
607
608
609
610
611
error:
	if (ofid)
		p9_client_clunk(ofid);

	if (fid)
		p9_client_clunk(fid);

	return ERR_PTR(err);
}

/**
 * v9fs_vfs_create - VFS hook to create files
612
 * @dir: directory inode that is being created
613
614
615
616
617
 * @dentry:  dentry that is being deleted
 * @mode: create permissions
 * @nd: path information
 *
 */
618

619
620
621
622
623
624
625
static int
v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode,
		struct nameidata *nd)
{
	int err;
	u32 perm;
	int flags;
626
627
	struct file *filp;
	struct v9fs_inode *v9inode;
628
	struct v9fs_session_info *v9ses;
629
	struct p9_fid *fid, *inode_fid;
630
631
632
633
634
635
636
637
638
639
640

	err = 0;
	fid = NULL;
	v9ses = v9fs_inode2v9ses(dir);
	perm = unixmode2p9mode(v9ses, mode);
	if (nd && nd->flags & LOOKUP_OPEN)
		flags = nd->intent.open.flags - 1;
	else
		flags = O_RDWR;

	fid = v9fs_create(v9ses, dir, dentry, NULL, perm,
641
642
				v9fs_uflags2omode(flags,
						v9fs_proto_dotu(v9ses)));
643
644
645
646
647
648
	if (IS_ERR(fid)) {
		err = PTR_ERR(fid);
		fid = NULL;
		goto error;
	}

649
	v9fs_invalidate_inode_attr(dir);
650
651
	/* if we are opening a file, assign the open fid to the file */
	if (nd && nd->flags & LOOKUP_OPEN) {
652
653
		v9inode = V9FS_I(dentry->d_inode);
		if (v9ses->cache && !v9inode->writeback_fid) {
654
			/*
655
			 * clone a fid and add it to writeback_fid
656
657
658
659
660
661
662
663
664
665
			 * we do it during open time instead of
			 * page dirty time via write_begin/page_mkwrite
			 * because we want write after unlink usecase
			 * to work.
			 */
			inode_fid = v9fs_writeback_fid(dentry);
			if (IS_ERR(inode_fid)) {
				err = PTR_ERR(inode_fid);
				goto error;
			}
666
			v9inode->writeback_fid = (void *) inode_fid;
667
		}
668
		filp = lookup_instantiate_filp(nd, dentry, generic_file_open);
669
		if (IS_ERR(filp)) {
670
671
			err = PTR_ERR(filp);
			goto error;
672
673
		}

674
		filp->private_data = fid;
675
676
677
678
#ifdef CONFIG_9P_FSCACHE
		if (v9ses->cache)
			v9fs_cache_inode_set_cookie(dentry->d_inode, filp);
#endif
679
680
	} else
		p9_client_clunk(fid);
681
682
683
684

	return 0;

error:
685
686
	if (fid)
		p9_client_clunk(fid);
687
688

	return err;
689
690
691
692
}

/**
 * v9fs_vfs_mkdir - VFS mkdir hook to create a directory
693
 * @dir:  inode that is being unlinked
694
695
696
697
698
 * @dentry: dentry that is being unlinked
 * @mode: mode for new directory
 *
 */

699
static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
700
{
701
	int err;
702
703
	u32 perm;
	struct p9_fid *fid;
704
	struct v9fs_session_info *v9ses;
705

706
707
	P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", dentry->d_name.name);
	err = 0;
708
709
	v9ses = v9fs_inode2v9ses(dir);
	perm = unixmode2p9mode(v9ses, mode | S_IFDIR);
710
711
712
713
	fid = v9fs_create(v9ses, dir, dentry, NULL, perm, P9_OREAD);
	if (IS_ERR(fid)) {
		err = PTR_ERR(fid);
		fid = NULL;
714
	} else {
715
		inc_nlink(dir);
716
717
		v9fs_invalidate_inode_attr(dir);
	}
718

719
720
	if (fid)
		p9_client_clunk(fid);
721
722

	return err;
723
724
725
726
727
728
729
730
731
732
}

/**
 * v9fs_vfs_lookup - VFS lookup hook to "walk" to a new inode
 * @dir:  inode that is being walked from
 * @dentry: dentry that is being walked to?
 * @nameidata: path data
 *
 */

733
struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
734
735
736
737
				      struct nameidata *nameidata)
{
	struct super_block *sb;
	struct v9fs_session_info *v9ses;
738
	struct p9_fid *dfid, *fid;
739
	struct inode *inode;
740
	char *name;
741
742
	int result = 0;

743
	P9_DPRINTK(P9_DEBUG_VFS, "dir: %p dentry: (%s) %p nameidata: %p\n",
744
		dir, dentry->d_name.name, dentry, nameidata);
745

746
747
748
	if (dentry->d_name.len > NAME_MAX)
		return ERR_PTR(-ENAMETOOLONG);

749
750
	sb = dir->i_sb;
	v9ses = v9fs_inode2v9ses(dir);
751
	/* We can walk d_parent because we hold the dir->i_mutex */
752
753
	dfid = v9fs_fid_lookup(dentry->d_parent);
	if (IS_ERR(dfid))
754
		return ERR_CAST(dfid);
755
756
757
758
759

	name = (char *) dentry->d_name.name;
	fid = p9_client_walk(dfid, 1, &name, 1);
	if (IS_ERR(fid)) {
		result = PTR_ERR(fid);
760
		if (result == -ENOENT) {
761
762
			inode = NULL;
			goto inst_out;
763
764
		}

765
		return ERR_PTR(result);
766
767
	}

Aneesh Kumar K.V's avatar
Aneesh Kumar K.V committed
768
	inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb);
769
770
771
772
	if (IS_ERR(inode)) {
		result = PTR_ERR(inode);
		inode = NULL;
		goto error;
773
774
	}

775
	result = v9fs_fid_add(dentry, fid);
776
	if (result < 0)
777
		goto error_iput;
778

779
inst_out:
780
781
782
	d_add(dentry, inode);
	return NULL;

783
784
error_iput:
	iput(inode);
785
error:
786
	p9_client_clunk(fid);
787

788
789
790
791
792
793
	return ERR_PTR(result);
}

/**
 * v9fs_vfs_unlink - VFS unlink hook to delete an inode
 * @i:  inode that is being unlinked
794
 * @d: dentry that is being unlinked
795
796
797
 *
 */

798
int v9fs_vfs_unlink(struct inode *i, struct dentry *d)
799
800
801
802
803
804
805
{
	return v9fs_remove(i, d, 0);
}

/**
 * v9fs_vfs_rmdir - VFS unlink hook to delete a directory
 * @i:  inode that is being unlinked
806
 * @d: dentry that is being unlinked
807
808
809
 *
 */

810
int v9fs_vfs_rmdir(struct inode *i, struct dentry *d)
811
812
813
814
815
816
817
818
819
820
821
822
823
{
	return v9fs_remove(i, d, 1);
}

/**
 * v9fs_vfs_rename - VFS hook to rename an inode
 * @old_dir:  old dir inode
 * @old_dentry: old dentry
 * @new_dir: new dir inode
 * @new_dentry: new dentry
 *
 */

824
int
825
826
827
v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
		struct inode *new_dir, struct dentry *new_dentry)
{
828
	int retval;
829
	struct inode *old_inode;
830
	struct inode *new_inode;
831
832
833
834
835
	struct v9fs_session_info *v9ses;
	struct p9_fid *oldfid;
	struct p9_fid *olddirfid;
	struct p9_fid *newdirfid;
	struct p9_wstat wstat;
836

837
838
839
	P9_DPRINTK(P9_DEBUG_VFS, "\n");
	retval = 0;
	old_inode = old_dentry->d_inode;
840
	new_inode = new_dentry->d_inode;
841
842
	v9ses = v9fs_inode2v9ses(old_inode);
	oldfid = v9fs_fid_lookup(old_dentry);
Latchesar Ionkov's avatar
Latchesar Ionkov committed
843
	if (IS_ERR(oldfid))
844
845
846
		return PTR_ERR(oldfid);

	olddirfid = v9fs_fid_clone(old_dentry->d_parent);
Latchesar Ionkov's avatar
Latchesar Ionkov committed
847
	if (IS_ERR(olddirfid)) {
848
		retval = PTR_ERR(olddirfid);
849
		goto done;
850
851
852
	}

	newdirfid = v9fs_fid_clone(new_dentry->d_parent);
Latchesar Ionkov's avatar
Latchesar Ionkov committed
853
	if (IS_ERR(newdirfid)) {
854
		retval = PTR_ERR(newdirfid);
855
		goto clunk_olddir;
856
857
	}

858
	down_write(&v9ses->rename_sem);
859
860
861
862
863
864
	if (v9fs_proto_dotl(v9ses)) {
		retval = p9_client_rename(oldfid, newdirfid,
					(char *) new_dentry->d_name.name);
		if (retval != -ENOSYS)
			goto clunk_newdir;
	}
865
866
867
868
	if (old_dentry->d_parent != new_dentry->d_parent) {
		/*
		 * 9P .u can only handle file rename in the same directory
		 */
869

870
871
		P9_DPRINTK(P9_DEBUG_ERROR,
				"old dir and new dir are different\n");
872
		retval = -EXDEV;
873
		goto clunk_newdir;
874
	}
875
	v9fs_blank_wstat(&wstat);
Latchesar Ionkov's avatar
Latchesar Ionkov committed
876
	wstat.muid = v9ses->uname;
877
	wstat.name = (char *) new_dentry->d_name.name;
878
	retval = p9_client_wstat(oldfid, &wstat);
879

880
clunk_newdir:
881
882
883
884
885
886
	if (!retval) {
		if (new_inode) {
			if (S_ISDIR(new_inode->i_mode))
				clear_nlink(new_inode);
			else
				drop_nlink(new_inode);
887
888
889
890
891
			/*
			 * Work around vfs rename rehash bug with
			 * FS_RENAME_DOES_D_MOVE
			 */
			v9fs_invalidate_inode_attr(new_inode);
892
893
894
895
896
897
		}
		if (S_ISDIR(old_inode->i_mode)) {
			if (!new_inode)
				inc_nlink(new_dir);
			drop_nlink(old_dir);
		}
898
		v9fs_invalidate_inode_attr(old_inode);
899
900
		v9fs_invalidate_inode_attr(old_dir);
		v9fs_invalidate_inode_attr(new_dir);
901

902
903
		/* successful rename */
		d_move(old_dentry, new_dentry);
904
	}
905
	up_write(&v9ses->rename_sem);
906
	p9_client_clunk(newdirfid);
907

908
clunk_olddir:
909
	p9_client_clunk(olddirfid);
910

911
done:
912
913
914
915
	return retval;
}

/**
Adrian Bunk's avatar
Adrian Bunk committed
916
 * v9fs_vfs_getattr - retrieve file metadata
917
918
919
 * @mnt: mount information
 * @dentry: file to get attributes on
 * @stat: metadata structure to populate
920
921
922
923
924
925
926
 *
 */

static int
v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
		 struct kstat *stat)
{
927
928
929
	int err;
	struct v9fs_session_info *v9ses;
	struct p9_fid *fid;
930
	struct p9_wstat *st;
931
932
933
934

	P9_DPRINTK(P9_DEBUG_VFS, "dentry: %p\n", dentry);
	err = -EPERM;
	v9ses = v9fs_inode2v9ses(dentry->d_inode);
935
936
937
938
	if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) {
		generic_fillattr(dentry->d_inode, stat);
		return 0;
	}
939
940
	fid = v9fs_fid_lookup(dentry);
	if (IS_ERR(fid))
941
		return PTR_ERR(fid);
942

943
944
945
	st = p9_client_stat(fid);
	if (IS_ERR(st))
		return PTR_ERR(st);
946

947
	v9fs_stat2inode(st, dentry->d_inode, dentry->d_inode->i_sb);
948
949
		generic_fillattr(dentry->d_inode, stat);

950
	p9stat_free(st);
951
952
	kfree(st);
	return 0;
953
954
955
956
957
958
959
960
961
962
963
}

/**
 * v9fs_vfs_setattr - set file metadata
 * @dentry: file whose metadata to set
 * @iattr: metadata assignment structure
 *
 */

static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
{
964
965
966
967
	int retval;
	struct v9fs_session_info *v9ses;
	struct p9_fid *fid;
	struct p9_wstat wstat;
968

969
970
971
972
	P9_DPRINTK(P9_DEBUG_VFS, "\n");
	retval = -EPERM;
	v9ses = v9fs_inode2v9ses(dentry->d_inode);
	fid = v9fs_fid_lookup(dentry);
973
974
	if(IS_ERR(fid))
		return PTR_ERR(fid);
975

976
	v9fs_blank_wstat(&wstat);
977
	if (iattr->ia_valid & ATTR_MODE)
978
		wstat.mode = unixmode2p9mode(v9ses, iattr->ia_mode);
979
980

	if (iattr->ia_valid & ATTR_MTIME)
981
		wstat.mtime = iattr->ia_mtime.tv_sec;
982
983

	if (iattr->ia_valid & ATTR_ATIME)
984
		wstat.atime = iattr->ia_atime.tv_sec;
985
986

	if (iattr->ia_valid & ATTR_SIZE)
987
		wstat.length = iattr->ia_size;
988

989
	if (v9fs_proto_dotu(v9ses)) {
990
991
		if (iattr->ia_valid & ATTR_UID)
			wstat.n_uid = iattr->ia_uid;
992

993
994
		if (iattr->ia_valid & ATTR_GID)
			wstat.n_gid = iattr->ia_gid;
995
996
	}

997
	retval = p9_client_wstat(fid, &wstat);
Christoph Hellwig's avatar
Christoph Hellwig committed
998
999
	if (retval < 0)
		return retval;
1000

1001
	v9fs_invalidate_inode_attr(dentry->d_inode);
Christoph Hellwig's avatar
Christoph Hellwig committed
1002
1003
1004
1005
1006
1007
	if ((iattr->ia_valid & ATTR_SIZE) &&
	    iattr->ia_size != i_size_read(dentry->d_inode)) {
		retval = vmtruncate(dentry->d_inode, iattr->ia_size);
		if (retval)
			return retval;
	}
1008

Christoph Hellwig's avatar
Christoph Hellwig committed
1009
1010
1011
	setattr_copy(dentry->d_inode, iattr);
	mark_inode_dirty(dentry->d_inode);
	return 0;
1012
1013
1014
}

/**
1015
1016
 * v9fs_stat2inode - populate an inode structure with mistat info
 * @stat: Plan 9 metadata (mistat) structure
1017
1018
1019
1020
1021
1022
 * @inode: inode to populate
 * @sb: superblock of filesystem
 *
 */

void
1023
v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode,
1024
	struct super_block *sb)
1025
{
1026
	char ext[32];
1027
1028
	char tag_name[14];
	unsigned int i_nlink;
1029
	struct v9fs_session_info *v9ses = sb->s_fs_info;
1030
	struct v9fs_inode *v9inode = V9FS_I(inode);
1031
1032
1033

	inode->i_nlink = 1;

1034
1035
1036
	inode->i_atime.tv_sec = stat->atime;
	inode->i_mtime.tv_sec = stat->mtime;
	inode->i_ctime.tv_sec = stat->mtime;
1037

1038
1039
	inode->i_uid = v9ses->dfltuid;
	inode->i_gid = v9ses->dfltgid;
1040