vfs_super.c 7.0 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

	sb->s_flags = flags | MS_ACTIVE | MS_SYNCHRONOUS | MS_DIRSYNC |
91
	    MS_NOATIME;
92

93
#ifdef CONFIG_9P_FS_POSIX_ACL
94 95
	if ((v9ses->flags & V9FS_ACCESS_MASK) == V9FS_ACCESS_CLIENT)
		sb->s_flags |= MS_POSIXACL;
96 97
#endif

98
	save_mount_options(sb, data);
99 100 101
}

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

A
Al Viro 已提交
110 111
static struct dentry *v9fs_mount(struct file_system_type *fs_type, int flags,
		       const char *dev_name, void *data)
112 113 114 115 116 117
{
	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;
118
	struct p9_fid *fid;
119 120
	int retval = 0;

121
	P9_DPRINTK(P9_DEBUG_VFS, " \n");
122

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

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

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

	inode = v9fs_get_inode(sb, S_IFDIR | mode);
	if (IS_ERR(inode)) {
		retval = PTR_ERR(inode);
147
		goto release_sb;
148 149 150 151
	}

	root = d_alloc_root(inode);
	if (!root) {
152
		iput(inode);
153
		retval = -ENOMEM;
154
		goto release_sb;
155 156
	}
	sb->s_root = root;
157 158 159 160 161
	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);
162
			goto release_sb;
163 164 165 166 167 168 169 170 171
		}

		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);
172
			goto release_sb;
173 174 175 176 177 178 179 180
		}

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

		p9stat_free(st);
		kfree(st);
	}
181 182 183
	retval = v9fs_get_acl(inode, fid);
	if (retval)
		goto release_sb;
184
	v9fs_fid_add(root, fid);
185

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

189 190 191 192 193
clunk_fid:
	p9_client_clunk(fid);
close_session:
	v9fs_session_close(v9ses);
	kfree(v9ses);
A
Al Viro 已提交
194 195
	return ERR_PTR(retval);

196
release_sb:
197 198 199 200 201 202 203
	/*
	 * 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.
	 */
	p9_client_clunk(fid);
204
	deactivate_locked_super(sb);
A
Al Viro 已提交
205
	return ERR_PTR(retval);
206 207 208 209 210 211 212 213 214 215 216 217
}

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

218
	P9_DPRINTK(P9_DEBUG_VFS, " %p\n", s);
219

A
Al Viro 已提交
220 221
	if (s->s_root)
		v9fs_dentry_release(s->s_root);	/* clunk root */
222 223 224

	kill_anon_super(s);

225
	v9fs_session_cancel(v9ses);
226 227
	v9fs_session_close(v9ses);
	kfree(v9ses);
228
	s->s_fs_info = NULL;
229
	P9_DPRINTK(P9_DEBUG_VFS, "exiting kill_super\n");
230 231
}

232
static void
233
v9fs_umount_begin(struct super_block *sb)
234
{
235
	struct v9fs_session_info *v9ses;
236

237
	v9ses = sb->s_fs_info;
238
	v9fs_session_begin_cancel(v9ses);
239 240
}

241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
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;
	}

	v9ses = v9fs_inode2v9ses(dentry->d_inode);
	if (v9fs_proto_dotl(v9ses)) {
		res = p9_client_statfs(fid, &rs);
		if (res == 0) {
M
M. Mohan Kumar 已提交
258
			buf->f_type = V9FS_MAGIC;
259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
			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;
}

277
static const struct super_operations v9fs_super_ops = {
278 279 280 281
#ifdef CONFIG_9P_FSCACHE
	.alloc_inode = v9fs_alloc_inode,
	.destroy_inode = v9fs_destroy_inode,
#endif
282
	.statfs = simple_statfs,
283
	.evict_inode = v9fs_evict_inode,
284
	.show_options = generic_show_options,
285
	.umount_begin = v9fs_umount_begin,
286 287
};

288 289 290 291 292
static const struct super_operations v9fs_super_ops_dotl = {
#ifdef CONFIG_9P_FSCACHE
	.alloc_inode = v9fs_alloc_inode,
	.destroy_inode = v9fs_destroy_inode,
#endif
293
	.statfs = v9fs_statfs,
294
	.evict_inode = v9fs_evict_inode,
295 296 297 298
	.show_options = generic_show_options,
	.umount_begin = v9fs_umount_begin,
};

299
struct file_system_type v9fs_fs_type = {
300
	.name = "9p",
A
Al Viro 已提交
301
	.mount = v9fs_mount,
302 303
	.kill_sb = v9fs_kill_super,
	.owner = THIS_MODULE,
304
	.fs_flags = FS_RENAME_DOES_D_MOVE,
305
};