1
2
3
4
5
6
7
8
9
10
11
12#include <linux/kernel.h>
13#include <linux/module.h>
14#include <linux/errno.h>
15#include <linux/fs.h>
16#include <linux/file.h>
17#include <linux/stat.h>
18#include <linux/string.h>
19#include <linux/inet.h>
20#include <linux/pagemap.h>
21#include <linux/mount.h>
22#include <linux/idr.h>
23#include <linux/sched.h>
24#include <linux/slab.h>
25#include <linux/statfs.h>
26#include <linux/magic.h>
27#include <net/9p/9p.h>
28#include <net/9p/client.h>
29
30#include "v9fs.h"
31#include "v9fs_vfs.h"
32#include "fid.h"
33#include "xattr.h"
34#include "acl.h"
35
36static const struct super_operations v9fs_super_ops, v9fs_super_ops_dotl;
37
38
39
40
41
42
43
44
45static int v9fs_set_super(struct super_block *s, void *data)
46{
47 s->s_fs_info = data;
48 return set_anon_super(s, data);
49}
50
51
52
53
54
55
56
57
58
59static int
60v9fs_fill_super(struct super_block *sb, struct v9fs_session_info *v9ses,
61 int flags, void *data)
62{
63 int ret;
64
65 sb->s_maxbytes = MAX_LFS_FILESIZE;
66 sb->s_blocksize_bits = fls(v9ses->maxdata - 1);
67 sb->s_blocksize = 1 << sb->s_blocksize_bits;
68 sb->s_magic = V9FS_MAGIC;
69 if (v9fs_proto_dotl(v9ses)) {
70 sb->s_op = &v9fs_super_ops_dotl;
71 sb->s_xattr = v9fs_xattr_handlers;
72 } else
73 sb->s_op = &v9fs_super_ops;
74
75 ret = super_setup_bdi(sb);
76 if (ret)
77 return ret;
78
79 if (v9ses->cache)
80 sb->s_bdi->ra_pages = VM_READAHEAD_PAGES;
81
82 sb->s_flags |= SB_ACTIVE | SB_DIRSYNC;
83 if (!v9ses->cache)
84 sb->s_flags |= SB_SYNCHRONOUS;
85
86#ifdef CONFIG_9P_FS_POSIX_ACL
87 if ((v9ses->flags & V9FS_ACL_MASK) == V9FS_POSIX_ACL)
88 sb->s_flags |= SB_POSIXACL;
89#endif
90
91 return 0;
92}
93
94
95
96
97
98
99
100
101
102
103static struct dentry *v9fs_mount(struct file_system_type *fs_type, int flags,
104 const char *dev_name, void *data)
105{
106 struct super_block *sb = NULL;
107 struct inode *inode = NULL;
108 struct dentry *root = NULL;
109 struct v9fs_session_info *v9ses = NULL;
110 umode_t mode = S_IRWXUGO | S_ISVTX;
111 struct p9_fid *fid;
112 int retval = 0;
113
114 p9_debug(P9_DEBUG_VFS, "\n");
115
116 v9ses = kzalloc(sizeof(struct v9fs_session_info), GFP_KERNEL);
117 if (!v9ses)
118 return ERR_PTR(-ENOMEM);
119
120 fid = v9fs_session_init(v9ses, dev_name, data);
121 if (IS_ERR(fid)) {
122 retval = PTR_ERR(fid);
123 goto free_session;
124 }
125
126 sb = sget(fs_type, NULL, v9fs_set_super, flags, v9ses);
127 if (IS_ERR(sb)) {
128 retval = PTR_ERR(sb);
129 goto clunk_fid;
130 }
131 retval = v9fs_fill_super(sb, v9ses, flags, data);
132 if (retval)
133 goto release_sb;
134
135 if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE)
136 sb->s_d_op = &v9fs_cached_dentry_operations;
137 else
138 sb->s_d_op = &v9fs_dentry_operations;
139
140 inode = v9fs_get_inode(sb, S_IFDIR | mode, 0);
141 if (IS_ERR(inode)) {
142 retval = PTR_ERR(inode);
143 goto release_sb;
144 }
145
146 root = d_make_root(inode);
147 if (!root) {
148 retval = -ENOMEM;
149 goto release_sb;
150 }
151 sb->s_root = root;
152 if (v9fs_proto_dotl(v9ses)) {
153 struct p9_stat_dotl *st = NULL;
154 st = p9_client_getattr_dotl(fid, P9_STATS_BASIC);
155 if (IS_ERR(st)) {
156 retval = PTR_ERR(st);
157 goto release_sb;
158 }
159 d_inode(root)->i_ino = v9fs_qid2ino(&st->qid);
160 v9fs_stat2inode_dotl(st, d_inode(root), 0);
161 kfree(st);
162 } else {
163 struct p9_wstat *st = NULL;
164 st = p9_client_stat(fid);
165 if (IS_ERR(st)) {
166 retval = PTR_ERR(st);
167 goto release_sb;
168 }
169
170 d_inode(root)->i_ino = v9fs_qid2ino(&st->qid);
171 v9fs_stat2inode(st, d_inode(root), sb, 0);
172
173 p9stat_free(st);
174 kfree(st);
175 }
176 retval = v9fs_get_acl(inode, fid);
177 if (retval)
178 goto release_sb;
179 v9fs_fid_add(root, fid);
180
181 p9_debug(P9_DEBUG_VFS, " simple set mount, return 0\n");
182 return dget(sb->s_root);
183
184clunk_fid:
185 p9_client_clunk(fid);
186 v9fs_session_close(v9ses);
187free_session:
188 kfree(v9ses);
189 return ERR_PTR(retval);
190
191release_sb:
192
193
194
195
196
197
198 p9_client_clunk(fid);
199 deactivate_locked_super(sb);
200 return ERR_PTR(retval);
201}
202
203
204
205
206
207
208
209static void v9fs_kill_super(struct super_block *s)
210{
211 struct v9fs_session_info *v9ses = s->s_fs_info;
212
213 p9_debug(P9_DEBUG_VFS, " %p\n", s);
214
215 kill_anon_super(s);
216
217 v9fs_session_cancel(v9ses);
218 v9fs_session_close(v9ses);
219 kfree(v9ses);
220 s->s_fs_info = NULL;
221 p9_debug(P9_DEBUG_VFS, "exiting kill_super\n");
222}
223
224static void
225v9fs_umount_begin(struct super_block *sb)
226{
227 struct v9fs_session_info *v9ses;
228
229 v9ses = sb->s_fs_info;
230 v9fs_session_begin_cancel(v9ses);
231}
232
233static int v9fs_statfs(struct dentry *dentry, struct kstatfs *buf)
234{
235 struct v9fs_session_info *v9ses;
236 struct p9_fid *fid;
237 struct p9_rstatfs rs;
238 int res;
239
240 fid = v9fs_fid_lookup(dentry);
241 if (IS_ERR(fid)) {
242 res = PTR_ERR(fid);
243 goto done;
244 }
245
246 v9ses = v9fs_dentry2v9ses(dentry);
247 if (v9fs_proto_dotl(v9ses)) {
248 res = p9_client_statfs(fid, &rs);
249 if (res == 0) {
250 buf->f_type = rs.type;
251 buf->f_bsize = rs.bsize;
252 buf->f_blocks = rs.blocks;
253 buf->f_bfree = rs.bfree;
254 buf->f_bavail = rs.bavail;
255 buf->f_files = rs.files;
256 buf->f_ffree = rs.ffree;
257 buf->f_fsid.val[0] = rs.fsid & 0xFFFFFFFFUL;
258 buf->f_fsid.val[1] = (rs.fsid >> 32) & 0xFFFFFFFFUL;
259 buf->f_namelen = rs.namelen;
260 }
261 if (res != -ENOSYS)
262 goto done;
263 }
264 res = simple_statfs(dentry, buf);
265done:
266 return res;
267}
268
269static int v9fs_drop_inode(struct inode *inode)
270{
271 struct v9fs_session_info *v9ses;
272 v9ses = v9fs_inode2v9ses(inode);
273 if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE)
274 return generic_drop_inode(inode);
275
276
277
278
279
280 return 1;
281}
282
283static int v9fs_write_inode(struct inode *inode,
284 struct writeback_control *wbc)
285{
286 int ret;
287 struct p9_wstat wstat;
288 struct v9fs_inode *v9inode;
289
290
291
292
293 p9_debug(P9_DEBUG_VFS, "%s: inode %p\n", __func__, inode);
294 v9inode = V9FS_I(inode);
295 if (!v9inode->writeback_fid)
296 return 0;
297 v9fs_blank_wstat(&wstat);
298
299 ret = p9_client_wstat(v9inode->writeback_fid, &wstat);
300 if (ret < 0) {
301 __mark_inode_dirty(inode, I_DIRTY_DATASYNC);
302 return ret;
303 }
304 return 0;
305}
306
307static int v9fs_write_inode_dotl(struct inode *inode,
308 struct writeback_control *wbc)
309{
310 int ret;
311 struct v9fs_inode *v9inode;
312
313
314
315
316 v9inode = V9FS_I(inode);
317 p9_debug(P9_DEBUG_VFS, "%s: inode %p, writeback_fid %p\n",
318 __func__, inode, v9inode->writeback_fid);
319 if (!v9inode->writeback_fid)
320 return 0;
321
322 ret = p9_client_fsync(v9inode->writeback_fid, 0);
323 if (ret < 0) {
324 __mark_inode_dirty(inode, I_DIRTY_DATASYNC);
325 return ret;
326 }
327 return 0;
328}
329
330static const struct super_operations v9fs_super_ops = {
331 .alloc_inode = v9fs_alloc_inode,
332 .free_inode = v9fs_free_inode,
333 .statfs = simple_statfs,
334 .evict_inode = v9fs_evict_inode,
335 .show_options = v9fs_show_options,
336 .umount_begin = v9fs_umount_begin,
337 .write_inode = v9fs_write_inode,
338};
339
340static const struct super_operations v9fs_super_ops_dotl = {
341 .alloc_inode = v9fs_alloc_inode,
342 .free_inode = v9fs_free_inode,
343 .statfs = v9fs_statfs,
344 .drop_inode = v9fs_drop_inode,
345 .evict_inode = v9fs_evict_inode,
346 .show_options = v9fs_show_options,
347 .umount_begin = v9fs_umount_begin,
348 .write_inode = v9fs_write_inode_dotl,
349};
350
351struct file_system_type v9fs_fs_type = {
352 .name = "9p",
353 .mount = v9fs_mount,
354 .kill_sb = v9fs_kill_super,
355 .owner = THIS_MODULE,
356 .fs_flags = FS_RENAME_DOES_D_MOVE,
357};
358MODULE_ALIAS_FS("9p");
359