vfs_inode.c 32.9 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
39
#include <net/9p/9p.h>
#include <net/9p/client.h>
40
41
42
43

#include "v9fs.h"
#include "v9fs_vfs.h"
#include "fid.h"
44
#include "cache.h"
45

46
static const struct inode_operations v9fs_dir_inode_operations;
47
48
static const struct inode_operations v9fs_dir_inode_operations_dotu;
static const struct inode_operations v9fs_dir_inode_operations_dotl;
49
static const struct inode_operations v9fs_file_inode_operations;
50
static const struct inode_operations v9fs_file_inode_operations_dotl;
51
static const struct inode_operations v9fs_symlink_inode_operations;
52
static const struct inode_operations v9fs_symlink_inode_operations_dotl;
53
54
55
56
57
58
59
60

/**
 * unixmode2p9mode - convert unix mode bits to plan 9
 * @v9ses: v9fs session information
 * @mode: mode to convert
 *
 */

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

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

	return res;
}

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

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

	res = mode & 0777;

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

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

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

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

	return res;
}

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

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

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

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

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

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

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

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

	return ret;
}

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

183
void
184
v9fs_blank_wstat(struct p9_wstat *wstat)
185
{
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
	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;
203
204
}

205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
#ifdef CONFIG_9P_FSCACHE
/**
 * v9fs_alloc_inode - helper function to allocate an inode
 * This callback is executed before setting up the inode so that we
 * can associate a vcookie with each inode.
 *
 */

struct inode *v9fs_alloc_inode(struct super_block *sb)
{
	struct v9fs_cookie *vcookie;
	vcookie = (struct v9fs_cookie *)kmem_cache_alloc(vcookie_cache,
							 GFP_KERNEL);
	if (!vcookie)
		return NULL;

	vcookie->fscache = NULL;
	vcookie->qid = NULL;
	spin_lock_init(&vcookie->lock);
	return &vcookie->inode;
}

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

void v9fs_destroy_inode(struct inode *inode)
{
	kmem_cache_free(vcookie_cache, v9fs_inode2cookie(inode));
}
#endif

238
239
240
241
242
243
244
245
246
/**
 * 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)
{
247
	int err;
248
	struct inode *inode;
249
	struct v9fs_session_info *v9ses = sb->s_fs_info;
250

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

	inode = new_inode(sb);
254
255
	if (!inode) {
		P9_EPRINTK(KERN_WARNING, "Problem allocating inode\n");
256
		return ERR_PTR(-ENOMEM);
257
258
	}

259
	inode_init_owner(inode, NULL, mode);
260
261
262
263
264
265
266
267
268
269
	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:
270
		if (!v9fs_proto_dotu(v9ses)) {
271
			P9_DPRINTK(P9_DEBUG_ERROR,
272
273
274
				   "special files without extended mode\n");
			err = -EINVAL;
			goto error;
275
		}
276
277
278
		init_special_inode(inode, inode->i_mode, inode->i_rdev);
		break;
	case S_IFREG:
279
280
281
282
283
284
285
286
		if (v9fs_proto_dotl(v9ses)) {
			inode->i_op = &v9fs_file_inode_operations_dotl;
			inode->i_fop = &v9fs_file_operations_dotl;
		} else {
			inode->i_op = &v9fs_file_inode_operations;
			inode->i_fop = &v9fs_file_operations;
		}

287
		break;
288

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

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

302
303
304
		break;
	case S_IFDIR:
		inc_nlink(inode);
305
306
307
308
		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;
309
310
		else
			inode->i_op = &v9fs_dir_inode_operations;
311
312
313
314
315
316

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

317
318
319
320
321
322
		break;
	default:
		P9_DPRINTK(P9_DEBUG_ERROR, "BAD mode 0x%x S_IFMT 0x%x\n",
			   mode, mode & S_IFMT);
		err = -EINVAL;
		goto error;
323
	}
324

325
	return inode;
326
327
328
329

error:
	iput(inode);
	return ERR_PTR(err);
330
331
}

332
/*
333
334
335
336
static struct v9fs_fid*
v9fs_clone_walk(struct v9fs_session_info *v9ses, u32 fid, struct dentry *dentry)
{
	int err;
337
	int nfid;
338
339
340
341
342
	struct v9fs_fid *ret;
	struct v9fs_fcall *fcall;

	nfid = v9fs_get_idpool(&v9ses->fidpool);
	if (nfid < 0) {
343
		eprintk(KERN_WARNING, "no free fids available\n");
344
		return ERR_PTR(-ENOSPC);
345
346
	}

347
348
349
350
	err = v9fs_t_walk(v9ses, fid, nfid, (char *) dentry->d_name.name,
		&fcall);

	if (err < 0) {
351
352
353
		if (fcall && fcall->id == RWALK)
			goto clunk_fid;

354
355
356
		PRINT_FCALL_ERROR("walk error", fcall);
		v9fs_put_idpool(nfid, &v9ses->fidpool);
		goto error;
357
	}
358

359
360
	kfree(fcall);
	fcall = NULL;
361
362
363
364
365
	ret = v9fs_fid_create(v9ses, nfid);
	if (!ret) {
		err = -ENOMEM;
		goto clunk_fid;
	}
366

367
368
369
370
	err = v9fs_fid_insert(ret, dentry);
	if (err < 0) {
		v9fs_fid_destroy(ret);
		goto clunk_fid;
371
	}
372

373
	return ret;
374

375
376
clunk_fid:
	v9fs_t_clunk(v9ses, nfid);
377

378
379
380
381
error:
	kfree(fcall);
	return ERR_PTR(err);
}
382
*/
383

384
385
386
387
388
389
390
391
392
393
394
395
396
397
398

/**
 * v9fs_clear_inode - release an inode
 * @inode: inode to release
 *
 */
void v9fs_clear_inode(struct inode *inode)
{
	filemap_fdatawrite(inode->i_mapping);

#ifdef CONFIG_9P_FSCACHE
	v9fs_cache_inode_put_cookie(inode);
#endif
}

399
static struct inode *
400
v9fs_inode(struct v9fs_session_info *v9ses, struct p9_fid *fid,
401
402
403
	struct super_block *sb)
{
	int err, umode;
404
	struct inode *ret = NULL;
405
	struct p9_wstat *st;
406

407
	st = p9_client_stat(fid);
408
409
	if (IS_ERR(st))
		return ERR_CAST(st);
410

411
	umode = p9mode2unixmode(v9ses, st->mode);
412
413
414
415
416
	ret = v9fs_get_inode(sb, umode);
	if (IS_ERR(ret)) {
		err = PTR_ERR(ret);
		goto error;
	}
417

418
419
	v9fs_stat2inode(st, ret, sb);
	ret->i_ino = v9fs_qid2ino(&st->qid);
420
421
422
423
424

#ifdef CONFIG_9P_FSCACHE
	v9fs_vcookie_set_qid(ret, &st->qid);
	v9fs_cache_inode_get_cookie(ret);
#endif
425
	p9stat_free(st);
426
	kfree(st);
427
428
	return ret;
error:
429
	p9stat_free(st);
430
	kfree(st);
431
	return ERR_PTR(err);
432
433
}

434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
static struct inode *
v9fs_inode_dotl(struct v9fs_session_info *v9ses, struct p9_fid *fid,
	struct super_block *sb)
{
	struct inode *ret = NULL;
	int err;
	struct p9_stat_dotl *st;

	st = p9_client_getattr_dotl(fid, P9_STATS_BASIC);
	if (IS_ERR(st))
		return ERR_CAST(st);

	ret = v9fs_get_inode(sb, st->st_mode);
	if (IS_ERR(ret)) {
		err = PTR_ERR(ret);
		goto error;
	}

	v9fs_stat2inode_dotl(st, ret);
	ret->i_ino = v9fs_qid2ino(&st->qid);
#ifdef CONFIG_9P_FSCACHE
	v9fs_vcookie_set_qid(ret, &st->qid);
	v9fs_cache_inode_get_cookie(ret);
#endif
	kfree(st);
	return ret;
error:
	kfree(st);
	return ERR_PTR(err);
}

/**
 * v9fs_inode_from_fid - Helper routine to populate an inode by
 * issuing a attribute request
 * @v9ses: session information
 * @fid: fid to issue attribute request for
 * @sb: superblock on which to create inode
 *
 */
static inline struct inode *
v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid,
			struct super_block *sb)
{
	if (v9fs_proto_dotl(v9ses))
		return v9fs_inode_dotl(v9ses, fid, sb);
	else
		return v9fs_inode(v9ses, fid, sb);
}

483
484
/**
 * v9fs_remove - helper function to remove files and directories
485
486
487
 * @dir: directory inode that is being deleted
 * @file:  dentry that is being deleted
 * @rmdir: removing a directory
488
489
490
491
492
 *
 */

static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir)
{
Aneesh Kumar K.V's avatar
Aneesh Kumar K.V committed
493
	int retval;
494
495
	struct inode *file_inode;
	struct p9_fid *v9fid;
496

497
	P9_DPRINTK(P9_DEBUG_VFS, "inode: %p dentry: %p rmdir: %d\n", dir, file,
498
499
500
		rmdir);

	file_inode = file->d_inode;
501
	v9fid = v9fs_fid_clone(file);
Latchesar Ionkov's avatar
Latchesar Ionkov committed
502
	if (IS_ERR(v9fid))
503
		return PTR_ERR(v9fid);
504

Aneesh Kumar K.V's avatar
Aneesh Kumar K.V committed
505
506
507
508
	retval = p9_client_remove(v9fid);
	if (!retval)
		drop_nlink(file_inode);
	return retval;
509
510
}

511
512
513
514
515
516
static int
v9fs_open_created(struct inode *inode, struct file *file)
{
	return 0;
}

517

518
/**
519
 * v9fs_create - Create a file
520
521
 * @v9ses: session information
 * @dir: directory that dentry is being created in
522
 * @dentry:  dentry that is being created
Abhishek Kulkarni's avatar
Abhishek Kulkarni committed
523
 * @extension: 9p2000.u extension string to support devices, etc.
524
525
 * @perm: create permissions
 * @mode: open mode
526
527
 *
 */
528
529
530
static struct p9_fid *
v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,
		struct dentry *dentry, char *extension, u32 perm, u8 mode)
531
{
532
	int err;
533
534
	char *name;
	struct p9_fid *dfid, *ofid, *fid;
535
536
	struct inode *inode;

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

539
540
541
542
	err = 0;
	ofid = NULL;
	fid = NULL;
	name = (char *) dentry->d_name.name;
543
	dfid = v9fs_fid_lookup(dentry->d_parent);
Latchesar Ionkov's avatar
Latchesar Ionkov committed
544
	if (IS_ERR(dfid)) {
545
		err = PTR_ERR(dfid);
546
547
		P9_DPRINTK(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
		return ERR_PTR(err);
548
	}
549

550
551
552
553
	/* clone a fid to use for creation */
	ofid = p9_client_walk(dfid, 0, NULL, 1);
	if (IS_ERR(ofid)) {
		err = PTR_ERR(ofid);
554
		P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err);
555
		return ERR_PTR(err);
556
	}
557

558
	err = p9_client_fcreate(ofid, name, perm, mode, extension);
559
560
	if (err < 0) {
		P9_DPRINTK(P9_DEBUG_VFS, "p9_client_fcreate failed %d\n", err);
561
		goto error;
562
	}
563

564
	/* now walk from the parent so we can get unopened fid */
565
	fid = p9_client_walk(dfid, 1, &name, 1);
566
567
	if (IS_ERR(fid)) {
		err = PTR_ERR(fid);
568
		P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err);
569
		fid = NULL;
570
		goto error;
571
	}
572

573
574
	/* instantiate inode and assign the unopened fid to the dentry */
	inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb);
575
576
	if (IS_ERR(inode)) {
		err = PTR_ERR(inode);
577
		P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", err);
578
579
580
		goto error;
	}

Latchesar Ionkov's avatar
Latchesar Ionkov committed
581
	if (v9ses->cache)
582
583
584
		dentry->d_op = &v9fs_cached_dentry_operations;
	else
		dentry->d_op = &v9fs_dentry_operations;
585

586
	d_instantiate(dentry, inode);
587
588
589
590
	err = v9fs_fid_add(dentry, fid);
	if (err < 0)
		goto error;

591
	return ofid;
592

593
594
595
596
597
598
599
600
601
602
603
604
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
605
 * @dir: directory inode that is being created
606
607
608
609
610
 * @dentry:  dentry that is being deleted
 * @mode: create permissions
 * @nd: path information
 *
 */
611

612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
static int
v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode,
		struct nameidata *nd)
{
	int err;
	u32 perm;
	int flags;
	struct v9fs_session_info *v9ses;
	struct p9_fid *fid;
	struct file *filp;

	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,
633
634
				v9fs_uflags2omode(flags,
						v9fs_proto_dotu(v9ses)));
635
636
637
638
639
640
641
642
	if (IS_ERR(fid)) {
		err = PTR_ERR(fid);
		fid = NULL;
		goto error;
	}

	/* if we are opening a file, assign the open fid to the file */
	if (nd && nd->flags & LOOKUP_OPEN) {
643
644
		filp = lookup_instantiate_filp(nd, dentry, v9fs_open_created);
		if (IS_ERR(filp)) {
645
646
			err = PTR_ERR(filp);
			goto error;
647
648
		}

649
650
651
		filp->private_data = fid;
	} else
		p9_client_clunk(fid);
652
653
654
655

	return 0;

error:
656
657
	if (fid)
		p9_client_clunk(fid);
658
659

	return err;
660
661
662
663
}

/**
 * v9fs_vfs_mkdir - VFS mkdir hook to create a directory
664
 * @dir:  inode that is being unlinked
665
666
667
668
669
 * @dentry: dentry that is being unlinked
 * @mode: mode for new directory
 *
 */

670
static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
671
{
672
	int err;
673
	u32 perm;
674
	struct v9fs_session_info *v9ses;
675
	struct p9_fid *fid;
676

677
678
	P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", dentry->d_name.name);
	err = 0;
679
680
	v9ses = v9fs_inode2v9ses(dir);
	perm = unixmode2p9mode(v9ses, mode | S_IFDIR);
681
682
683
684
	fid = v9fs_create(v9ses, dir, dentry, NULL, perm, P9_OREAD);
	if (IS_ERR(fid)) {
		err = PTR_ERR(fid);
		fid = NULL;
685
686
	}

687
688
	if (fid)
		p9_client_clunk(fid);
689
690

	return err;
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
}

/**
 * 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
 *
 */

static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
				      struct nameidata *nameidata)
{
	struct super_block *sb;
	struct v9fs_session_info *v9ses;
706
	struct p9_fid *dfid, *fid;
707
	struct inode *inode;
708
	char *name;
709
710
	int result = 0;

711
	P9_DPRINTK(P9_DEBUG_VFS, "dir: %p dentry: (%s) %p nameidata: %p\n",
712
		dir, dentry->d_name.name, dentry, nameidata);
713

714
715
716
	if (dentry->d_name.len > NAME_MAX)
		return ERR_PTR(-ENAMETOOLONG);

717
718
	sb = dir->i_sb;
	v9ses = v9fs_inode2v9ses(dir);
719
720
	dfid = v9fs_fid_lookup(dentry->d_parent);
	if (IS_ERR(dfid))
721
		return ERR_CAST(dfid);
722
723
724
725
726

	name = (char *) dentry->d_name.name;
	fid = p9_client_walk(dfid, 1, &name, 1);
	if (IS_ERR(fid)) {
		result = PTR_ERR(fid);
727
		if (result == -ENOENT) {
728
729
			inode = NULL;
			goto inst_out;
730
731
		}

732
		return ERR_PTR(result);
733
734
	}

735
736
737
738
739
	inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb);
	if (IS_ERR(inode)) {
		result = PTR_ERR(inode);
		inode = NULL;
		goto error;
740
741
	}

742
	result = v9fs_fid_add(dentry, fid);
743
	if (result < 0)
744
		goto error;
745

746
747
inst_out:
	if (v9ses->cache)
748
749
750
		dentry->d_op = &v9fs_cached_dentry_operations;
	else
		dentry->d_op = &v9fs_dentry_operations;
751
752
753
754

	d_add(dentry, inode);
	return NULL;

755
error:
756
	p9_client_clunk(fid);
757

758
759
760
761
762
763
	return ERR_PTR(result);
}

/**
 * v9fs_vfs_unlink - VFS unlink hook to delete an inode
 * @i:  inode that is being unlinked
764
 * @d: dentry that is being unlinked
765
766
767
768
769
770
771
772
773
774
775
 *
 */

static int v9fs_vfs_unlink(struct inode *i, struct dentry *d)
{
	return v9fs_remove(i, d, 0);
}

/**
 * v9fs_vfs_rmdir - VFS unlink hook to delete a directory
 * @i:  inode that is being unlinked
776
 * @d: dentry that is being unlinked
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
 *
 */

static int v9fs_vfs_rmdir(struct inode *i, struct dentry *d)
{
	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
 *
 */

static int
v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
		struct inode *new_dir, struct dentry *new_dentry)
{
798
799
800
801
802
803
804
	struct inode *old_inode;
	struct v9fs_session_info *v9ses;
	struct p9_fid *oldfid;
	struct p9_fid *olddirfid;
	struct p9_fid *newdirfid;
	struct p9_wstat wstat;
	int retval;
805

806
807
808
809
810
	P9_DPRINTK(P9_DEBUG_VFS, "\n");
	retval = 0;
	old_inode = old_dentry->d_inode;
	v9ses = v9fs_inode2v9ses(old_inode);
	oldfid = v9fs_fid_lookup(old_dentry);
Latchesar Ionkov's avatar
Latchesar Ionkov committed
811
	if (IS_ERR(oldfid))
812
813
814
		return PTR_ERR(oldfid);

	olddirfid = v9fs_fid_clone(old_dentry->d_parent);
Latchesar Ionkov's avatar
Latchesar Ionkov committed
815
	if (IS_ERR(olddirfid)) {
816
		retval = PTR_ERR(olddirfid);
817
		goto done;
818
819
820
	}

	newdirfid = v9fs_fid_clone(new_dentry->d_parent);
Latchesar Ionkov's avatar
Latchesar Ionkov committed
821
	if (IS_ERR(newdirfid)) {
822
		retval = PTR_ERR(newdirfid);
823
		goto clunk_olddir;
824
825
	}

826
827
828
829
830
831
832
	if (v9fs_proto_dotl(v9ses)) {
		retval = p9_client_rename(oldfid, newdirfid,
					(char *) new_dentry->d_name.name);
		if (retval != -ENOSYS)
			goto clunk_newdir;
	}

833
834
	/* 9P can only handle file rename in the same directory */
	if (memcmp(&olddirfid->qid, &newdirfid->qid, sizeof(newdirfid->qid))) {
835
836
		P9_DPRINTK(P9_DEBUG_ERROR,
				"old dir and new dir are different\n");
837
		retval = -EXDEV;
838
		goto clunk_newdir;
839
840
	}

841
	v9fs_blank_wstat(&wstat);
Latchesar Ionkov's avatar
Latchesar Ionkov committed
842
	wstat.muid = v9ses->uname;
843
	wstat.name = (char *) new_dentry->d_name.name;
844
	retval = p9_client_wstat(oldfid, &wstat);
845

846
clunk_newdir:
847
	p9_client_clunk(newdirfid);
848

849
clunk_olddir:
850
	p9_client_clunk(olddirfid);
851

852
done:
853
854
855
856
	return retval;
}

/**
Adrian Bunk's avatar
Adrian Bunk committed
857
 * v9fs_vfs_getattr - retrieve file metadata
858
859
860
 * @mnt: mount information
 * @dentry: file to get attributes on
 * @stat: metadata structure to populate
861
862
863
864
865
866
867
 *
 */

static int
v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
		 struct kstat *stat)
{
868
869
870
	int err;
	struct v9fs_session_info *v9ses;
	struct p9_fid *fid;
871
	struct p9_wstat *st;
872
873
874
875

	P9_DPRINTK(P9_DEBUG_VFS, "dentry: %p\n", dentry);
	err = -EPERM;
	v9ses = v9fs_inode2v9ses(dentry->d_inode);
876
	if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE)
877
878
		return simple_getattr(mnt, dentry, stat);

879
880
	fid = v9fs_fid_lookup(dentry);
	if (IS_ERR(fid))
881
		return PTR_ERR(fid);
882

883
884
885
	st = p9_client_stat(fid);
	if (IS_ERR(st))
		return PTR_ERR(st);
886

887
	v9fs_stat2inode(st, dentry->d_inode, dentry->d_inode->i_sb);
888
889
		generic_fillattr(dentry->d_inode, stat);

890
891
	kfree(st);
	return 0;
892
893
}

894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
static int
v9fs_vfs_getattr_dotl(struct vfsmount *mnt, struct dentry *dentry,
		 struct kstat *stat)
{
	int err;
	struct v9fs_session_info *v9ses;
	struct p9_fid *fid;
	struct p9_stat_dotl *st;

	P9_DPRINTK(P9_DEBUG_VFS, "dentry: %p\n", dentry);
	err = -EPERM;
	v9ses = v9fs_inode2v9ses(dentry->d_inode);
	if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE)
		return simple_getattr(mnt, dentry, stat);

	fid = v9fs_fid_lookup(dentry);
	if (IS_ERR(fid))
		return PTR_ERR(fid);

	/* Ask for all the fields in stat structure. Server will return
	 * whatever it supports
	 */

	st = p9_client_getattr_dotl(fid, P9_STATS_ALL);
	if (IS_ERR(st))
		return PTR_ERR(st);

	v9fs_stat2inode_dotl(st, dentry->d_inode);
	generic_fillattr(dentry->d_inode, stat);
	/* Change block size to what the server returned */
	stat->blksize = st->st_blksize;

	kfree(st);
	return 0;
}

930
931
932
933
934
935
936
937
938
/**
 * 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)
{
939
940
941
942
	int retval;
	struct v9fs_session_info *v9ses;
	struct p9_fid *fid;
	struct p9_wstat wstat;
943

944
945
946
947
	P9_DPRINTK(P9_DEBUG_VFS, "\n");
	retval = -EPERM;
	v9ses = v9fs_inode2v9ses(dentry->d_inode);
	fid = v9fs_fid_lookup(dentry);
948
949
	if(IS_ERR(fid))
		return PTR_ERR(fid);
950

951
	v9fs_blank_wstat(&wstat);
952
	if (iattr->ia_valid & ATTR_MODE)
953
		wstat.mode = unixmode2p9mode(v9ses, iattr->ia_mode);
954
955

	if (iattr->ia_valid & ATTR_MTIME)
956
		wstat.mtime = iattr->ia_mtime.tv_sec;
957
958

	if (iattr->ia_valid & ATTR_ATIME)
959
		wstat.atime = iattr->ia_atime.tv_sec;
960
961

	if (iattr->ia_valid & ATTR_SIZE)
962
		wstat.length = iattr->ia_size;
963

964
	if (v9fs_proto_dotu(v9ses)) {
965
966
		if (iattr->ia_valid & ATTR_UID)
			wstat.n_uid = iattr->ia_uid;
967

968
969
		if (iattr->ia_valid & ATTR_GID)
			wstat.n_gid = iattr->ia_gid;
970
971
	}

972
973
974
	retval = p9_client_wstat(fid, &wstat);
	if (retval >= 0)
		retval = inode_setattr(dentry->d_inode, iattr);
975

976
	return retval;
977
978
}

979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
/**
 * v9fs_vfs_setattr_dotl - set file metadata
 * @dentry: file whose metadata to set
 * @iattr: metadata assignment structure
 *
 */

static int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr)
{
	int retval;
	struct v9fs_session_info *v9ses;
	struct p9_fid *fid;
	struct p9_iattr_dotl p9attr;

	P9_DPRINTK(P9_DEBUG_VFS, "\n");

	retval = inode_change_ok(dentry->d_inode, iattr);
	if (retval)
		return retval;

	p9attr.valid = iattr->ia_valid;
	p9attr.mode = iattr->ia_mode;
	p9attr.uid = iattr->ia_uid;
	p9attr.gid = iattr->ia_gid;
	p9attr.size = iattr->ia_size;
	p9attr.atime_sec = iattr->ia_atime.tv_sec;
	p9attr.atime_nsec = iattr->ia_atime.tv_nsec;
	p9attr.mtime_sec = iattr->ia_mtime.tv_sec;
	p9attr.mtime_nsec = iattr->ia_mtime.tv_nsec;

	retval = -EPERM;
	v9ses = v9fs_inode2v9ses(dentry->d_inode);
	fid = v9fs_fid_lookup(dentry);
	if (IS_ERR(fid))
		return PTR_ERR(fid);

	retval = p9_client_setattr(fid, &p9attr);
	if (retval >= 0)
		retval = inode_setattr(dentry->d_inode, iattr);

	return retval;
}

1022
/**
1023
1024
 * v9fs_stat2inode - populate an inode structure with mistat info
 * @stat: Plan 9 metadata (mistat) structure
1025
1026
1027
1028
1029
1030
 * @inode: inode to populate
 * @sb: superblock of filesystem
 *
 */

void
1031
v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode,
1032
	struct super_block *sb)
1033
{
1034
	char ext[32];
1035
1036
	char tag_name[14];
	unsigned int i_nlink;
1037
1038
1039
1040
	struct v9fs_session_info *v9ses = sb->s_fs_info;

	inode->i_nlink = 1;

1041
1042
1043
	inode->i_atime.tv_sec = stat->atime;
	inode->i_mtime.tv_sec = stat->mtime;
	inode->i_ctime.tv_sec = stat->mtime;
1044

1045
1046
	inode->i_uid = v9ses->dfltuid;
	inode->i_gid = v9ses->dfltgid;
1047

1048
	if (v9fs_proto_dotu(v9ses)) {
1049
1050
		inode->i_uid = stat->n_uid;
		inode->i_gid = stat->n_gid;
1051
	}
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
	if ((S_ISREG(inode->i_mode)) || (S_ISDIR(inode->i_mode))) {
		if (v9fs_proto_dotu(v9ses) && (stat->extension[0] != '\0')) {
			/*
			 * Hadlink support got added later to
			 * to the .u extension. So there can be
			 * server out there that doesn't support
			 * this even with .u extension. So check
			 * for non NULL stat->extension
			 */
			strncpy(ext, stat->extension, sizeof(ext));
			/* HARDLINKCOUNT %u */
			sscanf(ext, "%13s %u", tag_name, &i_nlink);
			if (!strncmp(tag_name, "HARDLINKCOUNT", 13))
				inode->i_nlink = i_nlink;
		}
	}
1068
	inode->i_mode = p9mode2unixmode(v9ses, stat->mode);
1069
1070
1071
1072
	if ((S_ISBLK(inode->i_mode)) || (S_ISCHR(inode->i_mode))) {
		char type = 0;
		int major = -1;
		int minor = -1;
1073

1074
		strncpy(ext, stat->extension, sizeof(ext));
1075
		sscanf(ext, "%c %u %u", &type, &major, &minor);
1076
1077
1078
1079
1080
1081
1082
1083
		switch (type) {
		case 'c':
			inode->i_mode &= ~S_IFBLK;
			inode->i_mode |= S_IFCHR;
			break;
		case 'b':
			break;
		default:
1084
			P9_DPRINTK(P9_DEBUG_ERROR,
1085
1086
				"Unknown special type %c %s\n", type,
				stat->extension);
1087
1088
		};
		inode->i_rdev = MKDEV(major, minor);
1089
		init_special_inode(inode, inode->i_mode, inode->i_rdev);
1090
1091
1092
	} else
		inode->i_rdev = 0;

1093
	i_size_write(inode, stat->length);
1094

1095
	/* not real number of blocks, but 512 byte ones ... */
1096
	inode->i_blocks = (i_size_read(inode) + 512 - 1) >> 9;
1097
1098
}

1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
/**
 * v9fs_stat2inode_dotl - populate an inode structure with stat info
 * @stat: stat structure
 * @inode: inode to populate
 * @sb: superblock of filesystem
 *
 */

void
v9fs_stat2inode_dotl(struct p9_stat_dotl *stat, struct inode *inode)
{

	if ((stat->st_result_mask & P9_STATS_BASIC) == P9_STATS_BASIC) {
		inode->i_atime.tv_sec = stat->st_atime_sec;
		inode->i_atime.tv_nsec = stat->st_atime_nsec;
		inode->i_mtime.tv_sec = stat->st_mtime_sec;
		inode->i_mtime.tv_nsec = stat->st_mtime_nsec;
		inode->i_ctime.tv_sec = stat->st_ctime_sec;
		inode->i_ctime.tv_nsec = stat->st_ctime_nsec;
		inode->i_uid = stat->st_uid;
		inode->i_gid = stat->st_gid;
		inode->i_nlink = stat->st_nlink;
		inode->i_mode = stat->st_mode;
		inode->i_rdev = new_decode_dev(stat->st_rdev);

		if ((S_ISBLK(inode->i_mode)) || (S_ISCHR(inode->i_mode)))
			init_special_inode(inode, inode->i_mode, inode->i_rdev);

		i_size_write(inode, stat->st_size);
		inode->i_blocks = stat->st_blocks;
	} else {
		if (stat->st_result_mask & P9_STATS_ATIME) {
			inode->i_atime.tv_sec = stat->st_atime_sec;
			inode->i_atime.tv_nsec = stat->st_atime_nsec;
		}
		if (stat->st_result_mask & P9_STATS_MTIME) {
			inode->i_mtime.tv_sec = stat->st_mtime_sec;
			inode->i_mtime.tv_nsec = stat->st_mtime_nsec;
		}
		if (stat->st_result_mask & P9_STATS_CTIME) {
			inode->i_ctime.tv_sec = stat->st_ctime_sec;
			inode->i_ctime.tv_nsec = stat->st_ctime_nsec;
		}
		if (stat->st_result_mask & P9_STATS_UID)
			inode->i_uid = stat->st_uid;
		if (stat->st_result_mask & P9_STATS_GID)
			inode->i_gid = stat->st_gid;
		if (stat->st_result_mask & P9_STATS_NLINK)
			inode->i_nlink = stat->st_nlink;
		if (stat->st_result_mask & P9_STATS_MODE) {
			inode->i_mode = stat->st_mode;
			if ((S_ISBLK(inode->i_mode)) ||
						(S_ISCHR(inode->i_mode)))
				init_special_inode(inode, inode->i_mode,
								inode->i_rdev);
		}
		if (stat->st_result_mask & P9_STATS_RDEV)
			inode->i_rdev = new_decode_dev(stat->st_rdev);
		if (stat->st_result_mask & P9_STATS_SIZE)
			i_size_write(inode, stat->st_size);
		if (stat->st_result_mask & P9_STATS_BLOCKS)
			inode->i_blocks = stat->st_blocks;
	}
	if (stat->st_result_mask & P9_STATS_GEN)
			inode->i_generation = stat->st_gen;

	/* Currently we don't support P9_STATS_BTIME and P9_STATS_DATA_VERSION
	 * because the inode structure does not have fields for them.
	 */
}

1170
1171
1172
1173
1174
1175
1176
/**
 * v9fs_qid2ino - convert qid into inode number
 * @qid: qid to hash
 *
 * BUG: potential for inode number collisions?
 */

1177
ino_t v9fs_qid2ino(struct p9_qid *qid)
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
{
	u64 path = qid->path + 2;
	ino_t i = 0;

	if (sizeof(ino_t) == sizeof(path))
		memcpy(&i, &path, sizeof(ino_t));
	else
		i = (ino_t) (path ^ (path >> 32));

	return i;
}

/**
 * v9fs_readlink - read a symlink's location (internal version)
 * @dentry: dentry for symlink
1193
 * @buffer: buffer to load symlink location into
1194
1195
1196
1197
1198
1199
 * @buflen: length of buffer
 *
 */

static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen)
{
1200
	int retval;
1201

1202
1203
	struct v9fs_session_info *v9ses;
	struct p9_fid *fid;
1204
	struct p9_wstat *st;
1205