vfs_super.c 8.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
/*
 *  linux/fs/9p/vfs_super.c
 *
 * This file contians superblock ops for 9P2000. It is intended that
 * you mount this file system on directories.
 *
 *  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
11 12
 *  it under the terms of the GNU General Public License version 2
 *  as published by the Free Software Foundation.
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
 *
 *  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/kernel.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/file.h>
#include <linux/stat.h>
#include <linux/string.h>
#include <linux/inet.h>
#include <linux/pagemap.h>
#include <linux/seq_file.h>
#include <linux/mount.h>
#include <linux/idr.h>
A
Alexey Dobriyan 已提交
39
#include <linux/sched.h>
40
#include <linux/slab.h>
41
#include <linux/statfs.h>
M
M. Mohan Kumar 已提交
42
#include <linux/magic.h>
43 44
#include <net/9p/9p.h>
#include <net/9p/client.h>
45 46 47 48

#include "v9fs.h"
#include "v9fs_vfs.h"
#include "fid.h"
49
#include "xattr.h"
50
#include "acl.h"
51

52
static const struct super_operations v9fs_super_ops, v9fs_super_ops_dotl;
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70

/**
 * v9fs_set_super - set the superblock
 * @s: super block
 * @data: file system specific data
 *
 */

static int v9fs_set_super(struct super_block *s, void *data)
{
	s->s_fs_info = data;
	return set_anon_super(s, data);
}

/**
 * v9fs_fill_super - populate superblock with info
 * @sb: superblock
 * @v9ses: session information
A
Al Viro 已提交
71
 * @flags: flags propagated from v9fs_mount()
72 73 74 75 76
 *
 */

static void
v9fs_fill_super(struct super_block *sb, struct v9fs_session_info *v9ses,
77
		int flags, void *data)
78 79 80 81 82
{
	sb->s_maxbytes = MAX_LFS_FILESIZE;
	sb->s_blocksize_bits = fls(v9ses->maxdata - 1);
	sb->s_blocksize = 1 << sb->s_blocksize_bits;
	sb->s_magic = V9FS_MAGIC;
83
	if (v9fs_proto_dotl(v9ses)) {
84
		sb->s_op = &v9fs_super_ops_dotl;
85 86
		sb->s_xattr = v9fs_xattr_handlers;
	} else
87
		sb->s_op = &v9fs_super_ops;
88
	sb->s_bdi = &v9ses->bdi;
89 90
	if (v9ses->cache)
		sb->s_bdi->ra_pages = (VM_MAX_READAHEAD * 1024)/PAGE_CACHE_SIZE;
91

92 93 94
	sb->s_flags = flags | MS_ACTIVE | MS_DIRSYNC | MS_NOATIME;
	if (!v9ses->cache)
		sb->s_flags |= MS_SYNCHRONOUS;
95

96
#ifdef CONFIG_9P_FS_POSIX_ACL
97
	if ((v9ses->flags & V9FS_ACL_MASK) == V9FS_POSIX_ACL)
98
		sb->s_flags |= MS_POSIXACL;
99 100
#endif

101
	save_mount_options(sb, data);
102 103 104
}

/**
A
Al Viro 已提交
105
 * v9fs_mount - mount a superblock
106 107 108 109 110 111 112
 * @fs_type: file system type
 * @flags: mount flags
 * @dev_name: device name that was mounted
 * @data: mount options
 *
 */

A
Al Viro 已提交
113 114
static struct dentry *v9fs_mount(struct file_system_type *fs_type, int flags,
		       const char *dev_name, void *data)
115 116 117 118 119 120
{
	struct super_block *sb = NULL;
	struct inode *inode = NULL;
	struct dentry *root = NULL;
	struct v9fs_session_info *v9ses = NULL;
	int mode = S_IRWXUGO | S_ISVTX;
121
	struct p9_fid *fid;
122 123
	int retval = 0;

124
	P9_DPRINTK(P9_DEBUG_VFS, " \n");
125

126
	v9ses = kzalloc(sizeof(struct v9fs_session_info), GFP_KERNEL);
127
	if (!v9ses)
A
Al Viro 已提交
128
		return ERR_PTR(-ENOMEM);
129

130 131 132
	fid = v9fs_session_init(v9ses, dev_name, data);
	if (IS_ERR(fid)) {
		retval = PTR_ERR(fid);
133 134 135 136
		/*
		 * we need to call session_close to tear down some
		 * of the data structure setup by session_init
		 */
137
		goto close_session;
138 139
	}

140
	sb = sget(fs_type, NULL, v9fs_set_super, v9ses);
141 142
	if (IS_ERR(sb)) {
		retval = PTR_ERR(sb);
143
		goto clunk_fid;
144
	}
145
	v9fs_fill_super(sb, v9ses, flags, data);
146

A
Al Viro 已提交
147 148 149 150 151
	if (v9ses->cache)
		sb->s_d_op = &v9fs_cached_dentry_operations;
	else
		sb->s_d_op = &v9fs_dentry_operations;

152 153 154
	inode = v9fs_get_inode(sb, S_IFDIR | mode);
	if (IS_ERR(inode)) {
		retval = PTR_ERR(inode);
155
		goto release_sb;
156
	}
157

158 159
	root = d_alloc_root(inode);
	if (!root) {
160
		iput(inode);
161
		retval = -ENOMEM;
162
		goto release_sb;
163 164
	}
	sb->s_root = root;
165 166 167 168 169
	if (v9fs_proto_dotl(v9ses)) {
		struct p9_stat_dotl *st = NULL;
		st = p9_client_getattr_dotl(fid, P9_STATS_BASIC);
		if (IS_ERR(st)) {
			retval = PTR_ERR(st);
170
			goto release_sb;
171
		}
172
		root->d_inode->i_ino = v9fs_qid2ino(&st->qid);
173 174 175 176 177 178 179
		v9fs_stat2inode_dotl(st, root->d_inode);
		kfree(st);
	} else {
		struct p9_wstat *st = NULL;
		st = p9_client_stat(fid);
		if (IS_ERR(st)) {
			retval = PTR_ERR(st);
180
			goto release_sb;
181 182 183 184 185 186 187 188
		}

		root->d_inode->i_ino = v9fs_qid2ino(&st->qid);
		v9fs_stat2inode(st, root->d_inode, sb);

		p9stat_free(st);
		kfree(st);
	}
189 190 191
	retval = v9fs_get_acl(inode, fid);
	if (retval)
		goto release_sb;
192
	v9fs_fid_add(root, fid);
193

194
	P9_DPRINTK(P9_DEBUG_VFS, " simple set mount, return 0\n");
A
Al Viro 已提交
195
	return dget(sb->s_root);
196

197 198 199 200 201
clunk_fid:
	p9_client_clunk(fid);
close_session:
	v9fs_session_close(v9ses);
	kfree(v9ses);
A
Al Viro 已提交
202
	return ERR_PTR(retval);
203

204
release_sb:
205
	/*
206 207 208 209
	 * we will do the session_close and root dentry release
	 * in the below call. But we need to clunk fid, because we haven't
	 * attached the fid to dentry so it won't get clunked
	 * automatically.
210
	 */
211
	p9_client_clunk(fid);
212
	deactivate_locked_super(sb);
A
Al Viro 已提交
213
	return ERR_PTR(retval);
214 215 216 217 218 219 220 221 222 223 224 225
}

/**
 * v9fs_kill_super - Kill Superblock
 * @s: superblock
 *
 */

static void v9fs_kill_super(struct super_block *s)
{
	struct v9fs_session_info *v9ses = s->s_fs_info;

226
	P9_DPRINTK(P9_DEBUG_VFS, " %p\n", s);
227 228

	kill_anon_super(s);
229

230
	v9fs_session_cancel(v9ses);
231 232
	v9fs_session_close(v9ses);
	kfree(v9ses);
233
	s->s_fs_info = NULL;
234
	P9_DPRINTK(P9_DEBUG_VFS, "exiting kill_super\n");
235 236
}

237
static void
238
v9fs_umount_begin(struct super_block *sb)
239
{
240
	struct v9fs_session_info *v9ses;
241

242
	v9ses = sb->s_fs_info;
243
	v9fs_session_begin_cancel(v9ses);
244 245
}

246 247 248 249 250 251 252 253 254 255 256 257 258
static int v9fs_statfs(struct dentry *dentry, struct kstatfs *buf)
{
	struct v9fs_session_info *v9ses;
	struct p9_fid *fid;
	struct p9_rstatfs rs;
	int res;

	fid = v9fs_fid_lookup(dentry);
	if (IS_ERR(fid)) {
		res = PTR_ERR(fid);
		goto done;
	}

A
Aneesh Kumar K.V 已提交
259
	v9ses = v9fs_dentry2v9ses(dentry);
260 261 262
	if (v9fs_proto_dotl(v9ses)) {
		res = p9_client_statfs(fid, &rs);
		if (res == 0) {
M
M. Mohan Kumar 已提交
263
			buf->f_type = V9FS_MAGIC;
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281
			buf->f_bsize = rs.bsize;
			buf->f_blocks = rs.blocks;
			buf->f_bfree = rs.bfree;
			buf->f_bavail = rs.bavail;
			buf->f_files = rs.files;
			buf->f_ffree = rs.ffree;
			buf->f_fsid.val[0] = rs.fsid & 0xFFFFFFFFUL;
			buf->f_fsid.val[1] = (rs.fsid >> 32) & 0xFFFFFFFFUL;
			buf->f_namelen = rs.namelen;
		}
		if (res != -ENOSYS)
			goto done;
	}
	res = simple_statfs(dentry, buf);
done:
	return res;
}

282 283 284 285 286 287 288 289 290 291 292 293 294 295
static int v9fs_drop_inode(struct inode *inode)
{
	struct v9fs_session_info *v9ses;
	v9ses = v9fs_inode2v9ses(inode);
	if (v9ses->cache)
		return generic_drop_inode(inode);
	/*
	 * in case of non cached mode always drop the
	 * the inode because we want the inode attribute
	 * to always match that on the server.
	 */
	return 1;
}

296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340
static int v9fs_write_inode(struct inode *inode,
			    struct writeback_control *wbc)
{
	int ret;
	struct p9_wstat wstat;
	struct v9fs_inode *v9inode;
	/*
	 * send an fsync request to server irrespective of
	 * wbc->sync_mode.
	 */
	P9_DPRINTK(P9_DEBUG_VFS, "%s: inode %p\n", __func__, inode);
	v9inode = V9FS_I(inode);
	if (!v9inode->writeback_fid)
		return 0;
	v9fs_blank_wstat(&wstat);

	ret = p9_client_wstat(v9inode->writeback_fid, &wstat);
	if (ret < 0) {
		__mark_inode_dirty(inode, I_DIRTY_DATASYNC);
		return ret;
	}
	return 0;
}

static int v9fs_write_inode_dotl(struct inode *inode,
				 struct writeback_control *wbc)
{
	int ret;
	struct v9fs_inode *v9inode;
	/*
	 * send an fsync request to server irrespective of
	 * wbc->sync_mode.
	 */
	P9_DPRINTK(P9_DEBUG_VFS, "%s: inode %p\n", __func__, inode);
	v9inode = V9FS_I(inode);
	if (!v9inode->writeback_fid)
		return 0;
	ret = p9_client_fsync(v9inode->writeback_fid, 0);
	if (ret < 0) {
		__mark_inode_dirty(inode, I_DIRTY_DATASYNC);
		return ret;
	}
	return 0;
}

341
static const struct super_operations v9fs_super_ops = {
342 343
	.alloc_inode = v9fs_alloc_inode,
	.destroy_inode = v9fs_destroy_inode,
344
	.statfs = simple_statfs,
345
	.evict_inode = v9fs_evict_inode,
346
	.show_options = generic_show_options,
347
	.umount_begin = v9fs_umount_begin,
348
	.write_inode = v9fs_write_inode,
349 350
};

351 352 353
static const struct super_operations v9fs_super_ops_dotl = {
	.alloc_inode = v9fs_alloc_inode,
	.destroy_inode = v9fs_destroy_inode,
354
	.statfs = v9fs_statfs,
355
	.drop_inode = v9fs_drop_inode,
356
	.evict_inode = v9fs_evict_inode,
357 358
	.show_options = generic_show_options,
	.umount_begin = v9fs_umount_begin,
359
	.write_inode = v9fs_write_inode_dotl,
360 361
};

362
struct file_system_type v9fs_fs_type = {
363
	.name = "9p",
A
Al Viro 已提交
364
	.mount = v9fs_mount,
365 366
	.kill_sb = v9fs_kill_super,
	.owner = THIS_MODULE,
367
	.fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT,
368
};