hostfs_kern.c 20.4 KB
Newer Older
L
Linus Torvalds 已提交
1
/*
J
Jeff Dike 已提交
2
 * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
L
Linus Torvalds 已提交
3 4 5 6 7 8 9 10
 * Licensed under the GPL
 *
 * Ported the filesystem routines to 2.5.
 * 2003-02-10 Petr Baudis <pasky@ucw.cz>
 */

#include <linux/fs.h>
#include <linux/module.h>
J
Jeff Dike 已提交
11
#include <linux/mm.h>
L
Linus Torvalds 已提交
12 13
#include <linux/pagemap.h>
#include <linux/statfs.h>
14
#include <linux/slab.h>
M
Miklos Szeredi 已提交
15
#include <linux/seq_file.h>
J
Jiri Kosina 已提交
16
#include <linux/mount.h>
A
Al Viro 已提交
17
#include <linux/namei.h>
L
Linus Torvalds 已提交
18 19
#include "hostfs.h"
#include "init.h"
J
Jeff Dike 已提交
20
#include "kern.h"
L
Linus Torvalds 已提交
21 22 23

struct hostfs_inode_info {
	int fd;
24
	fmode_t mode;
L
Linus Torvalds 已提交
25 26 27 28 29
	struct inode vfs_inode;
};

static inline struct hostfs_inode_info *HOSTFS_I(struct inode *inode)
{
J
Jeff Dike 已提交
30
	return list_entry(inode, struct hostfs_inode_info, vfs_inode);
L
Linus Torvalds 已提交
31 32
}

J
Josef Sipek 已提交
33
#define FILE_HOSTFS_I(file) HOSTFS_I((file)->f_path.dentry->d_inode)
L
Linus Torvalds 已提交
34

35
static int hostfs_d_delete(struct dentry *dentry)
L
Linus Torvalds 已提交
36
{
J
Jeff Dike 已提交
37
	return 1;
L
Linus Torvalds 已提交
38 39
}

40
static const struct dentry_operations hostfs_dentry_ops = {
L
Linus Torvalds 已提交
41 42 43 44
	.d_delete		= hostfs_d_delete,
};

/* Changed in hostfs_args before the kernel starts running */
45
static char *root_ino = "";
L
Linus Torvalds 已提交
46 47 48 49
static int append = 0;

#define HOSTFS_SUPER_MAGIC 0x00c0ffee

50 51
static const struct inode_operations hostfs_iops;
static const struct inode_operations hostfs_dir_iops;
A
Al Viro 已提交
52
static const struct inode_operations hostfs_link_iops;
L
Linus Torvalds 已提交
53 54 55 56 57 58 59

#ifndef MODULE
static int __init hostfs_args(char *options, int *add)
{
	char *ptr;

	ptr = strchr(options, ',');
J
Jeff Dike 已提交
60
	if (ptr != NULL)
L
Linus Torvalds 已提交
61
		*ptr++ = '\0';
J
Jeff Dike 已提交
62
	if (*options != '\0')
L
Linus Torvalds 已提交
63 64 65
		root_ino = options;

	options = ptr;
J
Jeff Dike 已提交
66
	while (options) {
L
Linus Torvalds 已提交
67
		ptr = strchr(options, ',');
J
Jeff Dike 已提交
68
		if (ptr != NULL)
L
Linus Torvalds 已提交
69
			*ptr++ = '\0';
J
Jeff Dike 已提交
70 71
		if (*options != '\0') {
			if (!strcmp(options, "append"))
L
Linus Torvalds 已提交
72 73 74 75 76 77
				append = 1;
			else printf("hostfs_args - unsupported option - %s\n",
				    options);
		}
		options = ptr;
	}
J
Jeff Dike 已提交
78
	return 0;
L
Linus Torvalds 已提交
79 80 81 82 83 84 85 86 87 88 89 90 91 92
}

__uml_setup("hostfs=", hostfs_args,
"hostfs=<root dir>,<flags>,...\n"
"    This is used to set hostfs parameters.  The root directory argument\n"
"    is used to confine all hostfs mounts to within the specified directory\n"
"    tree on the host.  If this isn't specified, then a user inside UML can\n"
"    mount anything on the host that's accessible to the user that's running\n"
"    it.\n"
"    The only flag currently supported is 'append', which specifies that all\n"
"    files opened by hostfs will be opened in append mode.\n\n"
);
#endif

93
static char *__dentry_name(struct dentry *dentry, char *name)
L
Linus Torvalds 已提交
94
{
95 96 97
	char *p = __dentry_path(dentry, name, PATH_MAX);
	char *root;
	size_t len;
L
Linus Torvalds 已提交
98

99
	spin_unlock(&dcache_lock);
L
Linus Torvalds 已提交
100

101 102 103 104
	root = dentry->d_sb->s_fs_info;
	len = strlen(root);
	if (IS_ERR(p)) {
		__putname(name);
J
Jeff Dike 已提交
105
		return NULL;
L
Linus Torvalds 已提交
106
	}
107
	strlcpy(name, root, PATH_MAX);
108 109 110 111 112 113 114 115 116
	if (len > p - name) {
		__putname(name);
		return NULL;
	}
	if (p > name + len) {
		char *s = name + len;
		while ((*s++ = *p++) != '\0')
			;
	}
J
Jeff Dike 已提交
117
	return name;
L
Linus Torvalds 已提交
118 119
}

120 121 122 123 124 125 126 127 128 129
static char *dentry_name(struct dentry *dentry)
{
	char *name = __getname();
	if (!name)
		return NULL;

	spin_lock(&dcache_lock);
	return __dentry_name(dentry, name); /* will unlock */
}

A
Al Viro 已提交
130
static char *inode_name(struct inode *ino)
L
Linus Torvalds 已提交
131 132
{
	struct dentry *dentry;
133 134 135
	char *name = __getname();
	if (!name)
		return NULL;
L
Linus Torvalds 已提交
136

137 138 139 140 141 142 143 144
	spin_lock(&dcache_lock);
	if (list_empty(&ino->i_dentry)) {
		spin_unlock(&dcache_lock);
		__putname(name);
		return NULL;
	}
	dentry = list_first_entry(&ino->i_dentry, struct dentry, d_alias);
	return __dentry_name(dentry, name); /* will unlock */
L
Linus Torvalds 已提交
145 146 147 148 149 150 151 152
}

static char *follow_link(char *link)
{
	int len, n;
	char *name, *resolved, *end;

	len = 64;
J
Jeff Dike 已提交
153
	while (1) {
L
Linus Torvalds 已提交
154 155
		n = -ENOMEM;
		name = kmalloc(len, GFP_KERNEL);
J
Jeff Dike 已提交
156
		if (name == NULL)
L
Linus Torvalds 已提交
157 158
			goto out;

159
		n = hostfs_do_readlink(link, name, len);
J
Jeff Dike 已提交
160
		if (n < len)
L
Linus Torvalds 已提交
161 162 163 164
			break;
		len *= 2;
		kfree(name);
	}
J
Jeff Dike 已提交
165
	if (n < 0)
L
Linus Torvalds 已提交
166 167
		goto out_free;

J
Jeff Dike 已提交
168
	if (*name == '/')
J
Jeff Dike 已提交
169
		return name;
L
Linus Torvalds 已提交
170 171

	end = strrchr(link, '/');
J
Jeff Dike 已提交
172
	if (end == NULL)
J
Jeff Dike 已提交
173
		return name;
L
Linus Torvalds 已提交
174 175 176 177 178

	*(end + 1) = '\0';
	len = strlen(link) + strlen(name) + 1;

	resolved = kmalloc(len, GFP_KERNEL);
J
Jeff Dike 已提交
179
	if (resolved == NULL) {
L
Linus Torvalds 已提交
180 181 182 183 184 185 186
		n = -ENOMEM;
		goto out_free;
	}

	sprintf(resolved, "%s%s", link, name);
	kfree(name);
	kfree(link);
J
Jeff Dike 已提交
187
	return resolved;
L
Linus Torvalds 已提交
188 189 190 191

 out_free:
	kfree(name);
 out:
J
Jeff Dike 已提交
192
	return ERR_PTR(n);
L
Linus Torvalds 已提交
193 194
}

195 196
static struct inode *hostfs_iget(struct super_block *sb)
{
A
Al Viro 已提交
197
	struct inode *inode = new_inode(sb);
198 199 200 201 202
	if (!inode)
		return ERR_PTR(-ENOMEM);
	return inode;
}

203
int hostfs_statfs(struct dentry *dentry, struct kstatfs *sf)
L
Linus Torvalds 已提交
204
{
J
Jeff Dike 已提交
205 206
	/*
	 * do_statfs uses struct statfs64 internally, but the linux kernel
L
Linus Torvalds 已提交
207 208 209 210 211 212 213 214 215 216
	 * struct statfs still has 32-bit versions for most of these fields,
	 * so we convert them here
	 */
	int err;
	long long f_blocks;
	long long f_bfree;
	long long f_bavail;
	long long f_files;
	long long f_ffree;

217
	err = do_statfs(dentry->d_sb->s_fs_info,
L
Linus Torvalds 已提交
218 219 220
			&sf->f_bsize, &f_blocks, &f_bfree, &f_bavail, &f_files,
			&f_ffree, &sf->f_fsid, sizeof(sf->f_fsid),
			&sf->f_namelen, sf->f_spare);
J
Jeff Dike 已提交
221
	if (err)
J
Jeff Dike 已提交
222
		return err;
L
Linus Torvalds 已提交
223 224 225 226 227 228
	sf->f_blocks = f_blocks;
	sf->f_bfree = f_bfree;
	sf->f_bavail = f_bavail;
	sf->f_files = f_files;
	sf->f_ffree = f_ffree;
	sf->f_type = HOSTFS_SUPER_MAGIC;
J
Jeff Dike 已提交
229
	return 0;
L
Linus Torvalds 已提交
230 231 232 233 234 235
}

static struct inode *hostfs_alloc_inode(struct super_block *sb)
{
	struct hostfs_inode_info *hi;

236
	hi = kzalloc(sizeof(*hi), GFP_KERNEL);
J
Jeff Dike 已提交
237
	if (hi == NULL)
J
Jeff Dike 已提交
238
		return NULL;
239
	hi->fd = -1;
L
Linus Torvalds 已提交
240
	inode_init_once(&hi->vfs_inode);
J
Jeff Dike 已提交
241
	return &hi->vfs_inode;
L
Linus Torvalds 已提交
242 243
}

244
static void hostfs_evict_inode(struct inode *inode)
L
Linus Torvalds 已提交
245
{
246
	truncate_inode_pages(&inode->i_data, 0);
247
	end_writeback(inode);
J
Jeff Dike 已提交
248
	if (HOSTFS_I(inode)->fd != -1) {
L
Linus Torvalds 已提交
249 250 251 252 253 254 255 256 257 258
		close_file(&HOSTFS_I(inode)->fd);
		HOSTFS_I(inode)->fd = -1;
	}
}

static void hostfs_destroy_inode(struct inode *inode)
{
	kfree(HOSTFS_I(inode));
}

M
Miklos Szeredi 已提交
259 260
static int hostfs_show_options(struct seq_file *seq, struct vfsmount *vfs)
{
261
	const char *root_path = vfs->mnt_sb->s_fs_info;
M
Miklos Szeredi 已提交
262 263 264 265 266 267 268 269
	size_t offset = strlen(root_ino) + 1;

	if (strlen(root_path) > offset)
		seq_printf(seq, ",%s", root_path + offset);

	return 0;
}

270
static const struct super_operations hostfs_sbops = {
L
Linus Torvalds 已提交
271 272
	.alloc_inode	= hostfs_alloc_inode,
	.destroy_inode	= hostfs_destroy_inode,
273
	.evict_inode	= hostfs_evict_inode,
L
Linus Torvalds 已提交
274
	.statfs		= hostfs_statfs,
M
Miklos Szeredi 已提交
275
	.show_options	= hostfs_show_options,
L
Linus Torvalds 已提交
276 277 278 279 280 281 282 283 284
};

int hostfs_readdir(struct file *file, void *ent, filldir_t filldir)
{
	void *dir;
	char *name;
	unsigned long long next, ino;
	int error, len;

A
Al Viro 已提交
285
	name = dentry_name(file->f_path.dentry);
J
Jeff Dike 已提交
286
	if (name == NULL)
J
Jeff Dike 已提交
287
		return -ENOMEM;
L
Linus Torvalds 已提交
288
	dir = open_dir(name, &error);
289
	__putname(name);
J
Jeff Dike 已提交
290
	if (dir == NULL)
J
Jeff Dike 已提交
291
		return -error;
L
Linus Torvalds 已提交
292
	next = file->f_pos;
J
Jeff Dike 已提交
293
	while ((name = read_dir(dir, &next, &ino, &len)) != NULL) {
L
Linus Torvalds 已提交
294 295
		error = (*filldir)(ent, name, len, file->f_pos,
				   ino, DT_UNKNOWN);
J
Jeff Dike 已提交
296
		if (error) break;
L
Linus Torvalds 已提交
297 298 299
		file->f_pos = next;
	}
	close_dir(dir);
J
Jeff Dike 已提交
300
	return 0;
L
Linus Torvalds 已提交
301 302 303 304
}

int hostfs_file_open(struct inode *ino, struct file *file)
{
305
	static DEFINE_MUTEX(open_mutex);
L
Linus Torvalds 已提交
306
	char *name;
307
	fmode_t mode = 0;
308
	int err;
309
	int r = 0, w = 0, fd;
L
Linus Torvalds 已提交
310 311

	mode = file->f_mode & (FMODE_READ | FMODE_WRITE);
J
Jeff Dike 已提交
312
	if ((mode & HOSTFS_I(ino)->mode) == mode)
J
Jeff Dike 已提交
313
		return 0;
L
Linus Torvalds 已提交
314

315
	mode |= HOSTFS_I(ino)->mode;
L
Linus Torvalds 已提交
316

317 318
retry:
	if (mode & FMODE_READ)
L
Linus Torvalds 已提交
319
		r = 1;
320
	if (mode & FMODE_WRITE)
L
Linus Torvalds 已提交
321
		w = 1;
J
Jeff Dike 已提交
322
	if (w)
L
Linus Torvalds 已提交
323 324
		r = 1;

A
Al Viro 已提交
325
	name = dentry_name(file->f_path.dentry);
J
Jeff Dike 已提交
326
	if (name == NULL)
J
Jeff Dike 已提交
327
		return -ENOMEM;
L
Linus Torvalds 已提交
328 329

	fd = open_file(name, r, w, append);
330
	__putname(name);
J
Jeff Dike 已提交
331
	if (fd < 0)
J
Jeff Dike 已提交
332
		return fd;
333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357

	mutex_lock(&open_mutex);
	/* somebody else had handled it first? */
	if ((mode & HOSTFS_I(ino)->mode) == mode) {
		mutex_unlock(&open_mutex);
		return 0;
	}
	if ((mode | HOSTFS_I(ino)->mode) != mode) {
		mode |= HOSTFS_I(ino)->mode;
		mutex_unlock(&open_mutex);
		close_file(&fd);
		goto retry;
	}
	if (HOSTFS_I(ino)->fd == -1) {
		HOSTFS_I(ino)->fd = fd;
	} else {
		err = replace_file(fd, HOSTFS_I(ino)->fd);
		close_file(&fd);
		if (err < 0) {
			mutex_unlock(&open_mutex);
			return err;
		}
	}
	HOSTFS_I(ino)->mode = mode;
	mutex_unlock(&open_mutex);
L
Linus Torvalds 已提交
358

J
Jeff Dike 已提交
359
	return 0;
L
Linus Torvalds 已提交
360 361
}

362
int hostfs_fsync(struct file *file, int datasync)
L
Linus Torvalds 已提交
363
{
364
	return fsync_file(HOSTFS_I(file->f_mapping->host)->fd, datasync);
L
Linus Torvalds 已提交
365 366
}

367
static const struct file_operations hostfs_file_fops = {
L
Linus Torvalds 已提交
368
	.llseek		= generic_file_llseek,
369
	.read		= do_sync_read,
370
	.splice_read	= generic_file_splice_read,
L
Linus Torvalds 已提交
371 372
	.aio_read	= generic_file_aio_read,
	.aio_write	= generic_file_aio_write,
373
	.write		= do_sync_write,
L
Linus Torvalds 已提交
374 375 376 377 378 379
	.mmap		= generic_file_mmap,
	.open		= hostfs_file_open,
	.release	= NULL,
	.fsync		= hostfs_fsync,
};

380
static const struct file_operations hostfs_dir_fops = {
L
Linus Torvalds 已提交
381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402
	.llseek		= generic_file_llseek,
	.readdir	= hostfs_readdir,
	.read		= generic_read_dir,
};

int hostfs_writepage(struct page *page, struct writeback_control *wbc)
{
	struct address_space *mapping = page->mapping;
	struct inode *inode = mapping->host;
	char *buffer;
	unsigned long long base;
	int count = PAGE_CACHE_SIZE;
	int end_index = inode->i_size >> PAGE_CACHE_SHIFT;
	int err;

	if (page->index >= end_index)
		count = inode->i_size & (PAGE_CACHE_SIZE-1);

	buffer = kmap(page);
	base = ((unsigned long long) page->index) << PAGE_CACHE_SHIFT;

	err = write_file(HOSTFS_I(inode)->fd, &base, buffer, count);
J
Jeff Dike 已提交
403
	if (err != count) {
L
Linus Torvalds 已提交
404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431
		ClearPageUptodate(page);
		goto out;
	}

	if (base > inode->i_size)
		inode->i_size = base;

	if (PageError(page))
		ClearPageError(page);
	err = 0;

 out:
	kunmap(page);

	unlock_page(page);
	return err;
}

int hostfs_readpage(struct file *file, struct page *page)
{
	char *buffer;
	long long start;
	int err = 0;

	start = (long long) page->index << PAGE_CACHE_SHIFT;
	buffer = kmap(page);
	err = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer,
			PAGE_CACHE_SIZE);
J
Jeff Dike 已提交
432 433
	if (err < 0)
		goto out;
L
Linus Torvalds 已提交
434 435 436 437 438 439 440 441 442 443

	memset(&buffer[err], 0, PAGE_CACHE_SIZE - err);

	flush_dcache_page(page);
	SetPageUptodate(page);
	if (PageError(page)) ClearPageError(page);
	err = 0;
 out:
	kunmap(page);
	unlock_page(page);
J
Jeff Dike 已提交
444
	return err;
L
Linus Torvalds 已提交
445 446
}

N
Nick Piggin 已提交
447 448 449
int hostfs_write_begin(struct file *file, struct address_space *mapping,
			loff_t pos, unsigned len, unsigned flags,
			struct page **pagep, void **fsdata)
L
Linus Torvalds 已提交
450
{
N
Nick Piggin 已提交
451
	pgoff_t index = pos >> PAGE_CACHE_SHIFT;
L
Linus Torvalds 已提交
452

453
	*pagep = grab_cache_page_write_begin(mapping, index, flags);
N
Nick Piggin 已提交
454 455 456
	if (!*pagep)
		return -ENOMEM;
	return 0;
L
Linus Torvalds 已提交
457 458
}

N
Nick Piggin 已提交
459 460 461
int hostfs_write_end(struct file *file, struct address_space *mapping,
			loff_t pos, unsigned len, unsigned copied,
			struct page *page, void *fsdata)
L
Linus Torvalds 已提交
462 463
{
	struct inode *inode = mapping->host;
N
Nick Piggin 已提交
464 465 466
	void *buffer;
	unsigned from = pos & (PAGE_CACHE_SIZE - 1);
	int err;
L
Linus Torvalds 已提交
467 468

	buffer = kmap(page);
N
Nick Piggin 已提交
469 470
	err = write_file(FILE_HOSTFS_I(file)->fd, &pos, buffer + from, copied);
	kunmap(page);
471

N
Nick Piggin 已提交
472 473
	if (!PageUptodate(page) && err == PAGE_CACHE_SIZE)
		SetPageUptodate(page);
474

J
Jeff Dike 已提交
475 476
	/*
	 * If err > 0, write_file has added err to pos, so we are comparing
N
Nick Piggin 已提交
477 478 479 480 481 482
	 * i_size against the last byte written.
	 */
	if (err > 0 && (pos > inode->i_size))
		inode->i_size = pos;
	unlock_page(page);
	page_cache_release(page);
L
Linus Torvalds 已提交
483

J
Jeff Dike 已提交
484
	return err;
L
Linus Torvalds 已提交
485 486
}

487
static const struct address_space_operations hostfs_aops = {
L
Linus Torvalds 已提交
488 489
	.writepage 	= hostfs_writepage,
	.readpage	= hostfs_readpage,
490
	.set_page_dirty = __set_page_dirty_nobuffers,
N
Nick Piggin 已提交
491 492
	.write_begin	= hostfs_write_begin,
	.write_end	= hostfs_write_end,
L
Linus Torvalds 已提交
493 494
};

495
static int read_name(struct inode *ino, char *name)
L
Linus Torvalds 已提交
496
{
497 498 499 500 501
	dev_t rdev;
	struct hostfs_stat st;
	int err = stat_file(name, &st, -1);
	if (err)
		return err;
L
Linus Torvalds 已提交
502

A
Al Viro 已提交
503
	/* Reencode maj and min with the kernel encoding.*/
504
	rdev = MKDEV(st.maj, st.min);
L
Linus Torvalds 已提交
505

506 507
	switch (st.mode & S_IFMT) {
	case S_IFLNK:
A
Al Viro 已提交
508
		ino->i_op = &hostfs_link_iops;
L
Linus Torvalds 已提交
509
		break;
510 511 512
	case S_IFDIR:
		ino->i_op = &hostfs_dir_iops;
		ino->i_fop = &hostfs_dir_fops;
L
Linus Torvalds 已提交
513
		break;
514 515 516 517 518 519
	case S_IFCHR:
	case S_IFBLK:
	case S_IFIFO:
	case S_IFSOCK:
		init_special_inode(ino, st.mode & S_IFMT, rdev);
		ino->i_op = &hostfs_iops;
L
Linus Torvalds 已提交
520
		break;
521 522 523 524 525

	default:
		ino->i_op = &hostfs_iops;
		ino->i_fop = &hostfs_file_fops;
		ino->i_mapping->a_ops = &hostfs_aops;
L
Linus Torvalds 已提交
526
	}
527 528 529 530 531 532 533 534 535 536 537 538

	ino->i_ino = st.ino;
	ino->i_mode = st.mode;
	ino->i_nlink = st.nlink;
	ino->i_uid = st.uid;
	ino->i_gid = st.gid;
	ino->i_atime = st.atime;
	ino->i_mtime = st.mtime;
	ino->i_ctime = st.ctime;
	ino->i_size = st.size;
	ino->i_blocks = st.blocks;
	return 0;
L
Linus Torvalds 已提交
539 540 541
}

int hostfs_create(struct inode *dir, struct dentry *dentry, int mode,
J
Jeff Dike 已提交
542
		  struct nameidata *nd)
L
Linus Torvalds 已提交
543 544 545 546 547
{
	struct inode *inode;
	char *name;
	int error, fd;

548 549 550
	inode = hostfs_iget(dir->i_sb);
	if (IS_ERR(inode)) {
		error = PTR_ERR(inode);
J
Jeff Dike 已提交
551
		goto out;
552
	}
L
Linus Torvalds 已提交
553 554

	error = -ENOMEM;
A
Al Viro 已提交
555
	name = dentry_name(dentry);
J
Jeff Dike 已提交
556
	if (name == NULL)
L
Linus Torvalds 已提交
557 558 559 560 561 562
		goto out_put;

	fd = file_create(name,
			 mode & S_IRUSR, mode & S_IWUSR, mode & S_IXUSR,
			 mode & S_IRGRP, mode & S_IWGRP, mode & S_IXGRP,
			 mode & S_IROTH, mode & S_IWOTH, mode & S_IXOTH);
563
	if (fd < 0)
L
Linus Torvalds 已提交
564
		error = fd;
565
	else
A
Al Viro 已提交
566
		error = read_name(inode, name);
L
Linus Torvalds 已提交
567

568
	__putname(name);
J
Jeff Dike 已提交
569
	if (error)
L
Linus Torvalds 已提交
570 571 572 573 574
		goto out_put;

	HOSTFS_I(inode)->fd = fd;
	HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE;
	d_instantiate(dentry, inode);
J
Jeff Dike 已提交
575
	return 0;
L
Linus Torvalds 已提交
576 577 578 579

 out_put:
	iput(inode);
 out:
J
Jeff Dike 已提交
580
	return error;
L
Linus Torvalds 已提交
581 582 583
}

struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
J
Jeff Dike 已提交
584
			     struct nameidata *nd)
L
Linus Torvalds 已提交
585 586 587 588 589
{
	struct inode *inode;
	char *name;
	int err;

590 591 592
	inode = hostfs_iget(ino->i_sb);
	if (IS_ERR(inode)) {
		err = PTR_ERR(inode);
L
Linus Torvalds 已提交
593
		goto out;
594
	}
L
Linus Torvalds 已提交
595 596

	err = -ENOMEM;
A
Al Viro 已提交
597
	name = dentry_name(dentry);
J
Jeff Dike 已提交
598
	if (name == NULL)
L
Linus Torvalds 已提交
599 600 601
		goto out_put;

	err = read_name(inode, name);
A
Al Viro 已提交
602

603
	__putname(name);
J
Jeff Dike 已提交
604
	if (err == -ENOENT) {
L
Linus Torvalds 已提交
605 606 607
		iput(inode);
		inode = NULL;
	}
J
Jeff Dike 已提交
608
	else if (err)
L
Linus Torvalds 已提交
609 610 611 612
		goto out_put;

	d_add(dentry, inode);
	dentry->d_op = &hostfs_dentry_ops;
J
Jeff Dike 已提交
613
	return NULL;
L
Linus Torvalds 已提交
614 615 616 617

 out_put:
	iput(inode);
 out:
J
Jeff Dike 已提交
618
	return ERR_PTR(err);
L
Linus Torvalds 已提交
619 620 621 622
}

int hostfs_link(struct dentry *to, struct inode *ino, struct dentry *from)
{
J
Jeff Dike 已提交
623 624
	char *from_name, *to_name;
	int err;
L
Linus Torvalds 已提交
625

A
Al Viro 已提交
626
	if ((from_name = dentry_name(from)) == NULL)
J
Jeff Dike 已提交
627
		return -ENOMEM;
A
Al Viro 已提交
628
	to_name = dentry_name(to);
J
Jeff Dike 已提交
629
	if (to_name == NULL) {
630
		__putname(from_name);
J
Jeff Dike 已提交
631
		return -ENOMEM;
L
Linus Torvalds 已提交
632
	}
J
Jeff Dike 已提交
633
	err = link_file(to_name, from_name);
634 635
	__putname(from_name);
	__putname(to_name);
J
Jeff Dike 已提交
636
	return err;
L
Linus Torvalds 已提交
637 638 639 640 641 642 643
}

int hostfs_unlink(struct inode *ino, struct dentry *dentry)
{
	char *file;
	int err;

J
Jeff Dike 已提交
644
	if (append)
J
Jeff Dike 已提交
645
		return -EPERM;
L
Linus Torvalds 已提交
646

A
Al Viro 已提交
647 648 649
	if ((file = dentry_name(dentry)) == NULL)
		return -ENOMEM;

L
Linus Torvalds 已提交
650
	err = unlink_file(file);
651
	__putname(file);
J
Jeff Dike 已提交
652
	return err;
L
Linus Torvalds 已提交
653 654 655 656 657 658 659
}

int hostfs_symlink(struct inode *ino, struct dentry *dentry, const char *to)
{
	char *file;
	int err;

A
Al Viro 已提交
660
	if ((file = dentry_name(dentry)) == NULL)
J
Jeff Dike 已提交
661
		return -ENOMEM;
L
Linus Torvalds 已提交
662
	err = make_symlink(file, to);
663
	__putname(file);
J
Jeff Dike 已提交
664
	return err;
L
Linus Torvalds 已提交
665 666 667 668 669 670 671
}

int hostfs_mkdir(struct inode *ino, struct dentry *dentry, int mode)
{
	char *file;
	int err;

A
Al Viro 已提交
672
	if ((file = dentry_name(dentry)) == NULL)
J
Jeff Dike 已提交
673
		return -ENOMEM;
L
Linus Torvalds 已提交
674
	err = do_mkdir(file, mode);
675
	__putname(file);
J
Jeff Dike 已提交
676
	return err;
L
Linus Torvalds 已提交
677 678 679 680 681 682 683
}

int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
{
	char *file;
	int err;

A
Al Viro 已提交
684
	if ((file = dentry_name(dentry)) == NULL)
J
Jeff Dike 已提交
685
		return -ENOMEM;
L
Linus Torvalds 已提交
686
	err = do_rmdir(file);
687
	__putname(file);
J
Jeff Dike 已提交
688
	return err;
L
Linus Torvalds 已提交
689 690 691 692 693 694
}

int hostfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
{
	struct inode *inode;
	char *name;
695
	int err;
L
Linus Torvalds 已提交
696

697 698 699
	inode = hostfs_iget(dir->i_sb);
	if (IS_ERR(inode)) {
		err = PTR_ERR(inode);
L
Linus Torvalds 已提交
700
		goto out;
701
	}
L
Linus Torvalds 已提交
702 703

	err = -ENOMEM;
A
Al Viro 已提交
704
	name = dentry_name(dentry);
J
Jeff Dike 已提交
705
	if (name == NULL)
L
Linus Torvalds 已提交
706 707 708
		goto out_put;

	init_special_inode(inode, mode, dev);
J
Johannes Stezenbach 已提交
709
	err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
710
	if (!err)
L
Linus Torvalds 已提交
711 712 713
		goto out_free;

	err = read_name(inode, name);
714
	__putname(name);
A
Al Viro 已提交
715 716
	if (err)
		goto out_put;
J
Jeff Dike 已提交
717
	if (err)
L
Linus Torvalds 已提交
718 719 720
		goto out_put;

	d_instantiate(dentry, inode);
J
Jeff Dike 已提交
721
	return 0;
L
Linus Torvalds 已提交
722 723

 out_free:
724
	__putname(name);
L
Linus Torvalds 已提交
725 726 727
 out_put:
	iput(inode);
 out:
J
Jeff Dike 已提交
728
	return err;
L
Linus Torvalds 已提交
729 730 731 732 733 734 735 736
}

int hostfs_rename(struct inode *from_ino, struct dentry *from,
		  struct inode *to_ino, struct dentry *to)
{
	char *from_name, *to_name;
	int err;

A
Al Viro 已提交
737
	if ((from_name = dentry_name(from)) == NULL)
J
Jeff Dike 已提交
738
		return -ENOMEM;
A
Al Viro 已提交
739
	if ((to_name = dentry_name(to)) == NULL) {
740
		__putname(from_name);
J
Jeff Dike 已提交
741
		return -ENOMEM;
L
Linus Torvalds 已提交
742 743
	}
	err = rename_file(from_name, to_name);
744 745
	__putname(from_name);
	__putname(to_name);
J
Jeff Dike 已提交
746
	return err;
L
Linus Torvalds 已提交
747 748
}

749
int hostfs_permission(struct inode *ino, int desired)
L
Linus Torvalds 已提交
750 751 752 753 754 755 756
{
	char *name;
	int r = 0, w = 0, x = 0, err;

	if (desired & MAY_READ) r = 1;
	if (desired & MAY_WRITE) w = 1;
	if (desired & MAY_EXEC) x = 1;
A
Al Viro 已提交
757
	name = inode_name(ino);
J
Jeff Dike 已提交
758 759
	if (name == NULL)
		return -ENOMEM;
L
Linus Torvalds 已提交
760 761

	if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) ||
J
Jeff Dike 已提交
762
	    S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode))
L
Linus Torvalds 已提交
763 764 765
		err = 0;
	else
		err = access_file(name, r, w, x);
766
	__putname(name);
J
Jeff Dike 已提交
767
	if (!err)
L
Linus Torvalds 已提交
768 769 770 771 772 773
		err = generic_permission(ino, desired, NULL);
	return err;
}

int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
{
C
Christoph Hellwig 已提交
774
	struct inode *inode = dentry->d_inode;
L
Linus Torvalds 已提交
775 776 777 778
	struct hostfs_iattr attrs;
	char *name;
	int err;

C
Christoph Hellwig 已提交
779
	int fd = HOSTFS_I(inode)->fd;
780

C
Christoph Hellwig 已提交
781
	err = inode_change_ok(inode, attr);
L
Linus Torvalds 已提交
782 783 784
	if (err)
		return err;

J
Jeff Dike 已提交
785
	if (append)
L
Linus Torvalds 已提交
786 787 788
		attr->ia_valid &= ~ATTR_SIZE;

	attrs.ia_valid = 0;
J
Jeff Dike 已提交
789
	if (attr->ia_valid & ATTR_MODE) {
L
Linus Torvalds 已提交
790 791 792
		attrs.ia_valid |= HOSTFS_ATTR_MODE;
		attrs.ia_mode = attr->ia_mode;
	}
J
Jeff Dike 已提交
793
	if (attr->ia_valid & ATTR_UID) {
L
Linus Torvalds 已提交
794 795 796
		attrs.ia_valid |= HOSTFS_ATTR_UID;
		attrs.ia_uid = attr->ia_uid;
	}
J
Jeff Dike 已提交
797
	if (attr->ia_valid & ATTR_GID) {
L
Linus Torvalds 已提交
798 799 800
		attrs.ia_valid |= HOSTFS_ATTR_GID;
		attrs.ia_gid = attr->ia_gid;
	}
J
Jeff Dike 已提交
801
	if (attr->ia_valid & ATTR_SIZE) {
L
Linus Torvalds 已提交
802 803 804
		attrs.ia_valid |= HOSTFS_ATTR_SIZE;
		attrs.ia_size = attr->ia_size;
	}
J
Jeff Dike 已提交
805
	if (attr->ia_valid & ATTR_ATIME) {
L
Linus Torvalds 已提交
806 807 808
		attrs.ia_valid |= HOSTFS_ATTR_ATIME;
		attrs.ia_atime = attr->ia_atime;
	}
J
Jeff Dike 已提交
809
	if (attr->ia_valid & ATTR_MTIME) {
L
Linus Torvalds 已提交
810 811 812
		attrs.ia_valid |= HOSTFS_ATTR_MTIME;
		attrs.ia_mtime = attr->ia_mtime;
	}
J
Jeff Dike 已提交
813
	if (attr->ia_valid & ATTR_CTIME) {
L
Linus Torvalds 已提交
814 815 816
		attrs.ia_valid |= HOSTFS_ATTR_CTIME;
		attrs.ia_ctime = attr->ia_ctime;
	}
J
Jeff Dike 已提交
817
	if (attr->ia_valid & ATTR_ATIME_SET) {
L
Linus Torvalds 已提交
818 819
		attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
	}
J
Jeff Dike 已提交
820
	if (attr->ia_valid & ATTR_MTIME_SET) {
L
Linus Torvalds 已提交
821 822
		attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
	}
A
Al Viro 已提交
823
	name = dentry_name(dentry);
J
Jeff Dike 已提交
824
	if (name == NULL)
J
Jeff Dike 已提交
825
		return -ENOMEM;
826
	err = set_attr(name, &attrs, fd);
827
	__putname(name);
J
Jeff Dike 已提交
828
	if (err)
J
Jeff Dike 已提交
829
		return err;
L
Linus Torvalds 已提交
830

C
Christoph Hellwig 已提交
831 832 833 834 835 836 837 838 839 840 841 842
	if ((attr->ia_valid & ATTR_SIZE) &&
	    attr->ia_size != i_size_read(inode)) {
		int error;

		error = vmtruncate(inode, attr->ia_size);
		if (err)
			return err;
	}

	setattr_copy(inode, attr);
	mark_inode_dirty(inode);
	return 0;
L
Linus Torvalds 已提交
843 844
}

845
static const struct inode_operations hostfs_iops = {
L
Linus Torvalds 已提交
846 847 848 849 850 851 852 853 854 855 856 857
	.create		= hostfs_create,
	.link		= hostfs_link,
	.unlink		= hostfs_unlink,
	.symlink	= hostfs_symlink,
	.mkdir		= hostfs_mkdir,
	.rmdir		= hostfs_rmdir,
	.mknod		= hostfs_mknod,
	.rename		= hostfs_rename,
	.permission	= hostfs_permission,
	.setattr	= hostfs_setattr,
};

858
static const struct inode_operations hostfs_dir_iops = {
L
Linus Torvalds 已提交
859 860 861 862 863 864 865 866 867 868 869 870 871
	.create		= hostfs_create,
	.lookup		= hostfs_lookup,
	.link		= hostfs_link,
	.unlink		= hostfs_unlink,
	.symlink	= hostfs_symlink,
	.mkdir		= hostfs_mkdir,
	.rmdir		= hostfs_rmdir,
	.mknod		= hostfs_mknod,
	.rename		= hostfs_rename,
	.permission	= hostfs_permission,
	.setattr	= hostfs_setattr,
};

A
Al Viro 已提交
872 873 874 875 876 877 878
static void *hostfs_follow_link(struct dentry *dentry, struct nameidata *nd)
{
	char *link = __getname();
	if (link) {
		char *path = dentry_name(dentry);
		int err = -ENOMEM;
		if (path) {
A
Al Viro 已提交
879
			err = hostfs_do_readlink(path, link, PATH_MAX);
A
Al Viro 已提交
880 881
			if (err == PATH_MAX)
				err = -E2BIG;
882
			__putname(path);
A
Al Viro 已提交
883 884 885 886 887 888 889
		}
		if (err < 0) {
			__putname(link);
			link = ERR_PTR(err);
		}
	} else {
		link = ERR_PTR(-ENOMEM);
L
Linus Torvalds 已提交
890
	}
A
Al Viro 已提交
891 892 893 894 895 896 897 898 899 900

	nd_set_link(nd, link);
	return NULL;
}

static void hostfs_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
{
	char *s = nd_get_link(nd);
	if (!IS_ERR(s))
		__putname(s);
L
Linus Torvalds 已提交
901 902
}

A
Al Viro 已提交
903 904 905 906
static const struct inode_operations hostfs_link_iops = {
	.readlink	= generic_readlink,
	.follow_link	= hostfs_follow_link,
	.put_link	= hostfs_put_link,
L
Linus Torvalds 已提交
907 908 909 910 911
};

static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
{
	struct inode *root_inode;
912
	char *host_root_path, *req_root = d;
L
Linus Torvalds 已提交
913 914 915 916 917 918
	int err;

	sb->s_blocksize = 1024;
	sb->s_blocksize_bits = 10;
	sb->s_magic = HOSTFS_SUPER_MAGIC;
	sb->s_op = &hostfs_sbops;
919
	sb->s_maxbytes = MAX_LFS_FILESIZE;
L
Linus Torvalds 已提交
920

921
	/* NULL is printed as <NULL> by sprintf: avoid that. */
922 923
	if (req_root == NULL)
		req_root = "";
L
Linus Torvalds 已提交
924 925

	err = -ENOMEM;
926 927
	sb->s_fs_info = host_root_path =
		kmalloc(strlen(root_ino) + strlen(req_root) + 2, GFP_KERNEL);
J
Jeff Dike 已提交
928
	if (host_root_path == NULL)
L
Linus Torvalds 已提交
929 930
		goto out;

931
	sprintf(host_root_path, "%s/%s", root_ino, req_root);
L
Linus Torvalds 已提交
932

A
Al Viro 已提交
933 934
	root_inode = new_inode(sb);
	if (!root_inode)
935
		goto out;
L
Linus Torvalds 已提交
936

937 938 939
	err = read_name(root_inode, host_root_path);
	if (err)
		goto out_put;
A
Al Viro 已提交
940

941
	if (S_ISLNK(root_inode->i_mode)) {
A
Al Viro 已提交
942 943 944 945 946 947
		char *name = follow_link(host_root_path);
		if (IS_ERR(name))
			err = PTR_ERR(name);
		else
			err = read_name(root_inode, name);
		kfree(name);
948 949
		if (err)
			goto out_put;
A
Al Viro 已提交
950
	}
L
Linus Torvalds 已提交
951 952 953

	err = -ENOMEM;
	sb->s_root = d_alloc_root(root_inode);
J
Jeff Dike 已提交
954
	if (sb->s_root == NULL)
L
Linus Torvalds 已提交
955 956
		goto out_put;

J
Jeff Dike 已提交
957
	return 0;
L
Linus Torvalds 已提交
958

J
Jeff Dike 已提交
959 960 961 962
out_put:
	iput(root_inode);
out:
	return err;
L
Linus Torvalds 已提交
963 964
}

965 966 967
static int hostfs_read_sb(struct file_system_type *type,
			  int flags, const char *dev_name,
			  void *data, struct vfsmount *mnt)
L
Linus Torvalds 已提交
968
{
969
	return get_sb_nodev(type, flags, data, hostfs_fill_sb_common, mnt);
L
Linus Torvalds 已提交
970 971
}

972 973 974 975 976 977
static void hostfs_kill_sb(struct super_block *s)
{
	kill_anon_super(s);
	kfree(s->s_fs_info);
}

L
Linus Torvalds 已提交
978 979 980 981
static struct file_system_type hostfs_type = {
	.owner 		= THIS_MODULE,
	.name 		= "hostfs",
	.get_sb 	= hostfs_read_sb,
982
	.kill_sb	= hostfs_kill_sb,
L
Linus Torvalds 已提交
983 984 985 986 987
	.fs_flags 	= 0,
};

static int __init init_hostfs(void)
{
J
Jeff Dike 已提交
988
	return register_filesystem(&hostfs_type);
L
Linus Torvalds 已提交
989 990 991 992 993 994 995 996 997 998
}

static void __exit exit_hostfs(void)
{
	unregister_filesystem(&hostfs_type);
}

module_init(init_hostfs)
module_exit(exit_hostfs)
MODULE_LICENSE("GPL");