aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/9p/9p.c359
-rw-r--r--fs/9p/9p.h341
-rw-r--r--fs/9p/Makefile17
-rw-r--r--fs/9p/conv.c693
-rw-r--r--fs/9p/conv.h36
-rw-r--r--fs/9p/debug.h70
-rw-r--r--fs/9p/error.c93
-rw-r--r--fs/9p/error.h178
-rw-r--r--fs/9p/fid.c241
-rw-r--r--fs/9p/fid.h57
-rw-r--r--fs/9p/mux.c475
-rw-r--r--fs/9p/mux.h41
-rw-r--r--fs/9p/trans_fd.c172
-rw-r--r--fs/9p/trans_sock.c290
-rw-r--r--fs/9p/transport.h46
-rw-r--r--fs/9p/v9fs.c452
-rw-r--r--fs/9p/v9fs.h103
-rw-r--r--fs/9p/v9fs_vfs.h53
-rw-r--r--fs/9p/vfs_dentry.c126
-rw-r--r--fs/9p/vfs_dir.c226
-rw-r--r--fs/9p/vfs_file.c401
-rw-r--r--fs/9p/vfs_inode.c1338
-rw-r--r--fs/9p/vfs_super.c280
-rw-r--r--fs/Kconfig24
-rw-r--r--fs/Makefile2
-rw-r--r--fs/affs/inode.c1
-rw-r--r--fs/aio.c34
-rw-r--r--fs/autofs/autofs_i.h3
-rw-r--r--fs/autofs/dirhash.c5
-rw-r--r--fs/autofs/inode.c3
-rw-r--r--fs/bfs/bfs.h1
-rw-r--r--fs/bfs/dir.c25
-rw-r--r--fs/bfs/file.c23
-rw-r--r--fs/bfs/inode.c104
-rw-r--r--fs/buffer.c1
-rw-r--r--fs/cifs/connect.c6
-rw-r--r--fs/compat.c6
-rw-r--r--fs/compat_ioctl.c7
-rw-r--r--fs/cramfs/uncompress.c1
-rw-r--r--fs/dcache.c16
-rw-r--r--fs/exec.c8
-rw-r--r--fs/ext2/ialloc.c5
-rw-r--r--fs/ext2/inode.c2
-rw-r--r--fs/ext2/xattr.h8
-rw-r--r--fs/ext2/xattr_security.c22
-rw-r--r--fs/ext3/ialloc.c5
-rw-r--r--fs/ext3/inode.c2
-rw-r--r--fs/ext3/xattr.h11
-rw-r--r--fs/ext3/xattr_security.c22
-rw-r--r--fs/fat/inode.c2
-rw-r--r--fs/fcntl.c60
-rw-r--r--fs/file.c387
-rw-r--r--fs/file_table.c40
-rw-r--r--fs/fuse/Makefile7
-rw-r--r--fs/fuse/dev.c877
-rw-r--r--fs/fuse/dir.c982
-rw-r--r--fs/fuse/file.c555
-rw-r--r--fs/fuse/fuse_i.h451
-rw-r--r--fs/fuse/inode.c591
-rw-r--r--fs/hostfs/hostfs_kern.c1
-rw-r--r--fs/hpfs/inode.c1
-rw-r--r--fs/inode.c12
-rw-r--r--fs/jbd/transaction.c3
-rw-r--r--fs/jffs/inode-v23.c1
-rw-r--r--fs/jffs/intrep.c22
-rw-r--r--fs/jfs/acl.c24
-rw-r--r--fs/jfs/inode.c26
-rw-r--r--fs/jfs/jfs_acl.h12
-rw-r--r--fs/jfs/jfs_xattr.h14
-rw-r--r--fs/jfs/namei.c85
-rw-r--r--fs/jfs/xattr.c94
-rw-r--r--fs/lockd/clntproc.c3
-rw-r--r--fs/locks.c8
-rw-r--r--fs/minix/inode.c1
-rw-r--r--fs/namei.c26
-rw-r--r--fs/namespace.c4
-rw-r--r--fs/ncpfs/inode.c2
-rw-r--r--fs/nfs/inode.c2
-rw-r--r--fs/nfs/nfs3proc.c3
-rw-r--r--fs/nfs/nfs4proc.c12
-rw-r--r--fs/ntfs/aops.c1
-rw-r--r--fs/open.c43
-rw-r--r--fs/pipe.c6
-rw-r--r--fs/proc/array.c5
-rw-r--r--fs/proc/base.c33
-rw-r--r--fs/proc/inode.c2
-rw-r--r--fs/qnx4/inode.c1
-rw-r--r--fs/reiserfs/inode.c2
-rw-r--r--fs/reiserfs/journal.c3
-rw-r--r--fs/reiserfs/super.c3
-rw-r--r--fs/select.c23
-rw-r--r--fs/smbfs/inode.c1
-rw-r--r--fs/smbfs/proc.c3
-rw-r--r--fs/sysv/inode.c1
-rw-r--r--fs/udf/inode.c2
-rw-r--r--fs/ufs/inode.c1
-rw-r--r--fs/xfs/linux-2.6/time.h3
-rw-r--r--fs/xfs/linux-2.6/xfs_buf.c6
-rw-r--r--fs/xfs/linux-2.6/xfs_super.c12
-rw-r--r--fs/xfs/support/ktrace.c2
100 files changed, 10459 insertions, 437 deletions
diff --git a/fs/9p/9p.c b/fs/9p/9p.c
new file mode 100644
index 0000000000..e847f504a4
--- /dev/null
+++ b/fs/9p/9p.c
@@ -0,0 +1,359 @@
1/*
2 * linux/fs/9p/9p.c
3 *
4 * This file contains functions 9P2000 functions
5 *
6 * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
7 * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to:
21 * Free Software Foundation
22 * 51 Franklin Street, Fifth Floor
23 * Boston, MA 02111-1301 USA
24 *
25 */
26
27#include <linux/config.h>
28#include <linux/module.h>
29#include <linux/errno.h>
30#include <linux/fs.h>
31#include <linux/idr.h>
32
33#include "debug.h"
34#include "v9fs.h"
35#include "9p.h"
36#include "mux.h"
37
38/**
39 * v9fs_t_version - negotiate protocol parameters with sever
40 * @v9ses: 9P2000 session information
41 * @msize: requested max size packet
42 * @version: requested version.extension string
43 * @fcall: pointer to response fcall pointer
44 *
45 */
46
47int
48v9fs_t_version(struct v9fs_session_info *v9ses, u32 msize,
49 char *version, struct v9fs_fcall **fcall)
50{
51 struct v9fs_fcall msg;
52
53 dprintk(DEBUG_9P, "msize: %d version: %s\n", msize, version);
54 msg.id = TVERSION;
55 msg.params.tversion.msize = msize;
56 msg.params.tversion.version = version;
57
58 return v9fs_mux_rpc(v9ses, &msg, fcall);
59}
60
61/**
62 * v9fs_t_attach - mount the server
63 * @v9ses: 9P2000 session information
64 * @uname: user name doing the attach
65 * @aname: remote name being attached to
66 * @fid: mount fid to attatch to root node
67 * @afid: authentication fid (in this case result key)
68 * @fcall: pointer to response fcall pointer
69 *
70 */
71
72int
73v9fs_t_attach(struct v9fs_session_info *v9ses, char *uname, char *aname,
74 u32 fid, u32 afid, struct v9fs_fcall **fcall)
75{
76 struct v9fs_fcall msg;
77
78 dprintk(DEBUG_9P, "uname '%s' aname '%s' fid %d afid %d\n", uname,
79 aname, fid, afid);
80 msg.id = TATTACH;
81 msg.params.tattach.fid = fid;
82 msg.params.tattach.afid = afid;
83 msg.params.tattach.uname = uname;
84 msg.params.tattach.aname = aname;
85
86 return v9fs_mux_rpc(v9ses, &msg, fcall);
87}
88
89/**
90 * v9fs_t_clunk - release a fid (finish a transaction)
91 * @v9ses: 9P2000 session information
92 * @fid: fid to release
93 * @fcall: pointer to response fcall pointer
94 *
95 */
96
97int
98v9fs_t_clunk(struct v9fs_session_info *v9ses, u32 fid,
99 struct v9fs_fcall **fcall)
100{
101 struct v9fs_fcall msg;
102
103 dprintk(DEBUG_9P, "fid %d\n", fid);
104 msg.id = TCLUNK;
105 msg.params.tclunk.fid = fid;
106
107 return v9fs_mux_rpc(v9ses, &msg, fcall);
108}
109
110/**
111 * v9fs_v9fs_t_flush - flush a pending transaction
112 * @v9ses: 9P2000 session information
113 * @tag: tid to release
114 *
115 */
116
117int v9fs_t_flush(struct v9fs_session_info *v9ses, u16 tag)
118{
119 struct v9fs_fcall msg;
120
121 dprintk(DEBUG_9P, "oldtag %d\n", tag);
122 msg.id = TFLUSH;
123 msg.params.tflush.oldtag = tag;
124 return v9fs_mux_rpc(v9ses, &msg, NULL);
125}
126
127/**
128 * v9fs_t_stat - read a file's meta-data
129 * @v9ses: 9P2000 session information
130 * @fid: fid pointing to file or directory to get info about
131 * @fcall: pointer to response fcall
132 *
133 */
134
135int
136v9fs_t_stat(struct v9fs_session_info *v9ses, u32 fid, struct v9fs_fcall **fcall)
137{
138 struct v9fs_fcall msg;
139
140 dprintk(DEBUG_9P, "fid %d\n", fid);
141 if (fcall)
142 *fcall = NULL;
143
144 msg.id = TSTAT;
145 msg.params.tstat.fid = fid;
146 return v9fs_mux_rpc(v9ses, &msg, fcall);
147}
148
149/**
150 * v9fs_t_wstat - write a file's meta-data
151 * @v9ses: 9P2000 session information
152 * @fid: fid pointing to file or directory to write info about
153 * @stat: metadata
154 * @fcall: pointer to response fcall
155 *
156 */
157
158int
159v9fs_t_wstat(struct v9fs_session_info *v9ses, u32 fid,
160 struct v9fs_stat *stat, struct v9fs_fcall **fcall)
161{
162 struct v9fs_fcall msg;
163
164 dprintk(DEBUG_9P, "fid %d length %d\n", fid, (int)stat->length);
165 msg.id = TWSTAT;
166 msg.params.twstat.fid = fid;
167 msg.params.twstat.stat = stat;
168
169 return v9fs_mux_rpc(v9ses, &msg, fcall);
170}
171
172/**
173 * v9fs_t_walk - walk a fid to a new file or directory
174 * @v9ses: 9P2000 session information
175 * @fid: fid to walk
176 * @newfid: new fid (for clone operations)
177 * @name: path to walk fid to
178 * @fcall: pointer to response fcall
179 *
180 */
181
182/* TODO: support multiple walk */
183
184int
185v9fs_t_walk(struct v9fs_session_info *v9ses, u32 fid, u32 newfid,
186 char *name, struct v9fs_fcall **fcall)
187{
188 struct v9fs_fcall msg;
189
190 dprintk(DEBUG_9P, "fid %d newfid %d wname '%s'\n", fid, newfid, name);
191 msg.id = TWALK;
192 msg.params.twalk.fid = fid;
193 msg.params.twalk.newfid = newfid;
194
195 if (name) {
196 msg.params.twalk.nwname = 1;
197 msg.params.twalk.wnames = &name;
198 } else {
199 msg.params.twalk.nwname = 0;
200 }
201
202 return v9fs_mux_rpc(v9ses, &msg, fcall);
203}
204
205/**
206 * v9fs_t_open - open a file
207 *
208 * @v9ses - 9P2000 session information
209 * @fid - fid to open
210 * @mode - mode to open file (R, RW, etc)
211 * @fcall - pointer to response fcall
212 *
213 */
214
215int
216v9fs_t_open(struct v9fs_session_info *v9ses, u32 fid, u8 mode,
217 struct v9fs_fcall **fcall)
218{
219 struct v9fs_fcall msg;
220 long errorno = -1;
221
222 dprintk(DEBUG_9P, "fid %d mode %d\n", fid, mode);
223 msg.id = TOPEN;
224 msg.params.topen.fid = fid;
225 msg.params.topen.mode = mode;
226
227 errorno = v9fs_mux_rpc(v9ses, &msg, fcall);
228
229 return errorno;
230}
231
232/**
233 * v9fs_t_remove - remove a file or directory
234 * @v9ses: 9P2000 session information
235 * @fid: fid to remove
236 * @fcall: pointer to response fcall
237 *
238 */
239
240int
241v9fs_t_remove(struct v9fs_session_info *v9ses, u32 fid,
242 struct v9fs_fcall **fcall)
243{
244 struct v9fs_fcall msg;
245
246 dprintk(DEBUG_9P, "fid %d\n", fid);
247 msg.id = TREMOVE;
248 msg.params.tremove.fid = fid;
249 return v9fs_mux_rpc(v9ses, &msg, fcall);
250}
251
252/**
253 * v9fs_t_create - create a file or directory
254 * @v9ses: 9P2000 session information
255 * @fid: fid to create
256 * @name: name of the file or directory to create
257 * @perm: permissions to create with
258 * @mode: mode to open file (R, RW, etc)
259 * @fcall: pointer to response fcall
260 *
261 */
262
263int
264v9fs_t_create(struct v9fs_session_info *v9ses, u32 fid, char *name,
265 u32 perm, u8 mode, struct v9fs_fcall **fcall)
266{
267 struct v9fs_fcall msg;
268
269 dprintk(DEBUG_9P, "fid %d name '%s' perm %x mode %d\n",
270 fid, name, perm, mode);
271
272 msg.id = TCREATE;
273 msg.params.tcreate.fid = fid;
274 msg.params.tcreate.name = name;
275 msg.params.tcreate.perm = perm;
276 msg.params.tcreate.mode = mode;
277
278 return v9fs_mux_rpc(v9ses, &msg, fcall);
279}
280
281/**
282 * v9fs_t_read - read data
283 * @v9ses: 9P2000 session information
284 * @fid: fid to read from
285 * @offset: offset to start read at
286 * @count: how many bytes to read
287 * @fcall: pointer to response fcall (with data)
288 *
289 */
290
291int
292v9fs_t_read(struct v9fs_session_info *v9ses, u32 fid, u64 offset,
293 u32 count, struct v9fs_fcall **fcall)
294{
295 struct v9fs_fcall msg;
296 struct v9fs_fcall *rc = NULL;
297 long errorno = -1;
298
299 dprintk(DEBUG_9P, "fid %d offset 0x%lx count 0x%x\n", fid,
300 (long unsigned int)offset, count);
301 msg.id = TREAD;
302 msg.params.tread.fid = fid;
303 msg.params.tread.offset = offset;
304 msg.params.tread.count = count;
305 errorno = v9fs_mux_rpc(v9ses, &msg, &rc);
306
307 if (!errorno) {
308 errorno = rc->params.rread.count;
309 dump_data(rc->params.rread.data, rc->params.rread.count);
310 }
311
312 if (fcall)
313 *fcall = rc;
314 else
315 kfree(rc);
316
317 return errorno;
318}
319
320/**
321 * v9fs_t_write - write data
322 * @v9ses: 9P2000 session information
323 * @fid: fid to write to
324 * @offset: offset to start write at
325 * @count: how many bytes to write
326 * @fcall: pointer to response fcall
327 *
328 */
329
330int
331v9fs_t_write(struct v9fs_session_info *v9ses, u32 fid,
332 u64 offset, u32 count, void *data, struct v9fs_fcall **fcall)
333{
334 struct v9fs_fcall msg;
335 struct v9fs_fcall *rc = NULL;
336 long errorno = -1;
337
338 dprintk(DEBUG_9P, "fid %d offset 0x%llx count 0x%x\n", fid,
339 (unsigned long long)offset, count);
340 dump_data(data, count);
341
342 msg.id = TWRITE;
343 msg.params.twrite.fid = fid;
344 msg.params.twrite.offset = offset;
345 msg.params.twrite.count = count;
346 msg.params.twrite.data = data;
347
348 errorno = v9fs_mux_rpc(v9ses, &msg, &rc);
349
350 if (!errorno)
351 errorno = rc->params.rwrite.count;
352
353 if (fcall)
354 *fcall = rc;
355 else
356 kfree(rc);
357
358 return errorno;
359}
diff --git a/fs/9p/9p.h b/fs/9p/9p.h
new file mode 100644
index 0000000000..f55424216b
--- /dev/null
+++ b/fs/9p/9p.h
@@ -0,0 +1,341 @@
1/*
2 * linux/fs/9p/9p.h
3 *
4 * 9P protocol definitions.
5 *
6 * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
7 * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to:
21 * Free Software Foundation
22 * 51 Franklin Street, Fifth Floor
23 * Boston, MA 02111-1301 USA
24 *
25 */
26
27/* Message Types */
28enum {
29 TVERSION = 100,
30 RVERSION,
31 TAUTH = 102,
32 RAUTH,
33 TATTACH = 104,
34 RATTACH,
35 TERROR = 106,
36 RERROR,
37 TFLUSH = 108,
38 RFLUSH,
39 TWALK = 110,
40 RWALK,
41 TOPEN = 112,
42 ROPEN,
43 TCREATE = 114,
44 RCREATE,
45 TREAD = 116,
46 RREAD,
47 TWRITE = 118,
48 RWRITE,
49 TCLUNK = 120,
50 RCLUNK,
51 TREMOVE = 122,
52 RREMOVE,
53 TSTAT = 124,
54 RSTAT,
55 TWSTAT = 126,
56 RWSTAT,
57};
58
59/* modes */
60enum {
61 V9FS_OREAD = 0x00,
62 V9FS_OWRITE = 0x01,
63 V9FS_ORDWR = 0x02,
64 V9FS_OEXEC = 0x03,
65 V9FS_OEXCL = 0x04,
66 V9FS_OTRUNC = 0x10,
67 V9FS_OREXEC = 0x20,
68 V9FS_ORCLOSE = 0x40,
69 V9FS_OAPPEND = 0x80,
70};
71
72/* permissions */
73enum {
74 V9FS_DMDIR = 0x80000000,
75 V9FS_DMAPPEND = 0x40000000,
76 V9FS_DMEXCL = 0x20000000,
77 V9FS_DMMOUNT = 0x10000000,
78 V9FS_DMAUTH = 0x08000000,
79 V9FS_DMTMP = 0x04000000,
80 V9FS_DMSYMLINK = 0x02000000,
81 V9FS_DMLINK = 0x01000000,
82 /* 9P2000.u extensions */
83 V9FS_DMDEVICE = 0x00800000,
84 V9FS_DMNAMEDPIPE = 0x00200000,
85 V9FS_DMSOCKET = 0x00100000,
86 V9FS_DMSETUID = 0x00080000,
87 V9FS_DMSETGID = 0x00040000,
88};
89
90/* qid.types */
91enum {
92 V9FS_QTDIR = 0x80,
93 V9FS_QTAPPEND = 0x40,
94 V9FS_QTEXCL = 0x20,
95 V9FS_QTMOUNT = 0x10,
96 V9FS_QTAUTH = 0x08,
97 V9FS_QTTMP = 0x04,
98 V9FS_QTSYMLINK = 0x02,
99 V9FS_QTLINK = 0x01,
100 V9FS_QTFILE = 0x00,
101};
102
103/* ample room for Twrite/Rread header (iounit) */
104#define V9FS_IOHDRSZ 24
105
106/* qids are the unique ID for a file (like an inode */
107struct v9fs_qid {
108 u8 type;
109 u32 version;
110 u64 path;
111};
112
113/* Plan 9 file metadata (stat) structure */
114struct v9fs_stat {
115 u16 size;
116 u16 type;
117 u32 dev;
118 struct v9fs_qid qid;
119 u32 mode;
120 u32 atime;
121 u32 mtime;
122 u64 length;
123 char *name;
124 char *uid;
125 char *gid;
126 char *muid;
127 char *extension; /* 9p2000.u extensions */
128 u32 n_uid; /* 9p2000.u extensions */
129 u32 n_gid; /* 9p2000.u extensions */
130 u32 n_muid; /* 9p2000.u extensions */
131 char data[0];
132};
133
134/* Structures for Protocol Operations */
135
136struct Tversion {
137 u32 msize;
138 char *version;
139};
140
141struct Rversion {
142 u32 msize;
143 char *version;
144};
145
146struct Tauth {
147 u32 afid;
148 char *uname;
149 char *aname;
150};
151
152struct Rauth {
153 struct v9fs_qid qid;
154};
155
156struct Rerror {
157 char *error;
158 u32 errno; /* 9p2000.u extension */
159};
160
161struct Tflush {
162 u32 oldtag;
163};
164
165struct Rflush {
166};
167
168struct Tattach {
169 u32 fid;
170 u32 afid;
171 char *uname;
172 char *aname;
173};
174
175struct Rattach {
176 struct v9fs_qid qid;
177};
178
179struct Twalk {
180 u32 fid;
181 u32 newfid;
182 u32 nwname;
183 char **wnames;
184};
185
186struct Rwalk {
187 u32 nwqid;
188 struct v9fs_qid *wqids;
189};
190
191struct Topen {
192 u32 fid;
193 u8 mode;
194};
195
196struct Ropen {
197 struct v9fs_qid qid;
198 u32 iounit;
199};
200
201struct Tcreate {
202 u32 fid;
203 char *name;
204 u32 perm;
205 u8 mode;
206};
207
208struct Rcreate {
209 struct v9fs_qid qid;
210 u32 iounit;
211};
212
213struct Tread {
214 u32 fid;
215 u64 offset;
216 u32 count;
217};
218
219struct Rread {
220 u32 count;
221 u8 *data;
222};
223
224struct Twrite {
225 u32 fid;
226 u64 offset;
227 u32 count;
228 u8 *data;
229};
230
231struct Rwrite {
232 u32 count;
233};
234
235struct Tclunk {
236 u32 fid;
237};
238
239struct Rclunk {
240};
241
242struct Tremove {
243 u32 fid;
244};
245
246struct Rremove {
247};
248
249struct Tstat {
250 u32 fid;
251};
252
253struct Rstat {
254 struct v9fs_stat *stat;
255};
256
257struct Twstat {
258 u32 fid;
259 struct v9fs_stat *stat;
260};
261
262struct Rwstat {
263};
264
265/*
266 * fcall is the primary packet structure
267 *
268 */
269
270struct v9fs_fcall {
271 u32 size;
272 u8 id;
273 u16 tag;
274
275 union {
276 struct Tversion tversion;
277 struct Rversion rversion;
278 struct Tauth tauth;
279 struct Rauth rauth;
280 struct Rerror rerror;
281 struct Tflush tflush;
282 struct Rflush rflush;
283 struct Tattach tattach;
284 struct Rattach rattach;
285 struct Twalk twalk;
286 struct Rwalk rwalk;
287 struct Topen topen;
288 struct Ropen ropen;
289 struct Tcreate tcreate;
290 struct Rcreate rcreate;
291 struct Tread tread;
292 struct Rread rread;
293 struct Twrite twrite;
294 struct Rwrite rwrite;
295 struct Tclunk tclunk;
296 struct Rclunk rclunk;
297 struct Tremove tremove;
298 struct Rremove rremove;
299 struct Tstat tstat;
300 struct Rstat rstat;
301 struct Twstat twstat;
302 struct Rwstat rwstat;
303 } params;
304};
305
306#define FCALL_ERROR(fcall) (fcall ? fcall->params.rerror.error : "")
307
308int v9fs_t_version(struct v9fs_session_info *v9ses, u32 msize,
309 char *version, struct v9fs_fcall **rcall);
310
311int v9fs_t_attach(struct v9fs_session_info *v9ses, char *uname, char *aname,
312 u32 fid, u32 afid, struct v9fs_fcall **rcall);
313
314int v9fs_t_clunk(struct v9fs_session_info *v9ses, u32 fid,
315 struct v9fs_fcall **rcall);
316
317int v9fs_t_flush(struct v9fs_session_info *v9ses, u16 oldtag);
318
319int v9fs_t_stat(struct v9fs_session_info *v9ses, u32 fid,
320 struct v9fs_fcall **rcall);
321
322int v9fs_t_wstat(struct v9fs_session_info *v9ses, u32 fid,
323 struct v9fs_stat *stat, struct v9fs_fcall **rcall);
324
325int v9fs_t_walk(struct v9fs_session_info *v9ses, u32 fid, u32 newfid,
326 char *name, struct v9fs_fcall **rcall);
327
328int v9fs_t_open(struct v9fs_session_info *v9ses, u32 fid, u8 mode,
329 struct v9fs_fcall **rcall);
330
331int v9fs_t_remove(struct v9fs_session_info *v9ses, u32 fid,
332 struct v9fs_fcall **rcall);
333
334int v9fs_t_create(struct v9fs_session_info *v9ses, u32 fid, char *name,
335 u32 perm, u8 mode, struct v9fs_fcall **rcall);
336
337int v9fs_t_read(struct v9fs_session_info *v9ses, u32 fid,
338 u64 offset, u32 count, struct v9fs_fcall **rcall);
339
340int v9fs_t_write(struct v9fs_session_info *v9ses, u32 fid, u64 offset,
341 u32 count, void *data, struct v9fs_fcall **rcall);
diff --git a/fs/9p/Makefile b/fs/9p/Makefile
new file mode 100644
index 0000000000..e4e4ffe5a7
--- /dev/null
+++ b/fs/9p/Makefile
@@ -0,0 +1,17 @@
1obj-$(CONFIG_9P_FS) := 9p2000.o
2
39p2000-objs := \
4 vfs_super.o \
5 vfs_inode.o \
6 vfs_file.o \
7 vfs_dir.o \
8 vfs_dentry.o \
9 error.o \
10 mux.o \
11 trans_fd.o \
12 trans_sock.o \
13 9p.o \
14 conv.o \
15 v9fs.o \
16 fid.o
17
diff --git a/fs/9p/conv.c b/fs/9p/conv.c
new file mode 100644
index 0000000000..1554731bd6
--- /dev/null
+++ b/fs/9p/conv.c
@@ -0,0 +1,693 @@
1/*
2 * linux/fs/9p/conv.c
3 *
4 * 9P protocol conversion functions
5 *
6 * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
7 * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to:
21 * Free Software Foundation
22 * 51 Franklin Street, Fifth Floor
23 * Boston, MA 02111-1301 USA
24 *
25 */
26
27#include <linux/config.h>
28#include <linux/module.h>
29#include <linux/errno.h>
30#include <linux/fs.h>
31#include <linux/idr.h>
32
33#include "debug.h"
34#include "v9fs.h"
35#include "9p.h"
36#include "conv.h"
37
38/*
39 * Buffer to help with string parsing
40 */
41struct cbuf {
42 unsigned char *sp;
43 unsigned char *p;
44 unsigned char *ep;
45};
46
47static inline void buf_init(struct cbuf *buf, void *data, int datalen)
48{
49 buf->sp = buf->p = data;
50 buf->ep = data + datalen;
51}
52
53static inline int buf_check_overflow(struct cbuf *buf)
54{
55 return buf->p > buf->ep;
56}
57
58static inline void buf_check_size(struct cbuf *buf, int len)
59{
60 if (buf->p+len > buf->ep) {
61 if (buf->p < buf->ep) {
62 eprintk(KERN_ERR, "buffer overflow\n");
63 buf->p = buf->ep + 1;
64 }
65 }
66}
67
68static inline void *buf_alloc(struct cbuf *buf, int len)
69{
70 void *ret = NULL;
71
72 buf_check_size(buf, len);
73 ret = buf->p;
74 buf->p += len;
75
76 return ret;
77}
78
79static inline void buf_put_int8(struct cbuf *buf, u8 val)
80{
81 buf_check_size(buf, 1);
82
83 buf->p[0] = val;
84 buf->p++;
85}
86
87static inline void buf_put_int16(struct cbuf *buf, u16 val)
88{
89 buf_check_size(buf, 2);
90
91 *(__le16 *) buf->p = cpu_to_le16(val);
92 buf->p += 2;
93}
94
95static inline void buf_put_int32(struct cbuf *buf, u32 val)
96{
97 buf_check_size(buf, 4);
98
99 *(__le32 *)buf->p = cpu_to_le32(val);
100 buf->p += 4;
101}
102
103static inline void buf_put_int64(struct cbuf *buf, u64 val)
104{
105 buf_check_size(buf, 8);
106
107 *(__le64 *)buf->p = cpu_to_le64(val);
108 buf->p += 8;
109}
110
111static inline void buf_put_stringn(struct cbuf *buf, const char *s, u16 slen)
112{
113 buf_check_size(buf, slen + 2);
114
115 buf_put_int16(buf, slen);
116 memcpy(buf->p, s, slen);
117 buf->p += slen;
118}
119
120static inline void buf_put_string(struct cbuf *buf, const char *s)
121{
122 buf_put_stringn(buf, s, strlen(s));
123}
124
125static inline void buf_put_data(struct cbuf *buf, void *data, u32 datalen)
126{
127 buf_check_size(buf, datalen);
128
129 memcpy(buf->p, data, datalen);
130 buf->p += datalen;
131}
132
133static inline u8 buf_get_int8(struct cbuf *buf)
134{
135 u8 ret = 0;
136
137 buf_check_size(buf, 1);
138 ret = buf->p[0];
139
140 buf->p++;
141
142 return ret;
143}
144
145static inline u16 buf_get_int16(struct cbuf *buf)
146{
147 u16 ret = 0;
148
149 buf_check_size(buf, 2);
150 ret = le16_to_cpu(*(__le16 *)buf->p);
151
152 buf->p += 2;
153
154 return ret;
155}
156
157static inline u32 buf_get_int32(struct cbuf *buf)
158{
159 u32 ret = 0;
160
161 buf_check_size(buf, 4);
162 ret = le32_to_cpu(*(__le32 *)buf->p);
163
164 buf->p += 4;
165
166 return ret;
167}
168
169static inline u64 buf_get_int64(struct cbuf *buf)
170{
171 u64 ret = 0;
172
173 buf_check_size(buf, 8);
174 ret = le64_to_cpu(*(__le64 *)buf->p);
175
176 buf->p += 8;
177
178 return ret;
179}
180
181static inline int
182buf_get_string(struct cbuf *buf, char *data, unsigned int datalen)
183{
184
185 u16 len = buf_get_int16(buf);
186 buf_check_size(buf, len);
187 if (len + 1 > datalen)
188 return 0;
189
190 memcpy(data, buf->p, len);
191 data[len] = 0;
192 buf->p += len;
193
194 return len + 1;
195}
196
197static inline char *buf_get_stringb(struct cbuf *buf, struct cbuf *sbuf)
198{
199 char *ret = NULL;
200 int n = buf_get_string(buf, sbuf->p, sbuf->ep - sbuf->p);
201
202 if (n > 0) {
203 ret = sbuf->p;
204 sbuf->p += n;
205 }
206
207 return ret;
208}
209
210static inline int buf_get_data(struct cbuf *buf, void *data, int datalen)
211{
212 buf_check_size(buf, datalen);
213
214 memcpy(data, buf->p, datalen);
215 buf->p += datalen;
216
217 return datalen;
218}
219
220static inline void *buf_get_datab(struct cbuf *buf, struct cbuf *dbuf,
221 int datalen)
222{
223 char *ret = NULL;
224 int n = 0;
225
226 buf_check_size(dbuf, datalen);
227
228 n = buf_get_data(buf, dbuf->p, datalen);
229
230 if (n > 0) {
231 ret = dbuf->p;
232 dbuf->p += n;
233 }
234
235 return ret;
236}
237
238/**
239 * v9fs_size_stat - calculate the size of a variable length stat struct
240 * @v9ses: session information
241 * @stat: metadata (stat) structure
242 *
243 */
244
245static int v9fs_size_stat(struct v9fs_session_info *v9ses,
246 struct v9fs_stat *stat)
247{
248 int size = 0;
249
250 if (stat == NULL) {
251 eprintk(KERN_ERR, "v9fs_size_stat: got a NULL stat pointer\n");
252 return 0;
253 }
254
255 size = /* 2 + *//* size[2] */
256 2 + /* type[2] */
257 4 + /* dev[4] */
258 1 + /* qid.type[1] */
259 4 + /* qid.vers[4] */
260 8 + /* qid.path[8] */
261 4 + /* mode[4] */
262 4 + /* atime[4] */
263 4 + /* mtime[4] */
264 8 + /* length[8] */
265 8; /* minimum sum of string lengths */
266
267 if (stat->name)
268 size += strlen(stat->name);
269 if (stat->uid)
270 size += strlen(stat->uid);
271 if (stat->gid)
272 size += strlen(stat->gid);
273 if (stat->muid)
274 size += strlen(stat->muid);
275
276 if (v9ses->extended) {
277 size += 4 + /* n_uid[4] */
278 4 + /* n_gid[4] */
279 4 + /* n_muid[4] */
280 2; /* string length of extension[4] */
281 if (stat->extension)
282 size += strlen(stat->extension);
283 }
284
285 return size;
286}
287
288/**
289 * serialize_stat - safely format a stat structure for transmission
290 * @v9ses: session info
291 * @stat: metadata (stat) structure
292 * @bufp: buffer to serialize structure into
293 *
294 */
295
296static int
297serialize_stat(struct v9fs_session_info *v9ses, struct v9fs_stat *stat,
298 struct cbuf *bufp)
299{
300 buf_put_int16(bufp, stat->size);
301 buf_put_int16(bufp, stat->type);
302 buf_put_int32(bufp, stat->dev);
303 buf_put_int8(bufp, stat->qid.type);
304 buf_put_int32(bufp, stat->qid.version);
305 buf_put_int64(bufp, stat->qid.path);
306 buf_put_int32(bufp, stat->mode);
307 buf_put_int32(bufp, stat->atime);
308 buf_put_int32(bufp, stat->mtime);
309 buf_put_int64(bufp, stat->length);
310
311 buf_put_string(bufp, stat->name);
312 buf_put_string(bufp, stat->uid);
313 buf_put_string(bufp, stat->gid);
314 buf_put_string(bufp, stat->muid);
315
316 if (v9ses->extended) {
317 buf_put_string(bufp, stat->extension);
318 buf_put_int32(bufp, stat->n_uid);
319 buf_put_int32(bufp, stat->n_gid);
320 buf_put_int32(bufp, stat->n_muid);
321 }
322
323 if (buf_check_overflow(bufp))
324 return 0;
325
326 return stat->size;
327}
328
329/**
330 * deserialize_stat - safely decode a recieved metadata (stat) structure
331 * @v9ses: session info
332 * @bufp: buffer to deserialize
333 * @stat: metadata (stat) structure
334 * @dbufp: buffer to deserialize variable strings into
335 *
336 */
337
338static inline int
339deserialize_stat(struct v9fs_session_info *v9ses, struct cbuf *bufp,
340 struct v9fs_stat *stat, struct cbuf *dbufp)
341{
342
343 stat->size = buf_get_int16(bufp);
344 stat->type = buf_get_int16(bufp);
345 stat->dev = buf_get_int32(bufp);
346 stat->qid.type = buf_get_int8(bufp);
347 stat->qid.version = buf_get_int32(bufp);
348 stat->qid.path = buf_get_int64(bufp);
349 stat->mode = buf_get_int32(bufp);
350 stat->atime = buf_get_int32(bufp);
351 stat->mtime = buf_get_int32(bufp);
352 stat->length = buf_get_int64(bufp);
353 stat->name = buf_get_stringb(bufp, dbufp);
354 stat->uid = buf_get_stringb(bufp, dbufp);
355 stat->gid = buf_get_stringb(bufp, dbufp);
356 stat->muid = buf_get_stringb(bufp, dbufp);
357
358 if (v9ses->extended) {
359 stat->extension = buf_get_stringb(bufp, dbufp);
360 stat->n_uid = buf_get_int32(bufp);
361 stat->n_gid = buf_get_int32(bufp);
362 stat->n_muid = buf_get_int32(bufp);
363 }
364
365 if (buf_check_overflow(bufp) || buf_check_overflow(dbufp))
366 return 0;
367
368 return stat->size + 2;
369}
370
371/**
372 * deserialize_statb - wrapper for decoding a received metadata structure
373 * @v9ses: session info
374 * @bufp: buffer to deserialize
375 * @dbufp: buffer to deserialize variable strings into
376 *
377 */
378
379static inline struct v9fs_stat *deserialize_statb(struct v9fs_session_info
380 *v9ses, struct cbuf *bufp,
381 struct cbuf *dbufp)
382{
383 struct v9fs_stat *ret = buf_alloc(dbufp, sizeof(struct v9fs_stat));
384
385 if (ret) {
386 int n = deserialize_stat(v9ses, bufp, ret, dbufp);
387 if (n <= 0)
388 return NULL;
389 }
390
391 return ret;
392}
393
394/**
395 * v9fs_deserialize_stat - decode a received metadata structure
396 * @v9ses: session info
397 * @buf: buffer to deserialize
398 * @buflen: length of received buffer
399 * @stat: metadata structure to decode into
400 * @statlen: length of destination metadata structure
401 *
402 */
403
404int
405v9fs_deserialize_stat(struct v9fs_session_info *v9ses, void *buf,
406 u32 buflen, struct v9fs_stat *stat, u32 statlen)
407{
408 struct cbuf buffer;
409 struct cbuf *bufp = &buffer;
410 struct cbuf dbuffer;
411 struct cbuf *dbufp = &dbuffer;
412
413 buf_init(bufp, buf, buflen);
414 buf_init(dbufp, (char *)stat + sizeof(struct v9fs_stat),
415 statlen - sizeof(struct v9fs_stat));
416
417 return deserialize_stat(v9ses, bufp, stat, dbufp);
418}
419
420static inline int
421v9fs_size_fcall(struct v9fs_session_info *v9ses, struct v9fs_fcall *fcall)
422{
423 int size = 4 + 1 + 2; /* size[4] msg[1] tag[2] */
424 int i = 0;
425
426 switch (fcall->id) {
427 default:
428 eprintk(KERN_ERR, "bad msg type %d\n", fcall->id);
429 return 0;
430 case TVERSION: /* msize[4] version[s] */
431 size += 4 + 2 + strlen(fcall->params.tversion.version);
432 break;
433 case TAUTH: /* afid[4] uname[s] aname[s] */
434 size += 4 + 2 + strlen(fcall->params.tauth.uname) +
435 2 + strlen(fcall->params.tauth.aname);
436 break;
437 case TFLUSH: /* oldtag[2] */
438 size += 2;
439 break;
440 case TATTACH: /* fid[4] afid[4] uname[s] aname[s] */
441 size += 4 + 4 + 2 + strlen(fcall->params.tattach.uname) +
442 2 + strlen(fcall->params.tattach.aname);
443 break;
444 case TWALK: /* fid[4] newfid[4] nwname[2] nwname*(wname[s]) */
445 size += 4 + 4 + 2;
446 /* now compute total for the array of names */
447 for (i = 0; i < fcall->params.twalk.nwname; i++)
448 size += 2 + strlen(fcall->params.twalk.wnames[i]);
449 break;
450 case TOPEN: /* fid[4] mode[1] */
451 size += 4 + 1;
452 break;
453 case TCREATE: /* fid[4] name[s] perm[4] mode[1] */
454 size += 4 + 2 + strlen(fcall->params.tcreate.name) + 4 + 1;
455 break;
456 case TREAD: /* fid[4] offset[8] count[4] */
457 size += 4 + 8 + 4;
458 break;
459 case TWRITE: /* fid[4] offset[8] count[4] data[count] */
460 size += 4 + 8 + 4 + fcall->params.twrite.count;
461 break;
462 case TCLUNK: /* fid[4] */
463 size += 4;
464 break;
465 case TREMOVE: /* fid[4] */
466 size += 4;
467 break;
468 case TSTAT: /* fid[4] */
469 size += 4;
470 break;
471 case TWSTAT: /* fid[4] stat[n] */
472 fcall->params.twstat.stat->size =
473 v9fs_size_stat(v9ses, fcall->params.twstat.stat);
474 size += 4 + 2 + 2 + fcall->params.twstat.stat->size;
475 }
476 return size;
477}
478
479/*
480 * v9fs_serialize_fcall - marshall fcall struct into a packet
481 * @v9ses: session information
482 * @fcall: structure to convert
483 * @data: buffer to serialize fcall into
484 * @datalen: length of buffer to serialize fcall into
485 *
486 */
487
488int
489v9fs_serialize_fcall(struct v9fs_session_info *v9ses, struct v9fs_fcall *fcall,
490 void *data, u32 datalen)
491{
492 int i = 0;
493 struct v9fs_stat *stat = NULL;
494 struct cbuf buffer;
495 struct cbuf *bufp = &buffer;
496
497 buf_init(bufp, data, datalen);
498
499 if (!fcall) {
500 eprintk(KERN_ERR, "no fcall\n");
501 return -EINVAL;
502 }
503
504 fcall->size = v9fs_size_fcall(v9ses, fcall);
505
506 buf_put_int32(bufp, fcall->size);
507 buf_put_int8(bufp, fcall->id);
508 buf_put_int16(bufp, fcall->tag);
509
510 dprintk(DEBUG_CONV, "size %d id %d tag %d\n", fcall->size, fcall->id,
511 fcall->tag);
512
513 /* now encode it */
514 switch (fcall->id) {
515 default:
516 eprintk(KERN_ERR, "bad msg type: %d\n", fcall->id);
517 return -EPROTO;
518 case TVERSION:
519 buf_put_int32(bufp, fcall->params.tversion.msize);
520 buf_put_string(bufp, fcall->params.tversion.version);
521 break;
522 case TAUTH:
523 buf_put_int32(bufp, fcall->params.tauth.afid);
524 buf_put_string(bufp, fcall->params.tauth.uname);
525 buf_put_string(bufp, fcall->params.tauth.aname);
526 break;
527 case TFLUSH:
528 buf_put_int16(bufp, fcall->params.tflush.oldtag);
529 break;
530 case TATTACH:
531 buf_put_int32(bufp, fcall->params.tattach.fid);
532 buf_put_int32(bufp, fcall->params.tattach.afid);
533 buf_put_string(bufp, fcall->params.tattach.uname);
534 buf_put_string(bufp, fcall->params.tattach.aname);
535 break;
536 case TWALK:
537 buf_put_int32(bufp, fcall->params.twalk.fid);
538 buf_put_int32(bufp, fcall->params.twalk.newfid);
539 buf_put_int16(bufp, fcall->params.twalk.nwname);
540 for (i = 0; i < fcall->params.twalk.nwname; i++)
541 buf_put_string(bufp, fcall->params.twalk.wnames[i]);
542 break;
543 case TOPEN:
544 buf_put_int32(bufp, fcall->params.topen.fid);
545 buf_put_int8(bufp, fcall->params.topen.mode);
546 break;
547 case TCREATE:
548 buf_put_int32(bufp, fcall->params.tcreate.fid);
549 buf_put_string(bufp, fcall->params.tcreate.name);
550 buf_put_int32(bufp, fcall->params.tcreate.perm);
551 buf_put_int8(bufp, fcall->params.tcreate.mode);
552 break;
553 case TREAD:
554 buf_put_int32(bufp, fcall->params.tread.fid);
555 buf_put_int64(bufp, fcall->params.tread.offset);
556 buf_put_int32(bufp, fcall->params.tread.count);
557 break;
558 case TWRITE:
559 buf_put_int32(bufp, fcall->params.twrite.fid);
560 buf_put_int64(bufp, fcall->params.twrite.offset);
561 buf_put_int32(bufp, fcall->params.twrite.count);
562 buf_put_data(bufp, fcall->params.twrite.data,
563 fcall->params.twrite.count);
564 break;
565 case TCLUNK:
566 buf_put_int32(bufp, fcall->params.tclunk.fid);
567 break;
568 case TREMOVE:
569 buf_put_int32(bufp, fcall->params.tremove.fid);
570 break;
571 case TSTAT:
572 buf_put_int32(bufp, fcall->params.tstat.fid);
573 break;
574 case TWSTAT:
575 buf_put_int32(bufp, fcall->params.twstat.fid);
576 stat = fcall->params.twstat.stat;
577
578 buf_put_int16(bufp, stat->size + 2);
579 serialize_stat(v9ses, stat, bufp);
580 break;
581 }
582
583 if (buf_check_overflow(bufp))
584 return -EIO;
585
586 return fcall->size;
587}
588
589/**
590 * deserialize_fcall - unmarshal a response
591 * @v9ses: session information
592 * @msgsize: size of rcall message
593 * @buf: recieved buffer
594 * @buflen: length of received buffer
595 * @rcall: fcall structure to populate
596 * @rcalllen: length of fcall structure to populate
597 *
598 */
599
600int
601v9fs_deserialize_fcall(struct v9fs_session_info *v9ses, u32 msgsize,
602 void *buf, u32 buflen, struct v9fs_fcall *rcall,
603 int rcalllen)
604{
605
606 struct cbuf buffer;
607 struct cbuf *bufp = &buffer;
608 struct cbuf dbuffer;
609 struct cbuf *dbufp = &dbuffer;
610 int i = 0;
611
612 buf_init(bufp, buf, buflen);
613 buf_init(dbufp, (char *)rcall + sizeof(struct v9fs_fcall),
614 rcalllen - sizeof(struct v9fs_fcall));
615
616 rcall->size = msgsize;
617 rcall->id = buf_get_int8(bufp);
618 rcall->tag = buf_get_int16(bufp);
619
620 dprintk(DEBUG_CONV, "size %d id %d tag %d\n", rcall->size, rcall->id,
621 rcall->tag);
622 switch (rcall->id) {
623 default:
624 eprintk(KERN_ERR, "unknown message type: %d\n", rcall->id);
625 return -EPROTO;
626 case RVERSION:
627 rcall->params.rversion.msize = buf_get_int32(bufp);
628 rcall->params.rversion.version = buf_get_stringb(bufp, dbufp);
629 break;
630 case RFLUSH:
631 break;
632 case RATTACH:
633 rcall->params.rattach.qid.type = buf_get_int8(bufp);
634 rcall->params.rattach.qid.version = buf_get_int32(bufp);
635 rcall->params.rattach.qid.path = buf_get_int64(bufp);
636 break;
637 case RWALK:
638 rcall->params.rwalk.nwqid = buf_get_int16(bufp);
639 rcall->params.rwalk.wqids = buf_alloc(bufp,
640 rcall->params.rwalk.nwqid * sizeof(struct v9fs_qid));
641 if (rcall->params.rwalk.wqids)
642 for (i = 0; i < rcall->params.rwalk.nwqid; i++) {
643 rcall->params.rwalk.wqids[i].type =
644 buf_get_int8(bufp);
645 rcall->params.rwalk.wqids[i].version =
646 buf_get_int16(bufp);
647 rcall->params.rwalk.wqids[i].path =
648 buf_get_int64(bufp);
649 }
650 break;
651 case ROPEN:
652 rcall->params.ropen.qid.type = buf_get_int8(bufp);
653 rcall->params.ropen.qid.version = buf_get_int32(bufp);
654 rcall->params.ropen.qid.path = buf_get_int64(bufp);
655 rcall->params.ropen.iounit = buf_get_int32(bufp);
656 break;
657 case RCREATE:
658 rcall->params.rcreate.qid.type = buf_get_int8(bufp);
659 rcall->params.rcreate.qid.version = buf_get_int32(bufp);
660 rcall->params.rcreate.qid.path = buf_get_int64(bufp);
661 rcall->params.rcreate.iounit = buf_get_int32(bufp);
662 break;
663 case RREAD:
664 rcall->params.rread.count = buf_get_int32(bufp);
665 rcall->params.rread.data = buf_get_datab(bufp, dbufp,
666 rcall->params.rread.count);
667 break;
668 case RWRITE:
669 rcall->params.rwrite.count = buf_get_int32(bufp);
670 break;
671 case RCLUNK:
672 break;
673 case RREMOVE:
674 break;
675 case RSTAT:
676 buf_get_int16(bufp);
677 rcall->params.rstat.stat =
678 deserialize_statb(v9ses, bufp, dbufp);
679 break;
680 case RWSTAT:
681 break;
682 case RERROR:
683 rcall->params.rerror.error = buf_get_stringb(bufp, dbufp);
684 if (v9ses->extended)
685 rcall->params.rerror.errno = buf_get_int16(bufp);
686 break;
687 }
688
689 if (buf_check_overflow(bufp) || buf_check_overflow(dbufp))
690 return -EIO;
691
692 return rcall->size;
693}
diff --git a/fs/9p/conv.h b/fs/9p/conv.h
new file mode 100644
index 0000000000..ee849613c6
--- /dev/null
+++ b/fs/9p/conv.h
@@ -0,0 +1,36 @@
1/*
2 * linux/fs/9p/conv.h
3 *
4 * 9P protocol conversion definitions
5 *
6 * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
7 * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to:
21 * Free Software Foundation
22 * 51 Franklin Street, Fifth Floor
23 * Boston, MA 02111-1301 USA
24 *
25 */
26
27int v9fs_deserialize_stat(struct v9fs_session_info *, void *buf,
28 u32 buflen, struct v9fs_stat *stat, u32 statlen);
29int v9fs_serialize_fcall(struct v9fs_session_info *, struct v9fs_fcall *tcall,
30 void *buf, u32 buflen);
31int v9fs_deserialize_fcall(struct v9fs_session_info *, u32 msglen,
32 void *buf, u32 buflen, struct v9fs_fcall *rcall,
33 int rcalllen);
34
35/* this one is actually in error.c right now */
36int v9fs_errstr2errno(char *errstr);
diff --git a/fs/9p/debug.h b/fs/9p/debug.h
new file mode 100644
index 0000000000..4445f06919
--- /dev/null
+++ b/fs/9p/debug.h
@@ -0,0 +1,70 @@
1/*
2 * linux/fs/9p/debug.h - V9FS Debug Definitions
3 *
4 * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
5 * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to:
19 * Free Software Foundation
20 * 51 Franklin Street, Fifth Floor
21 * Boston, MA 02111-1301 USA
22 *
23 */
24
25#define DEBUG_ERROR (1<<0)
26#define DEBUG_CURRENT (1<<1)
27#define DEBUG_9P (1<<2)
28#define DEBUG_VFS (1<<3)
29#define DEBUG_CONV (1<<4)
30#define DEBUG_MUX (1<<5)
31#define DEBUG_TRANS (1<<6)
32#define DEBUG_SLABS (1<<7)
33
34#define DEBUG_DUMP_PKT 0
35
36extern int v9fs_debug_level;
37
38#define dprintk(level, format, arg...) \
39do { \
40 if((v9fs_debug_level & level)==level) \
41 printk(KERN_NOTICE "-- %s (%d): " \
42 format , __FUNCTION__, current->pid , ## arg); \
43} while(0)
44
45#define eprintk(level, format, arg...) \
46do { \
47 printk(level "v9fs: %s (%d): " \
48 format , __FUNCTION__, current->pid , ## arg); \
49} while(0)
50
51#if DEBUG_DUMP_PKT
52static inline void dump_data(const unsigned char *data, unsigned int datalen)
53{
54 int i, j;
55 int len = datalen;
56
57 printk(KERN_DEBUG "data ");
58 for (i = 0; i < len; i += 4) {
59 for (j = 0; (j < 4) && (i + j < len); j++)
60 printk(KERN_DEBUG "%02x", data[i + j]);
61 printk(KERN_DEBUG " ");
62 }
63 printk(KERN_DEBUG "\n");
64}
65#else /* DEBUG_DUMP_PKT */
66static inline void dump_data(const unsigned char *data, unsigned int datalen)
67{
68
69}
70#endif /* DEBUG_DUMP_PKT */
diff --git a/fs/9p/error.c b/fs/9p/error.c
new file mode 100644
index 0000000000..fee5d19179
--- /dev/null
+++ b/fs/9p/error.c
@@ -0,0 +1,93 @@
1/*
2 * linux/fs/9p/error.c
3 *
4 * Error string handling
5 *
6 * Plan 9 uses error strings, Unix uses error numbers. These functions
7 * try to help manage that and provide for dynamically adding error
8 * mappings.
9 *
10 * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
11 * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to:
25 * Free Software Foundation
26 * 51 Franklin Street, Fifth Floor
27 * Boston, MA 02111-1301 USA
28 *
29 */
30
31#include <linux/config.h>
32#include <linux/module.h>
33
34#include <linux/list.h>
35#include <linux/jhash.h>
36
37#include "debug.h"
38#include "error.h"
39
40/**
41 * v9fs_error_init - preload
42 * @errstr: error string
43 *
44 */
45
46int v9fs_error_init(void)
47{
48 struct errormap *c;
49 int bucket;
50
51 /* initialize hash table */
52 for (bucket = 0; bucket < ERRHASHSZ; bucket++)
53 INIT_HLIST_HEAD(&hash_errmap[bucket]);
54
55 /* load initial error map into hash table */
56 for (c = errmap; c->name != NULL; c++) {
57 bucket = jhash(c->name, strlen(c->name), 0) % ERRHASHSZ;
58 INIT_HLIST_NODE(&c->list);
59 hlist_add_head(&c->list, &hash_errmap[bucket]);
60 }
61
62 return 1;
63}
64
65/**
66 * errstr2errno - convert error string to error number
67 * @errstr: error string
68 *
69 */
70
71int v9fs_errstr2errno(char *errstr)
72{
73 int errno = 0;
74 struct hlist_node *p = NULL;
75 struct errormap *c = NULL;
76 int bucket = jhash(errstr, strlen(errstr), 0) % ERRHASHSZ;
77
78 hlist_for_each_entry(c, p, &hash_errmap[bucket], list) {
79 if (!strcmp(c->name, errstr)) {
80 errno = c->val;
81 break;
82 }
83 }
84
85 if (errno == 0) {
86 /* TODO: if error isn't found, add it dynamically */
87 printk(KERN_ERR "%s: errstr :%s: not found\n", __FUNCTION__,
88 errstr);
89 errno = 1;
90 }
91
92 return -errno;
93}
diff --git a/fs/9p/error.h b/fs/9p/error.h
new file mode 100644
index 0000000000..78f89acf7c
--- /dev/null
+++ b/fs/9p/error.h
@@ -0,0 +1,178 @@
1/*
2 * linux/fs/9p/error.h
3 *
4 * Huge Nasty Error Table
5 *
6 * Plan 9 uses error strings, Unix uses error numbers. This table tries to
7 * match UNIX strings and Plan 9 strings to unix error numbers. It is used
8 * to preload the dynamic error table which can also track user-specific error
9 * strings.
10 *
11 * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
12 * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to:
26 * Free Software Foundation
27 * 51 Franklin Street, Fifth Floor
28 * Boston, MA 02111-1301 USA
29 *
30 */
31
32#include <linux/errno.h>
33#include <asm/errno.h>
34
35struct errormap {
36 char *name;
37 int val;
38
39 struct hlist_node list;
40};
41
42#define ERRHASHSZ 32
43static struct hlist_head hash_errmap[ERRHASHSZ];
44
45/* FixMe - reduce to a reasonable size */
46static struct errormap errmap[] = {
47 {"Operation not permitted", EPERM},
48 {"wstat prohibited", EPERM},
49 {"No such file or directory", ENOENT},
50 {"directory entry not found", ENOENT},
51 {"file not found", ENOENT},
52 {"Interrupted system call", EINTR},
53 {"Input/output error", EIO},
54 {"No such device or address", ENXIO},
55 {"Argument list too long", E2BIG},
56 {"Bad file descriptor", EBADF},
57 {"Resource temporarily unavailable", EAGAIN},
58 {"Cannot allocate memory", ENOMEM},
59 {"Permission denied", EACCES},
60 {"Bad address", EFAULT},
61 {"Block device required", ENOTBLK},
62 {"Device or resource busy", EBUSY},
63 {"File exists", EEXIST},
64 {"Invalid cross-device link", EXDEV},
65 {"No such device", ENODEV},
66 {"Not a directory", ENOTDIR},
67 {"Is a directory", EISDIR},
68 {"Invalid argument", EINVAL},
69 {"Too many open files in system", ENFILE},
70 {"Too many open files", EMFILE},
71 {"Text file busy", ETXTBSY},
72 {"File too large", EFBIG},
73 {"No space left on device", ENOSPC},
74 {"Illegal seek", ESPIPE},
75 {"Read-only file system", EROFS},
76 {"Too many links", EMLINK},
77 {"Broken pipe", EPIPE},
78 {"Numerical argument out of domain", EDOM},
79 {"Numerical result out of range", ERANGE},
80 {"Resource deadlock avoided", EDEADLK},
81 {"File name too long", ENAMETOOLONG},
82 {"No locks available", ENOLCK},
83 {"Function not implemented", ENOSYS},
84 {"Directory not empty", ENOTEMPTY},
85 {"Too many levels of symbolic links", ELOOP},
86 {"No message of desired type", ENOMSG},
87 {"Identifier removed", EIDRM},
88 {"No data available", ENODATA},
89 {"Machine is not on the network", ENONET},
90 {"Package not installed", ENOPKG},
91 {"Object is remote", EREMOTE},
92 {"Link has been severed", ENOLINK},
93 {"Communication error on send", ECOMM},
94 {"Protocol error", EPROTO},
95 {"Bad message", EBADMSG},
96 {"File descriptor in bad state", EBADFD},
97 {"Streams pipe error", ESTRPIPE},
98 {"Too many users", EUSERS},
99 {"Socket operation on non-socket", ENOTSOCK},
100 {"Message too long", EMSGSIZE},
101 {"Protocol not available", ENOPROTOOPT},
102 {"Protocol not supported", EPROTONOSUPPORT},
103 {"Socket type not supported", ESOCKTNOSUPPORT},
104 {"Operation not supported", EOPNOTSUPP},
105 {"Protocol family not supported", EPFNOSUPPORT},
106 {"Network is down", ENETDOWN},
107 {"Network is unreachable", ENETUNREACH},
108 {"Network dropped connection on reset", ENETRESET},
109 {"Software caused connection abort", ECONNABORTED},
110 {"Connection reset by peer", ECONNRESET},
111 {"No buffer space available", ENOBUFS},
112 {"Transport endpoint is already connected", EISCONN},
113 {"Transport endpoint is not connected", ENOTCONN},
114 {"Cannot send after transport endpoint shutdown", ESHUTDOWN},
115 {"Connection timed out", ETIMEDOUT},
116 {"Connection refused", ECONNREFUSED},
117 {"Host is down", EHOSTDOWN},
118 {"No route to host", EHOSTUNREACH},
119 {"Operation already in progress", EALREADY},
120 {"Operation now in progress", EINPROGRESS},
121 {"Is a named type file", EISNAM},
122 {"Remote I/O error", EREMOTEIO},
123 {"Disk quota exceeded", EDQUOT},
124/* errors from fossil, vacfs, and u9fs */
125 {"fid unknown or out of range", EBADF},
126 {"permission denied", EACCES},
127 {"file does not exist", ENOENT},
128 {"authentication failed", ECONNREFUSED},
129 {"bad offset in directory read", ESPIPE},
130 {"bad use of fid", EBADF},
131 {"wstat can't convert between files and directories", EPERM},
132 {"directory is not empty", ENOTEMPTY},
133 {"file exists", EEXIST},
134 {"file already exists", EEXIST},
135 {"file or directory already exists", EEXIST},
136 {"fid already in use", EBADF},
137 {"file in use", ETXTBSY},
138 {"i/o error", EIO},
139 {"file already open for I/O", ETXTBSY},
140 {"illegal mode", EINVAL},
141 {"illegal name", ENAMETOOLONG},
142 {"not a directory", ENOTDIR},
143 {"not a member of proposed group", EPERM},
144 {"not owner", EACCES},
145 {"only owner can change group in wstat", EACCES},
146 {"read only file system", EROFS},
147 {"no access to special file", EPERM},
148 {"i/o count too large", EIO},
149 {"unknown group", EINVAL},
150 {"unknown user", EINVAL},
151 {"bogus wstat buffer", EPROTO},
152 {"exclusive use file already open", EAGAIN},
153 {"corrupted directory entry", EIO},
154 {"corrupted file entry", EIO},
155 {"corrupted block label", EIO},
156 {"corrupted meta data", EIO},
157 {"illegal offset", EINVAL},
158 {"illegal path element", ENOENT},
159 {"root of file system is corrupted", EIO},
160 {"corrupted super block", EIO},
161 {"protocol botch", EPROTO},
162 {"file system is full", ENOSPC},
163 {"file is in use", EAGAIN},
164 {"directory entry is not allocated", ENOENT},
165 {"file is read only", EROFS},
166 {"file has been removed", EIDRM},
167 {"only support truncation to zero length", EPERM},
168 {"cannot remove root", EPERM},
169 {"file too big", EFBIG},
170 {"venti i/o error", EIO},
171 /* these are not errors */
172 {"u9fs rhostsauth: no authentication required", 0},
173 {"u9fs authnone: no authentication required", 0},
174 {NULL, -1}
175};
176
177extern int v9fs_error_init(void);
178extern int v9fs_errstr2errno(char *errstr);
diff --git a/fs/9p/fid.c b/fs/9p/fid.c
new file mode 100644
index 0000000000..821c9c4d76
--- /dev/null
+++ b/fs/9p/fid.c
@@ -0,0 +1,241 @@
1/*
2 * V9FS FID Management
3 *
4 * Copyright (C) 2005 by Eric Van Hensbergen <ericvh@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to:
18 * Free Software Foundation
19 * 51 Franklin Street, Fifth Floor
20 * Boston, MA 02111-1301 USA
21 *
22 */
23
24#include <linux/config.h>
25#include <linux/module.h>
26#include <linux/errno.h>
27#include <linux/fs.h>
28#include <linux/idr.h>
29
30#include "debug.h"
31#include "v9fs.h"
32#include "9p.h"
33#include "v9fs_vfs.h"
34#include "transport.h"
35#include "mux.h"
36#include "conv.h"
37#include "fid.h"
38
39/**
40 * v9fs_fid_insert - add a fid to a dentry
41 * @fid: fid to add
42 * @dentry: dentry that it is being added to
43 *
44 */
45
46static int v9fs_fid_insert(struct v9fs_fid *fid, struct dentry *dentry)
47{
48 struct list_head *fid_list = (struct list_head *)dentry->d_fsdata;
49 dprintk(DEBUG_9P, "fid %d (%p) dentry %s (%p)\n", fid->fid, fid,
50 dentry->d_iname, dentry);
51 if (dentry->d_fsdata == NULL) {
52 dentry->d_fsdata =
53 kmalloc(sizeof(struct list_head), GFP_KERNEL);
54 if (dentry->d_fsdata == NULL) {
55 dprintk(DEBUG_ERROR, "Out of memory\n");
56 return -ENOMEM;
57 }
58 fid_list = (struct list_head *)dentry->d_fsdata;
59 INIT_LIST_HEAD(fid_list); /* Initialize list head */
60 }
61
62 fid->uid = current->uid;
63 fid->pid = current->pid;
64 list_add(&fid->list, fid_list);
65 return 0;
66}
67
68/**
69 * v9fs_fid_create - allocate a FID structure
70 * @dentry - dentry to link newly created fid to
71 *
72 */
73
74struct v9fs_fid *v9fs_fid_create(struct dentry *dentry)
75{
76 struct v9fs_fid *new;
77
78 new = kmalloc(sizeof(struct v9fs_fid), GFP_KERNEL);
79 if (new == NULL) {
80 dprintk(DEBUG_ERROR, "Out of Memory\n");
81 return ERR_PTR(-ENOMEM);
82 }
83
84 new->fid = -1;
85 new->fidopen = 0;
86 new->fidcreate = 0;
87 new->fidclunked = 0;
88 new->iounit = 0;
89
90 if (v9fs_fid_insert(new, dentry) == 0)
91 return new;
92 else {
93 dprintk(DEBUG_ERROR, "Problems inserting to dentry\n");
94 kfree(new);
95 return NULL;
96 }
97}
98
99/**
100 * v9fs_fid_destroy - deallocate a FID structure
101 * @fid: fid to destroy
102 *
103 */
104
105void v9fs_fid_destroy(struct v9fs_fid *fid)
106{
107 list_del(&fid->list);
108 kfree(fid);
109}
110
111/**
112 * v9fs_fid_lookup - retrieve the right fid from a particular dentry
113 * @dentry: dentry to look for fid in
114 * @type: intent of lookup (operation or traversal)
115 *
116 * search list of fids associated with a dentry for a fid with a matching
117 * thread id or uid. If that fails, look up the dentry's parents to see if you
118 * can find a matching fid.
119 *
120 */
121
122struct v9fs_fid *v9fs_fid_lookup(struct dentry *dentry, int type)
123{
124 struct list_head *fid_list = (struct list_head *)dentry->d_fsdata;
125 struct v9fs_fid *current_fid = NULL;
126 struct v9fs_fid *temp = NULL;
127 struct v9fs_fid *return_fid = NULL;
128 int found_parent = 0;
129 int found_user = 0;
130
131 dprintk(DEBUG_9P, " dentry: %s (%p) type %d\n", dentry->d_iname, dentry,
132 type);
133
134 if (fid_list && !list_empty(fid_list)) {
135 list_for_each_entry_safe(current_fid, temp, fid_list, list) {
136 if (current_fid->uid == current->uid) {
137 if (return_fid == NULL) {
138 if ((type == FID_OP)
139 || (!current_fid->fidopen)) {
140 return_fid = current_fid;
141 found_user = 1;
142 }
143 }
144 }
145 if (current_fid->pid == current->real_parent->pid) {
146 if ((return_fid == NULL) || (found_parent)
147 || (found_user)) {
148 if ((type == FID_OP)
149 || (!current_fid->fidopen)) {
150 return_fid = current_fid;
151 found_parent = 1;
152 found_user = 0;
153 }
154 }
155 }
156 if (current_fid->pid == current->pid) {
157 if ((type == FID_OP) ||
158 (!current_fid->fidopen)) {
159 return_fid = current_fid;
160 found_parent = 0;
161 found_user = 0;
162 }
163 }
164 }
165 }
166
167 /* we are at the root but didn't match */
168 if ((!return_fid) && (dentry->d_parent == dentry)) {
169 /* TODO: clone attach with new uid */
170 return_fid = current_fid;
171 }
172
173 if (!return_fid) {
174 struct dentry *par = current->fs->pwd->d_parent;
175 int count = 1;
176 while (par != NULL) {
177 if (par == dentry)
178 break;
179 count++;
180 if (par == par->d_parent) {
181 dprintk(DEBUG_ERROR,
182 "got to root without finding dentry\n");
183 break;
184 }
185 par = par->d_parent;
186 }
187
188/* XXX - there may be some duplication we can get rid of */
189 if (par == dentry) {
190 /* we need to fid_lookup the starting point */
191 int fidnum = -1;
192 int oldfid = -1;
193 int result = -1;
194 struct v9fs_session_info *v9ses =
195 v9fs_inode2v9ses(current->fs->pwd->d_inode);
196
197 current_fid =
198 v9fs_fid_lookup(current->fs->pwd, FID_WALK);
199 if (current_fid == NULL) {
200 dprintk(DEBUG_ERROR,
201 "process cwd doesn't have a fid\n");
202 return return_fid;
203 }
204 oldfid = current_fid->fid;
205 par = current->fs->pwd;
206 /* TODO: take advantage of multiwalk */
207
208 fidnum = v9fs_get_idpool(&v9ses->fidpool);
209 if (fidnum < 0) {
210 dprintk(DEBUG_ERROR,
211 "could not get a new fid num\n");
212 return return_fid;
213 }
214
215 while (par != dentry) {
216 result =
217 v9fs_t_walk(v9ses, oldfid, fidnum, "..",
218 NULL);
219 if (result < 0) {
220 dprintk(DEBUG_ERROR,
221 "problem walking to parent\n");
222
223 break;
224 }
225 oldfid = fidnum;
226 if (par == par->d_parent) {
227 dprintk(DEBUG_ERROR,
228 "can't find dentry\n");
229 break;
230 }
231 par = par->d_parent;
232 }
233 if (par == dentry) {
234 return_fid = v9fs_fid_create(dentry);
235 return_fid->fid = fidnum;
236 }
237 }
238 }
239
240 return return_fid;
241}
diff --git a/fs/9p/fid.h b/fs/9p/fid.h
new file mode 100644
index 0000000000..7db478ccca
--- /dev/null
+++ b/fs/9p/fid.h
@@ -0,0 +1,57 @@
1/*
2 * V9FS FID Management
3 *
4 * Copyright (C) 2005 by Eric Van Hensbergen <ericvh@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to:
18 * Free Software Foundation
19 * 51 Franklin Street, Fifth Floor
20 * Boston, MA 02111-1301 USA
21 *
22 */
23
24#include <linux/list.h>
25
26#define FID_OP 0
27#define FID_WALK 1
28
29struct v9fs_fid {
30 struct list_head list; /* list of fids associated with a dentry */
31 struct list_head active; /* XXX - debug */
32
33 u32 fid;
34 unsigned char fidopen; /* set when fid is opened */
35 unsigned char fidcreate; /* set when fid was just created */
36 unsigned char fidclunked; /* set when fid has already been clunked */
37
38 struct v9fs_qid qid;
39 u32 iounit;
40
41 /* readdir stuff */
42 int rdir_fpos;
43 loff_t rdir_pos;
44 struct v9fs_fcall *rdir_fcall;
45
46 /* management stuff */
47 pid_t pid; /* thread associated with this fid */
48 uid_t uid; /* user associated with this fid */
49
50 /* private data */
51 struct file *filp; /* backpointer to File struct for open files */
52 struct v9fs_session_info *v9ses; /* session info for this FID */
53};
54
55struct v9fs_fid *v9fs_fid_lookup(struct dentry *dentry, int type);
56void v9fs_fid_destroy(struct v9fs_fid *fid);
57struct v9fs_fid *v9fs_fid_create(struct dentry *);
diff --git a/fs/9p/mux.c b/fs/9p/mux.c
new file mode 100644
index 0000000000..8835b576f7
--- /dev/null
+++ b/fs/9p/mux.c
@@ -0,0 +1,475 @@
1/*
2 * linux/fs/9p/mux.c
3 *
4 * Protocol Multiplexer
5 *
6 * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
7 * Copyright (C) 2004 by Latchesar Ionkov <lucho@ionkov.net>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to:
21 * Free Software Foundation
22 * 51 Franklin Street, Fifth Floor
23 * Boston, MA 02111-1301 USA
24 *
25 */
26
27#include <linux/config.h>
28#include <linux/module.h>
29#include <linux/errno.h>
30#include <linux/fs.h>
31#include <linux/kthread.h>
32#include <linux/idr.h>
33
34#include "debug.h"
35#include "v9fs.h"
36#include "9p.h"
37#include "transport.h"
38#include "conv.h"
39#include "mux.h"
40
41/**
42 * dprintcond - print condition of session info
43 * @v9ses: session info structure
44 * @req: RPC request structure
45 *
46 */
47
48static inline int
49dprintcond(struct v9fs_session_info *v9ses, struct v9fs_rpcreq *req)
50{
51 dprintk(DEBUG_MUX, "condition: %d, %p\n", v9ses->transport->status,
52 req->rcall);
53 return 0;
54}
55
56/**
57 * xread - force read of a certain number of bytes
58 * @v9ses: session info structure
59 * @ptr: pointer to buffer
60 * @sz: number of bytes to read
61 *
62 * Chuck Cranor CS-533 project1
63 */
64
65static int xread(struct v9fs_session_info *v9ses, void *ptr, unsigned long sz)
66{
67 int rd = 0;
68 int ret = 0;
69 while (rd < sz) {
70 ret = v9ses->transport->read(v9ses->transport, ptr, sz - rd);
71 if (ret <= 0) {
72 dprintk(DEBUG_ERROR, "xread errno %d\n", ret);
73 return ret;
74 }
75 rd += ret;
76 ptr += ret;
77 }
78 return (rd);
79}
80
81/**
82 * read_message - read a full 9P2000 fcall packet
83 * @v9ses: session info structure
84 * @rcall: fcall structure to read into
85 * @rcalllen: size of fcall buffer
86 *
87 */
88
89static int
90read_message(struct v9fs_session_info *v9ses,
91 struct v9fs_fcall *rcall, int rcalllen)
92{
93 unsigned char buf[4];
94 void *data;
95 int size = 0;
96 int res = 0;
97
98 res = xread(v9ses, buf, sizeof(buf));
99 if (res < 0) {
100 dprintk(DEBUG_ERROR,
101 "Reading of count field failed returned: %d\n", res);
102 return res;
103 }
104
105 if (res < 4) {
106 dprintk(DEBUG_ERROR,
107 "Reading of count field failed returned: %d\n", res);
108 return -EIO;
109 }
110
111 size = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
112 dprintk(DEBUG_MUX, "got a packet count: %d\n", size);
113
114 /* adjust for the four bytes of size */
115 size -= 4;
116
117 if (size > v9ses->maxdata) {
118 dprintk(DEBUG_ERROR, "packet too big: %d\n", size);
119 return -E2BIG;
120 }
121
122 data = kmalloc(size, GFP_KERNEL);
123 if (!data) {
124 eprintk(KERN_WARNING, "out of memory\n");
125 return -ENOMEM;
126 }
127
128 res = xread(v9ses, data, size);
129 if (res < size) {
130 dprintk(DEBUG_ERROR, "Reading of fcall failed returned: %d\n",
131 res);
132 kfree(data);
133 return res;
134 }
135
136 /* we now have an in-memory string that is the reply.
137 * deserialize it. There is very little to go wrong at this point
138 * save for v9fs_alloc errors.
139 */
140 res = v9fs_deserialize_fcall(v9ses, size, data, v9ses->maxdata,
141 rcall, rcalllen);
142
143 kfree(data);
144
145 if (res < 0)
146 return res;
147
148 return 0;
149}
150
151/**
152 * v9fs_recv - receive an RPC response for a particular tag
153 * @v9ses: session info structure
154 * @req: RPC request structure
155 *
156 */
157
158static int v9fs_recv(struct v9fs_session_info *v9ses, struct v9fs_rpcreq *req)
159{
160 int ret = 0;
161
162 dprintk(DEBUG_MUX, "waiting for response: %d\n", req->tcall->tag);
163 ret = wait_event_interruptible(v9ses->read_wait,
164 ((v9ses->transport->status != Connected) ||
165 (req->rcall != 0) || (req->err < 0) ||
166 dprintcond(v9ses, req)));
167
168 dprintk(DEBUG_MUX, "got it: rcall %p\n", req->rcall);
169
170 spin_lock(&v9ses->muxlock);
171 list_del(&req->next);
172 spin_unlock(&v9ses->muxlock);
173
174 if (req->err < 0)
175 return req->err;
176
177 if (v9ses->transport->status == Disconnected)
178 return -ECONNRESET;
179
180 return ret;
181}
182
183/**
184 * v9fs_send - send a 9P request
185 * @v9ses: session info structure
186 * @req: RPC request to send
187 *
188 */
189
190static int v9fs_send(struct v9fs_session_info *v9ses, struct v9fs_rpcreq *req)
191{
192 int ret = -1;
193 void *data = NULL;
194 struct v9fs_fcall *tcall = req->tcall;
195
196 data = kmalloc(v9ses->maxdata + V9FS_IOHDRSZ, GFP_KERNEL);
197 if (!data)
198 return -ENOMEM;
199
200 tcall->size = 0; /* enforce size recalculation */
201 ret =
202 v9fs_serialize_fcall(v9ses, tcall, data,
203 v9ses->maxdata + V9FS_IOHDRSZ);
204 if (ret < 0)
205 goto free_data;
206
207 spin_lock(&v9ses->muxlock);
208 list_add(&req->next, &v9ses->mux_fcalls);
209 spin_unlock(&v9ses->muxlock);
210
211 dprintk(DEBUG_MUX, "sending message: tag %d size %d\n", tcall->tag,
212 tcall->size);
213 ret = v9ses->transport->write(v9ses->transport, data, tcall->size);
214
215 if (ret != tcall->size) {
216 spin_lock(&v9ses->muxlock);
217 list_del(&req->next);
218 kfree(req->rcall);
219
220 spin_unlock(&v9ses->muxlock);
221 if (ret >= 0)
222 ret = -EREMOTEIO;
223 } else
224 ret = 0;
225
226 free_data:
227 kfree(data);
228 return ret;
229}
230
231/**
232 * v9fs_mux_rpc - send a request, receive a response
233 * @v9ses: session info structure
234 * @tcall: fcall to send
235 * @rcall: buffer to place response into
236 *
237 */
238
239long
240v9fs_mux_rpc(struct v9fs_session_info *v9ses, struct v9fs_fcall *tcall,
241 struct v9fs_fcall **rcall)
242{
243 int tid = -1;
244 struct v9fs_fcall *fcall = NULL;
245 struct v9fs_rpcreq req;
246 int ret = -1;
247
248 if (!v9ses)
249 return -EINVAL;
250
251 if (!v9ses->transport || v9ses->transport->status != Connected)
252 return -EIO;
253
254 if (rcall)
255 *rcall = NULL;
256
257 if (tcall->id != TVERSION) {
258 tid = v9fs_get_idpool(&v9ses->tidpool);
259 if (tid < 0)
260 return -ENOMEM;
261 }
262
263 tcall->tag = tid;
264
265 req.tcall = tcall;
266 req.err = 0;
267 req.rcall = NULL;
268
269 ret = v9fs_send(v9ses, &req);
270
271 if (ret < 0) {
272 if (tcall->id != TVERSION)
273 v9fs_put_idpool(tid, &v9ses->tidpool);
274 dprintk(DEBUG_MUX, "error %d\n", ret);
275 return ret;
276 }
277
278 ret = v9fs_recv(v9ses, &req);
279
280 fcall = req.rcall;
281
282 dprintk(DEBUG_MUX, "received: tag=%x, ret=%d\n", tcall->tag, ret);
283 if (ret == -ERESTARTSYS) {
284 if (v9ses->transport->status != Disconnected
285 && tcall->id != TFLUSH) {
286 unsigned long flags;
287
288 dprintk(DEBUG_MUX, "flushing the tag: %d\n",
289 tcall->tag);
290 clear_thread_flag(TIF_SIGPENDING);
291 v9fs_t_flush(v9ses, tcall->tag);
292 spin_lock_irqsave(&current->sighand->siglock, flags);
293 recalc_sigpending();
294 spin_unlock_irqrestore(&current->sighand->siglock,
295 flags);
296 dprintk(DEBUG_MUX, "flushing done\n");
297 }
298
299 goto release_req;
300 } else if (ret < 0)
301 goto release_req;
302
303 if (!fcall)
304 ret = -EIO;
305 else {
306 if (fcall->id == RERROR) {
307 ret = v9fs_errstr2errno(fcall->params.rerror.error);
308 if (ret == 0) { /* string match failed */
309 if (fcall->params.rerror.errno)
310 ret = -(fcall->params.rerror.errno);
311 else
312 ret = -ESERVERFAULT;
313 }
314 } else if (fcall->id != tcall->id + 1) {
315 dprintk(DEBUG_ERROR,
316 "fcall mismatch: expected %d, got %d\n",
317 tcall->id + 1, fcall->id);
318 ret = -EIO;
319 }
320 }
321
322 release_req:
323 if (tcall->id != TVERSION)
324 v9fs_put_idpool(tid, &v9ses->tidpool);
325 if (rcall)
326 *rcall = fcall;
327 else
328 kfree(fcall);
329
330 return ret;
331}
332
333/**
334 * v9fs_mux_cancel_requests - cancels all pending requests
335 *
336 * @v9ses: session info structure
337 * @err: error code to return to the requests
338 */
339void v9fs_mux_cancel_requests(struct v9fs_session_info *v9ses, int err)
340{
341 struct v9fs_rpcreq *rptr;
342 struct v9fs_rpcreq *rreq;
343
344 dprintk(DEBUG_MUX, " %d\n", err);
345 spin_lock(&v9ses->muxlock);
346 list_for_each_entry_safe(rreq, rptr, &v9ses->mux_fcalls, next) {
347 rreq->err = err;
348 }
349 spin_unlock(&v9ses->muxlock);
350 wake_up_all(&v9ses->read_wait);
351}
352
353/**
354 * v9fs_recvproc - kproc to handle demultiplexing responses
355 * @data: session info structure
356 *
357 */
358
359static int v9fs_recvproc(void *data)
360{
361 struct v9fs_session_info *v9ses = (struct v9fs_session_info *)data;
362 struct v9fs_fcall *rcall = NULL;
363 struct v9fs_rpcreq *rptr;
364 struct v9fs_rpcreq *req;
365 struct v9fs_rpcreq *rreq;
366 int err = 0;
367
368 allow_signal(SIGKILL);
369 set_current_state(TASK_INTERRUPTIBLE);
370 complete(&v9ses->proccmpl);
371 while (!kthread_should_stop() && err >= 0) {
372 req = rptr = rreq = NULL;
373
374 rcall = kmalloc(v9ses->maxdata + V9FS_IOHDRSZ, GFP_KERNEL);
375 if (!rcall) {
376 eprintk(KERN_ERR, "no memory for buffers\n");
377 break;
378 }
379
380 err = read_message(v9ses, rcall, v9ses->maxdata + V9FS_IOHDRSZ);
381 spin_lock(&v9ses->muxlock);
382 if (err < 0) {
383 list_for_each_entry_safe(rreq, rptr, &v9ses->mux_fcalls, next) {
384 rreq->err = err;
385 }
386 if(err != -ERESTARTSYS)
387 eprintk(KERN_ERR,
388 "Transport error while reading message %d\n", err);
389 } else {
390 list_for_each_entry_safe(rreq, rptr, &v9ses->mux_fcalls, next) {
391 if (rreq->tcall->tag == rcall->tag) {
392 req = rreq;
393 req->rcall = rcall;
394 break;
395 }
396 }
397 }
398
399 if (req && (req->tcall->id == TFLUSH)) {
400 struct v9fs_rpcreq *treq = NULL;
401 list_for_each_entry_safe(treq, rptr, &v9ses->mux_fcalls, next) {
402 if (treq->tcall->tag ==
403 req->tcall->params.tflush.oldtag) {
404 list_del(&rptr->next);
405 kfree(treq->rcall);
406 break;
407 }
408 }
409 }
410
411 spin_unlock(&v9ses->muxlock);
412
413 if (!req) {
414 if (err >= 0)
415 dprintk(DEBUG_ERROR,
416 "unexpected response: id %d tag %d\n",
417 rcall->id, rcall->tag);
418
419 kfree(rcall);
420 }
421
422 wake_up_all(&v9ses->read_wait);
423 set_current_state(TASK_INTERRUPTIBLE);
424 }
425
426 v9ses->transport->close(v9ses->transport);
427
428 /* Inform all pending processes about the failure */
429 wake_up_all(&v9ses->read_wait);
430
431 if (signal_pending(current))
432 complete(&v9ses->proccmpl);
433
434 dprintk(DEBUG_MUX, "recvproc: end\n");
435 v9ses->recvproc = NULL;
436
437 return err >= 0;
438}
439
440/**
441 * v9fs_mux_init - initialize multiplexer (spawn kproc)
442 * @v9ses: session info structure
443 * @dev_name: mount device information (to create unique kproc)
444 *
445 */
446
447int v9fs_mux_init(struct v9fs_session_info *v9ses, const char *dev_name)
448{
449 char procname[60];
450
451 strncpy(procname, dev_name, sizeof(procname));
452 procname[sizeof(procname) - 1] = 0;
453
454 init_waitqueue_head(&v9ses->read_wait);
455 init_completion(&v9ses->fcread);
456 init_completion(&v9ses->proccmpl);
457 spin_lock_init(&v9ses->muxlock);
458 INIT_LIST_HEAD(&v9ses->mux_fcalls);
459 v9ses->recvproc = NULL;
460 v9ses->curfcall = NULL;
461
462 v9ses->recvproc = kthread_create(v9fs_recvproc, v9ses,
463 "v9fs_recvproc %s", procname);
464
465 if (IS_ERR(v9ses->recvproc)) {
466 eprintk(KERN_ERR, "cannot create receiving thread\n");
467 v9fs_session_close(v9ses);
468 return -ECONNABORTED;
469 }
470
471 wake_up_process(v9ses->recvproc);
472 wait_for_completion(&v9ses->proccmpl);
473
474 return 0;
475}
diff --git a/fs/9p/mux.h b/fs/9p/mux.h
new file mode 100644
index 0000000000..4994cb10ba
--- /dev/null
+++ b/fs/9p/mux.h
@@ -0,0 +1,41 @@
1/*
2 * linux/fs/9p/mux.h
3 *
4 * Multiplexer Definitions
5 *
6 * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to:
20 * Free Software Foundation
21 * 51 Franklin Street, Fifth Floor
22 * Boston, MA 02111-1301 USA
23 *
24 */
25
26/* structure to manage each RPC transaction */
27
28struct v9fs_rpcreq {
29 struct v9fs_fcall *tcall;
30 struct v9fs_fcall *rcall;
31 int err; /* error code if response failed */
32
33 /* XXX - could we put scatter/gather buffers here? */
34
35 struct list_head next;
36};
37
38int v9fs_mux_init(struct v9fs_session_info *v9ses, const char *dev_name);
39long v9fs_mux_rpc(struct v9fs_session_info *v9ses,
40 struct v9fs_fcall *tcall, struct v9fs_fcall **rcall);
41void v9fs_mux_cancel_requests(struct v9fs_session_info *v9ses, int err);
diff --git a/fs/9p/trans_fd.c b/fs/9p/trans_fd.c
new file mode 100644
index 0000000000..63b58ce98f
--- /dev/null
+++ b/fs/9p/trans_fd.c
@@ -0,0 +1,172 @@
1/*
2 * linux/fs/9p/trans_fd.c
3 *
4 * File Descriptor Transport Layer
5 *
6 * Copyright (C) 2005 by Eric Van Hensbergen <ericvh@gmail.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to:
20 * Free Software Foundation
21 * 51 Franklin Street, Fifth Floor
22 * Boston, MA 02111-1301 USA
23 *
24 */
25
26#include <linux/config.h>
27#include <linux/module.h>
28#include <linux/net.h>
29#include <linux/ipv6.h>
30#include <linux/errno.h>
31#include <linux/kernel.h>
32#include <linux/un.h>
33#include <asm/uaccess.h>
34#include <linux/inet.h>
35#include <linux/idr.h>
36#include <linux/file.h>
37
38#include "debug.h"
39#include "v9fs.h"
40#include "transport.h"
41
42struct v9fs_trans_fd {
43 struct file *in_file;
44 struct file *out_file;
45};
46
47/**
48 * v9fs_fd_recv - receive from a socket
49 * @v9ses: session information
50 * @v: buffer to receive data into
51 * @len: size of receive buffer
52 *
53 */
54
55static int v9fs_fd_recv(struct v9fs_transport *trans, void *v, int len)
56{
57 struct v9fs_trans_fd *ts = trans ? trans->priv : NULL;
58
59 if (!trans || trans->status != Connected || !ts)
60 return -EIO;
61
62 return kernel_read(ts->in_file, ts->in_file->f_pos, v, len);
63}
64
65/**
66 * v9fs_fd_send - send to a socket
67 * @v9ses: session information
68 * @v: buffer to send data from
69 * @len: size of send buffer
70 *
71 */
72
73static int v9fs_fd_send(struct v9fs_transport *trans, void *v, int len)
74{
75 struct v9fs_trans_fd *ts = trans ? trans->priv : NULL;
76 mm_segment_t oldfs = get_fs();
77 int ret = 0;
78
79 if (!trans || trans->status != Connected || !ts)
80 return -EIO;
81
82 set_fs(get_ds());
83 /* The cast to a user pointer is valid due to the set_fs() */
84 ret = vfs_write(ts->out_file, (void __user *)v, len, &ts->out_file->f_pos);
85 set_fs(oldfs);
86
87 return ret;
88}
89
90/**
91 * v9fs_fd_init - initialize file descriptor transport
92 * @v9ses: session information
93 * @addr: address of server to mount
94 * @data: mount options
95 *
96 */
97
98static int
99v9fs_fd_init(struct v9fs_session_info *v9ses, const char *addr, char *data)
100{
101 struct v9fs_trans_fd *ts = NULL;
102 struct v9fs_transport *trans = v9ses->transport;
103
104 if((v9ses->wfdno == ~0) || (v9ses->rfdno == ~0)) {
105 printk(KERN_ERR "v9fs: Insufficient options for proto=fd\n");
106 return -ENOPROTOOPT;
107 }
108
109 sema_init(&trans->writelock, 1);
110 sema_init(&trans->readlock, 1);
111
112 ts = kmalloc(sizeof(struct v9fs_trans_fd), GFP_KERNEL);
113
114 if (!ts)
115 return -ENOMEM;
116
117 ts->in_file = fget( v9ses->rfdno );
118 ts->out_file = fget( v9ses->wfdno );
119
120 if (!ts->in_file || !ts->out_file) {
121 if (ts->in_file)
122 fput(ts->in_file);
123
124 if (ts->out_file)
125 fput(ts->out_file);
126
127 kfree(ts);
128 return -EIO;
129 }
130
131 trans->priv = ts;
132 trans->status = Connected;
133
134 return 0;
135}
136
137
138/**
139 * v9fs_fd_close - shutdown file descriptor
140 * @trans: private socket structure
141 *
142 */
143
144static void v9fs_fd_close(struct v9fs_transport *trans)
145{
146 struct v9fs_trans_fd *ts;
147
148 if (!trans)
149 return;
150
151 trans->status = Disconnected;
152 ts = trans->priv;
153
154 if (!ts)
155 return;
156
157 if (ts->in_file)
158 fput(ts->in_file);
159
160 if (ts->out_file)
161 fput(ts->out_file);
162
163 kfree(ts);
164}
165
166struct v9fs_transport v9fs_trans_fd = {
167 .init = v9fs_fd_init,
168 .write = v9fs_fd_send,
169 .read = v9fs_fd_recv,
170 .close = v9fs_fd_close,
171};
172
diff --git a/fs/9p/trans_sock.c b/fs/9p/trans_sock.c
new file mode 100644
index 0000000000..01e26f0013
--- /dev/null
+++ b/fs/9p/trans_sock.c
@@ -0,0 +1,290 @@
1/*
2 * linux/fs/9p/trans_socket.c
3 *
4 * Socket Transport Layer
5 *
6 * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
7 * Copyright (C) 1997-2002 by Ron Minnich <rminnich@sarnoff.com>
8 * Copyright (C) 1995, 1996 by Olaf Kirch <okir@monad.swb.de>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to:
22 * Free Software Foundation
23 * 51 Franklin Street, Fifth Floor
24 * Boston, MA 02111-1301 USA
25 *
26 */
27
28#include <linux/config.h>
29#include <linux/module.h>
30#include <linux/net.h>
31#include <linux/ipv6.h>
32#include <linux/errno.h>
33#include <linux/kernel.h>
34#include <linux/un.h>
35#include <asm/uaccess.h>
36#include <linux/inet.h>
37#include <linux/idr.h>
38
39#include "debug.h"
40#include "v9fs.h"
41#include "transport.h"
42
43#define V9FS_PORT 564
44
45struct v9fs_trans_sock {
46 struct socket *s;
47};
48
49/**
50 * v9fs_sock_recv - receive from a socket
51 * @v9ses: session information
52 * @v: buffer to receive data into
53 * @len: size of receive buffer
54 *
55 */
56
57static int v9fs_sock_recv(struct v9fs_transport *trans, void *v, int len)
58{
59 struct msghdr msg;
60 struct kvec iov;
61 int result;
62 mm_segment_t oldfs;
63 struct v9fs_trans_sock *ts = trans ? trans->priv : NULL;
64
65 if (trans->status == Disconnected)
66 return -EREMOTEIO;
67
68 result = -EINVAL;
69
70 oldfs = get_fs();
71 set_fs(get_ds());
72
73 iov.iov_base = v;
74 iov.iov_len = len;
75 msg.msg_name = NULL;
76 msg.msg_namelen = 0;
77 msg.msg_iovlen = 1;
78 msg.msg_control = NULL;
79 msg.msg_controllen = 0;
80 msg.msg_namelen = 0;
81 msg.msg_flags = MSG_NOSIGNAL;
82
83 result = kernel_recvmsg(ts->s, &msg, &iov, 1, len, 0);
84
85 dprintk(DEBUG_TRANS, "socket state %d\n", ts->s->state);
86 set_fs(oldfs);
87
88 if (result <= 0) {
89 if (result != -ERESTARTSYS)
90 trans->status = Disconnected;
91 }
92
93 return result;
94}
95
96/**
97 * v9fs_sock_send - send to a socket
98 * @v9ses: session information
99 * @v: buffer to send data from
100 * @len: size of send buffer
101 *
102 */
103
104static int v9fs_sock_send(struct v9fs_transport *trans, void *v, int len)
105{
106 struct kvec iov;
107 struct msghdr msg;
108 int result = -1;
109 mm_segment_t oldfs;
110 struct v9fs_trans_sock *ts = trans ? trans->priv : NULL;
111
112 dprintk(DEBUG_TRANS, "Sending packet size %d (%x)\n", len, len);
113 dump_data(v, len);
114
115 down(&trans->writelock);
116
117 oldfs = get_fs();
118 set_fs(get_ds());
119 iov.iov_base = v;
120 iov.iov_len = len;
121 msg.msg_name = NULL;
122 msg.msg_namelen = 0;
123 msg.msg_iovlen = 1;
124 msg.msg_control = NULL;
125 msg.msg_controllen = 0;
126 msg.msg_namelen = 0;
127 msg.msg_flags = MSG_NOSIGNAL;
128 result = kernel_sendmsg(ts->s, &msg, &iov, 1, len);
129 set_fs(oldfs);
130
131 if (result < 0) {
132 if (result != -ERESTARTSYS)
133 trans->status = Disconnected;
134 }
135
136 up(&trans->writelock);
137 return result;
138}
139
140/**
141 * v9fs_tcp_init - initialize TCP socket
142 * @v9ses: session information
143 * @addr: address of server to mount
144 * @data: mount options
145 *
146 */
147
148static int
149v9fs_tcp_init(struct v9fs_session_info *v9ses, const char *addr, char *data)
150{
151 struct socket *csocket = NULL;
152 struct sockaddr_in sin_server;
153 int rc = 0;
154 struct v9fs_trans_sock *ts = NULL;
155 struct v9fs_transport *trans = v9ses->transport;
156
157 sema_init(&trans->writelock, 1);
158 sema_init(&trans->readlock, 1);
159
160 ts = kmalloc(sizeof(struct v9fs_trans_sock), GFP_KERNEL);
161
162 if (!ts)
163 return -ENOMEM;
164
165 trans->priv = ts;
166 ts->s = NULL;
167
168 if (!addr)
169 return -EINVAL;
170
171 dprintk(DEBUG_TRANS, "Connecting to %s\n", addr);
172
173 sin_server.sin_family = AF_INET;
174 sin_server.sin_addr.s_addr = in_aton(addr);
175 sin_server.sin_port = htons(v9ses->port);
176 sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &csocket);
177 rc = csocket->ops->connect(csocket,
178 (struct sockaddr *)&sin_server,
179 sizeof(struct sockaddr_in), 0);
180 if (rc < 0) {
181 eprintk(KERN_ERR,
182 "v9fs_trans_tcp: problem connecting socket to %s\n",
183 addr);
184 return rc;
185 }
186 csocket->sk->sk_allocation = GFP_NOIO;
187 ts->s = csocket;
188 trans->status = Connected;
189
190 return 0;
191}
192
193/**
194 * v9fs_unix_init - initialize UNIX domain socket
195 * @v9ses: session information
196 * @dev_name: path to named pipe
197 * @data: mount options
198 *
199 */
200
201static int
202v9fs_unix_init(struct v9fs_session_info *v9ses, const char *dev_name,
203 char *data)
204{
205 int rc;
206 struct socket *csocket;
207 struct sockaddr_un sun_server;
208 struct v9fs_transport *trans;
209 struct v9fs_trans_sock *ts;
210
211 rc = 0;
212 csocket = NULL;
213 trans = v9ses->transport;
214
215 if (strlen(dev_name) > UNIX_PATH_MAX) {
216 eprintk(KERN_ERR, "v9fs_trans_unix: address too long: %s\n",
217 dev_name);
218 return -ENOMEM;
219 }
220
221 ts = kmalloc(sizeof(struct v9fs_trans_sock), GFP_KERNEL);
222 if (!ts)
223 return -ENOMEM;
224
225 trans->priv = ts;
226 ts->s = NULL;
227
228 sema_init(&trans->writelock, 1);
229 sema_init(&trans->readlock, 1);
230
231 sun_server.sun_family = PF_UNIX;
232 strcpy(sun_server.sun_path, dev_name);
233 sock_create_kern(PF_UNIX, SOCK_STREAM, 0, &csocket);
234 rc = csocket->ops->connect(csocket, (struct sockaddr *)&sun_server,
235 sizeof(struct sockaddr_un) - 1, 0); /* -1 *is* important */
236 if (rc < 0) {
237 eprintk(KERN_ERR,
238 "v9fs_trans_unix: problem connecting socket: %s: %d\n",
239 dev_name, rc);
240 return rc;
241 }
242 csocket->sk->sk_allocation = GFP_NOIO;
243 ts->s = csocket;
244 trans->status = Connected;
245
246 return 0;
247}
248
249/**
250 * v9fs_sock_close - shutdown socket
251 * @trans: private socket structure
252 *
253 */
254
255static void v9fs_sock_close(struct v9fs_transport *trans)
256{
257 struct v9fs_trans_sock *ts;
258
259 if (!trans)
260 return;
261
262 ts = trans->priv;
263
264 if ((ts) && (ts->s)) {
265 dprintk(DEBUG_TRANS, "closing the socket %p\n", ts->s);
266 sock_release(ts->s);
267 ts->s = NULL;
268 trans->status = Disconnected;
269 dprintk(DEBUG_TRANS, "socket closed\n");
270 }
271
272 if (ts)
273 kfree(ts);
274
275 trans->priv = NULL;
276}
277
278struct v9fs_transport v9fs_trans_tcp = {
279 .init = v9fs_tcp_init,
280 .write = v9fs_sock_send,
281 .read = v9fs_sock_recv,
282 .close = v9fs_sock_close,
283};
284
285struct v9fs_transport v9fs_trans_unix = {
286 .init = v9fs_unix_init,
287 .write = v9fs_sock_send,
288 .read = v9fs_sock_recv,
289 .close = v9fs_sock_close,
290};
diff --git a/fs/9p/transport.h b/fs/9p/transport.h
new file mode 100644
index 0000000000..9e9cd418ef
--- /dev/null
+++ b/fs/9p/transport.h
@@ -0,0 +1,46 @@
1/*
2 * linux/fs/9p/transport.h
3 *
4 * Transport Definition
5 *
6 * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to:
20 * Free Software Foundation
21 * 51 Franklin Street, Fifth Floor
22 * Boston, MA 02111-1301 USA
23 *
24 */
25
26enum v9fs_transport_status {
27 Connected,
28 Disconnected,
29 Hung,
30};
31
32struct v9fs_transport {
33 enum v9fs_transport_status status;
34 struct semaphore writelock;
35 struct semaphore readlock;
36 void *priv;
37
38 int (*init) (struct v9fs_session_info *, const char *, char *);
39 int (*write) (struct v9fs_transport *, void *, int);
40 int (*read) (struct v9fs_transport *, void *, int);
41 void (*close) (struct v9fs_transport *);
42};
43
44extern struct v9fs_transport v9fs_trans_tcp;
45extern struct v9fs_transport v9fs_trans_unix;
46extern struct v9fs_transport v9fs_trans_fd;
diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c
new file mode 100644
index 0000000000..13bdbbab43
--- /dev/null
+++ b/fs/9p/v9fs.c
@@ -0,0 +1,452 @@
1/*
2 * linux/fs/9p/v9fs.c
3 *
4 * This file contains functions assisting in mapping VFS to 9P2000
5 *
6 * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
7 * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to:
21 * Free Software Foundation
22 * 51 Franklin Street, Fifth Floor
23 * Boston, MA 02111-1301 USA
24 *
25 */
26
27#include <linux/config.h>
28#include <linux/module.h>
29#include <linux/errno.h>
30#include <linux/fs.h>
31#include <linux/parser.h>
32#include <linux/idr.h>
33
34#include "debug.h"
35#include "v9fs.h"
36#include "9p.h"
37#include "v9fs_vfs.h"
38#include "transport.h"
39#include "mux.h"
40#include "conv.h"
41
42/* TODO: sysfs or debugfs interface */
43int v9fs_debug_level = 0; /* feature-rific global debug level */
44
45/*
46 * Option Parsing (code inspired by NFS code)
47 *
48 */
49
50enum {
51 /* Options that take integer arguments */
52 Opt_port, Opt_msize, Opt_uid, Opt_gid, Opt_afid, Opt_debug,
53 Opt_rfdno, Opt_wfdno,
54 /* String options */
55 Opt_name, Opt_remotename,
56 /* Options that take no arguments */
57 Opt_legacy, Opt_nodevmap, Opt_unix, Opt_tcp, Opt_fd,
58 /* Error token */
59 Opt_err
60};
61
62static match_table_t tokens = {
63 {Opt_port, "port=%u"},
64 {Opt_msize, "msize=%u"},
65 {Opt_uid, "uid=%u"},
66 {Opt_gid, "gid=%u"},
67 {Opt_afid, "afid=%u"},
68 {Opt_rfdno, "rfdno=%u"},
69 {Opt_wfdno, "wfdno=%u"},
70 {Opt_debug, "debug=%u"},
71 {Opt_name, "name=%s"},
72 {Opt_remotename, "aname=%s"},
73 {Opt_unix, "proto=unix"},
74 {Opt_tcp, "proto=tcp"},
75 {Opt_fd, "proto=fd"},
76 {Opt_tcp, "tcp"},
77 {Opt_unix, "unix"},
78 {Opt_fd, "fd"},
79 {Opt_legacy, "noextend"},
80 {Opt_nodevmap, "nodevmap"},
81 {Opt_err, NULL}
82};
83
84/*
85 * Parse option string.
86 */
87
88/**
89 * v9fs_parse_options - parse mount options into session structure
90 * @options: options string passed from mount
91 * @v9ses: existing v9fs session information
92 *
93 */
94
95static void v9fs_parse_options(char *options, struct v9fs_session_info *v9ses)
96{
97 char *p;
98 substring_t args[MAX_OPT_ARGS];
99 int option;
100 int ret;
101
102 /* setup defaults */
103 v9ses->port = V9FS_PORT;
104 v9ses->maxdata = 9000;
105 v9ses->proto = PROTO_TCP;
106 v9ses->extended = 1;
107 v9ses->afid = ~0;
108 v9ses->debug = 0;
109 v9ses->rfdno = ~0;
110 v9ses->wfdno = ~0;
111
112 if (!options)
113 return;
114
115 while ((p = strsep(&options, ",")) != NULL) {
116 int token;
117 if (!*p)
118 continue;
119 token = match_token(p, tokens, args);
120 if (token < Opt_name) {
121 if ((ret = match_int(&args[0], &option)) < 0) {
122 dprintk(DEBUG_ERROR,
123 "integer field, but no integer?\n");
124 continue;
125 }
126
127 }
128 switch (token) {
129 case Opt_port:
130 v9ses->port = option;
131 break;
132 case Opt_msize:
133 v9ses->maxdata = option;
134 break;
135 case Opt_uid:
136 v9ses->uid = option;
137 break;
138 case Opt_gid:
139 v9ses->gid = option;
140 break;
141 case Opt_afid:
142 v9ses->afid = option;
143 break;
144 case Opt_rfdno:
145 v9ses->rfdno = option;
146 break;
147 case Opt_wfdno:
148 v9ses->wfdno = option;
149 break;
150 case Opt_debug:
151 v9ses->debug = option;
152 break;
153 case Opt_tcp:
154 v9ses->proto = PROTO_TCP;
155 break;
156 case Opt_unix:
157 v9ses->proto = PROTO_UNIX;
158 break;
159 case Opt_fd:
160 v9ses->proto = PROTO_FD;
161 break;
162 case Opt_name:
163 match_strcpy(v9ses->name, &args[0]);
164 break;
165 case Opt_remotename:
166 match_strcpy(v9ses->remotename, &args[0]);
167 break;
168 case Opt_legacy:
169 v9ses->extended = 0;
170 break;
171 case Opt_nodevmap:
172 v9ses->nodev = 1;
173 break;
174 default:
175 continue;
176 }
177 }
178}
179
180/**
181 * v9fs_inode2v9ses - safely extract v9fs session info from super block
182 * @inode: inode to extract information from
183 *
184 * Paranoid function to extract v9ses information from superblock,
185 * if anything is missing it will report an error.
186 *
187 */
188
189struct v9fs_session_info *v9fs_inode2v9ses(struct inode *inode)
190{
191 return (inode->i_sb->s_fs_info);
192}
193
194/**
195 * v9fs_get_idpool - allocate numeric id from pool
196 * @p - pool to allocate from
197 *
198 * XXX - This seems to be an awful generic function, should it be in idr.c with
199 * the lock included in struct idr?
200 */
201
202int v9fs_get_idpool(struct v9fs_idpool *p)
203{
204 int i = 0;
205 int error;
206
207retry:
208 if (idr_pre_get(&p->pool, GFP_KERNEL) == 0)
209 return 0;
210
211 if (down_interruptible(&p->lock) == -EINTR) {
212 eprintk(KERN_WARNING, "Interrupted while locking\n");
213 return -1;
214 }
215
216 error = idr_get_new(&p->pool, NULL, &i);
217 up(&p->lock);
218
219 if (error == -EAGAIN)
220 goto retry;
221 else if (error)
222 return -1;
223
224 return i;
225}
226
227/**
228 * v9fs_put_idpool - release numeric id from pool
229 * @p - pool to allocate from
230 *
231 * XXX - This seems to be an awful generic function, should it be in idr.c with
232 * the lock included in struct idr?
233 */
234
235void v9fs_put_idpool(int id, struct v9fs_idpool *p)
236{
237 if (down_interruptible(&p->lock) == -EINTR) {
238 eprintk(KERN_WARNING, "Interrupted while locking\n");
239 return;
240 }
241 idr_remove(&p->pool, id);
242 up(&p->lock);
243}
244
245/**
246 * v9fs_session_init - initialize session
247 * @v9ses: session information structure
248 * @dev_name: device being mounted
249 * @data: options
250 *
251 */
252
253int
254v9fs_session_init(struct v9fs_session_info *v9ses,
255 const char *dev_name, char *data)
256{
257 struct v9fs_fcall *fcall = NULL;
258 struct v9fs_transport *trans_proto;
259 int n = 0;
260 int newfid = -1;
261 int retval = -EINVAL;
262
263 v9ses->name = __getname();
264 if (!v9ses->name)
265 return -ENOMEM;
266
267 v9ses->remotename = __getname();
268 if (!v9ses->remotename) {
269 putname(v9ses->name);
270 return -ENOMEM;
271 }
272
273 strcpy(v9ses->name, V9FS_DEFUSER);
274 strcpy(v9ses->remotename, V9FS_DEFANAME);
275
276 v9fs_parse_options(data, v9ses);
277
278 /* set global debug level */
279 v9fs_debug_level = v9ses->debug;
280
281 /* id pools that are session-dependent: FIDs and TIDs */
282 idr_init(&v9ses->fidpool.pool);
283 init_MUTEX(&v9ses->fidpool.lock);
284 idr_init(&v9ses->tidpool.pool);
285 init_MUTEX(&v9ses->tidpool.lock);
286
287
288 switch (v9ses->proto) {
289 case PROTO_TCP:
290 trans_proto = &v9fs_trans_tcp;
291 break;
292 case PROTO_UNIX:
293 trans_proto = &v9fs_trans_unix;
294 *v9ses->remotename = 0;
295 break;
296 case PROTO_FD:
297 trans_proto = &v9fs_trans_fd;
298 *v9ses->remotename = 0;
299 break;
300 default:
301 printk(KERN_ERR "v9fs: Bad mount protocol %d\n", v9ses->proto);
302 retval = -ENOPROTOOPT;
303 goto SessCleanUp;
304 };
305
306 v9ses->transport = trans_proto;
307
308 if ((retval = v9ses->transport->init(v9ses, dev_name, data)) < 0) {
309 eprintk(KERN_ERR, "problem initializing transport\n");
310 goto SessCleanUp;
311 }
312
313 v9ses->inprogress = 0;
314 v9ses->shutdown = 0;
315 v9ses->session_hung = 0;
316
317 if ((retval = v9fs_mux_init(v9ses, dev_name)) < 0) {
318 dprintk(DEBUG_ERROR, "problem initializing mux\n");
319 goto SessCleanUp;
320 }
321
322 if (v9ses->afid == ~0) {
323 if (v9ses->extended)
324 retval =
325 v9fs_t_version(v9ses, v9ses->maxdata, "9P2000.u",
326 &fcall);
327 else
328 retval = v9fs_t_version(v9ses, v9ses->maxdata, "9P2000",
329 &fcall);
330
331 if (retval < 0) {
332 dprintk(DEBUG_ERROR, "v9fs_t_version failed\n");
333 goto FreeFcall;
334 }
335
336 /* Really should check for 9P1 and report error */
337 if (!strcmp(fcall->params.rversion.version, "9P2000.u")) {
338 dprintk(DEBUG_9P, "9P2000 UNIX extensions enabled\n");
339 v9ses->extended = 1;
340 } else {
341 dprintk(DEBUG_9P, "9P2000 legacy mode enabled\n");
342 v9ses->extended = 0;
343 }
344
345 n = fcall->params.rversion.msize;
346 kfree(fcall);
347
348 if (n < v9ses->maxdata)
349 v9ses->maxdata = n;
350 }
351
352 newfid = v9fs_get_idpool(&v9ses->fidpool);
353 if (newfid < 0) {
354 eprintk(KERN_WARNING, "couldn't allocate FID\n");
355 retval = -ENOMEM;
356 goto SessCleanUp;
357 }
358 /* it is a little bit ugly, but we have to prevent newfid */
359 /* being the same as afid, so if it is, get a new fid */
360 if (v9ses->afid != ~0 && newfid == v9ses->afid) {
361 newfid = v9fs_get_idpool(&v9ses->fidpool);
362 if (newfid < 0) {
363 eprintk(KERN_WARNING, "couldn't allocate FID\n");
364 retval = -ENOMEM;
365 goto SessCleanUp;
366 }
367 }
368
369 if ((retval =
370 v9fs_t_attach(v9ses, v9ses->name, v9ses->remotename, newfid,
371 v9ses->afid, NULL))
372 < 0) {
373 dprintk(DEBUG_ERROR, "cannot attach\n");
374 goto SessCleanUp;
375 }
376
377 if (v9ses->afid != ~0) {
378 if (v9fs_t_clunk(v9ses, v9ses->afid, NULL))
379 dprintk(DEBUG_ERROR, "clunk failed\n");
380 }
381
382 return newfid;
383
384 FreeFcall:
385 kfree(fcall);
386
387 SessCleanUp:
388 v9fs_session_close(v9ses);
389 return retval;
390}
391
392/**
393 * v9fs_session_close - shutdown a session
394 * @v9ses: session information structure
395 *
396 */
397
398void v9fs_session_close(struct v9fs_session_info *v9ses)
399{
400 if (v9ses->recvproc) {
401 send_sig(SIGKILL, v9ses->recvproc, 1);
402 wait_for_completion(&v9ses->proccmpl);
403 }
404
405 if (v9ses->transport)
406 v9ses->transport->close(v9ses->transport);
407
408 putname(v9ses->name);
409 putname(v9ses->remotename);
410}
411
412/**
413 * v9fs_session_cancel - mark transport as disconnected
414 * and cancel all pending requests.
415 */
416void v9fs_session_cancel(struct v9fs_session_info *v9ses) {
417 v9ses->transport->status = Disconnected;
418 v9fs_mux_cancel_requests(v9ses, -EIO);
419}
420
421extern int v9fs_error_init(void);
422
423/**
424 * v9fs_init - Initialize module
425 *
426 */
427
428static int __init init_v9fs(void)
429{
430 v9fs_error_init();
431
432 printk(KERN_INFO "Installing v9fs 9P2000 file system support\n");
433
434 return register_filesystem(&v9fs_fs_type);
435}
436
437/**
438 * v9fs_init - shutdown module
439 *
440 */
441
442static void __exit exit_v9fs(void)
443{
444 unregister_filesystem(&v9fs_fs_type);
445}
446
447module_init(init_v9fs)
448module_exit(exit_v9fs)
449
450MODULE_AUTHOR("Eric Van Hensbergen <ericvh@gmail.com>");
451MODULE_AUTHOR("Ron Minnich <rminnich@lanl.gov>");
452MODULE_LICENSE("GPL");
diff --git a/fs/9p/v9fs.h b/fs/9p/v9fs.h
new file mode 100644
index 0000000000..45dcef42bd
--- /dev/null
+++ b/fs/9p/v9fs.h
@@ -0,0 +1,103 @@
1/*
2 * V9FS definitions.
3 *
4 * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
5 * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to:
19 * Free Software Foundation
20 * 51 Franklin Street, Fifth Floor
21 * Boston, MA 02111-1301 USA
22 *
23 */
24
25/*
26 * Idpool structure provides lock and id management
27 *
28 */
29
30struct v9fs_idpool {
31 struct semaphore lock;
32 struct idr pool;
33};
34
35/*
36 * Session structure provides information for an opened session
37 *
38 */
39
40struct v9fs_session_info {
41 /* options */
42 unsigned int maxdata;
43 unsigned char extended; /* set to 1 if we are using UNIX extensions */
44 unsigned char nodev; /* set to 1 if no disable device mapping */
45 unsigned short port; /* port to connect to */
46 unsigned short debug; /* debug level */
47 unsigned short proto; /* protocol to use */
48 unsigned int afid; /* authentication fid */
49 unsigned int rfdno; /* read file descriptor number */
50 unsigned int wfdno; /* write file descriptor number */
51
52
53 char *name; /* user name to mount as */
54 char *remotename; /* name of remote hierarchy being mounted */
55 unsigned int uid; /* default uid/muid for legacy support */
56 unsigned int gid; /* default gid for legacy support */
57
58 /* book keeping */
59 struct v9fs_idpool fidpool; /* The FID pool for file descriptors */
60 struct v9fs_idpool tidpool; /* The TID pool for transactions ids */
61
62 /* transport information */
63 struct v9fs_transport *transport;
64
65 int inprogress; /* session in progress => true */
66 int shutdown; /* session shutting down. no more attaches. */
67 unsigned char session_hung;
68
69 /* mux private data */
70 struct v9fs_fcall *curfcall;
71 wait_queue_head_t read_wait;
72 struct completion fcread;
73 struct completion proccmpl;
74 struct task_struct *recvproc;
75
76 spinlock_t muxlock;
77 struct list_head mux_fcalls;
78};
79
80/* possible values of ->proto */
81enum {
82 PROTO_TCP,
83 PROTO_UNIX,
84 PROTO_FD,
85};
86
87int v9fs_session_init(struct v9fs_session_info *, const char *, char *);
88struct v9fs_session_info *v9fs_inode2v9ses(struct inode *);
89void v9fs_session_close(struct v9fs_session_info *v9ses);
90int v9fs_get_idpool(struct v9fs_idpool *p);
91void v9fs_put_idpool(int id, struct v9fs_idpool *p);
92void v9fs_session_cancel(struct v9fs_session_info *v9ses);
93
94#define V9FS_MAGIC 0x01021997
95
96/* other default globals */
97#define V9FS_PORT 564
98#define V9FS_DEFUSER "nobody"
99#define V9FS_DEFANAME ""
100
101/* inital pool sizes for fids and tags */
102#define V9FS_START_FIDS 8192
103#define V9FS_START_TIDS 256
diff --git a/fs/9p/v9fs_vfs.h b/fs/9p/v9fs_vfs.h
new file mode 100644
index 0000000000..2f2cea7ee3
--- /dev/null
+++ b/fs/9p/v9fs_vfs.h
@@ -0,0 +1,53 @@
1/*
2 * V9FS VFS extensions.
3 *
4 * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
5 * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to:
19 * Free Software Foundation
20 * 51 Franklin Street, Fifth Floor
21 * Boston, MA 02111-1301 USA
22 *
23 */
24
25/* plan9 semantics are that created files are implicitly opened.
26 * But linux semantics are that you call create, then open.
27 * the plan9 approach is superior as it provides an atomic
28 * open.
29 * we track the create fid here. When the file is opened, if fidopen is
30 * non-zero, we use the fid and can skip some steps.
31 * there may be a better way to do this, but I don't know it.
32 * one BAD way is to clunk the fid on create, then open it again:
33 * you lose the atomicity of file open
34 */
35
36/* special case:
37 * unlink calls remove, which is an implicit clunk. So we have to track
38 * that kind of thing so that we don't try to clunk a dead fid.
39 */
40
41extern struct file_system_type v9fs_fs_type;
42extern struct file_operations v9fs_file_operations;
43extern struct file_operations v9fs_dir_operations;
44extern struct dentry_operations v9fs_dentry_operations;
45
46struct inode *v9fs_get_inode(struct super_block *sb, int mode);
47ino_t v9fs_qid2ino(struct v9fs_qid *qid);
48void v9fs_mistat2inode(struct v9fs_stat *, struct inode *,
49 struct super_block *);
50int v9fs_dir_release(struct inode *inode, struct file *filp);
51int v9fs_file_open(struct inode *inode, struct file *file);
52void v9fs_inode2mistat(struct inode *inode, struct v9fs_stat *mistat);
53void v9fs_dentry_release(struct dentry *);
diff --git a/fs/9p/vfs_dentry.c b/fs/9p/vfs_dentry.c
new file mode 100644
index 0000000000..306c96741f
--- /dev/null
+++ b/fs/9p/vfs_dentry.c
@@ -0,0 +1,126 @@
1/*
2 * linux/fs/9p/vfs_dentry.c
3 *
4 * This file contians vfs dentry ops for the 9P2000 protocol.
5 *
6 * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
7 * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to:
21 * Free Software Foundation
22 * 51 Franklin Street, Fifth Floor
23 * Boston, MA 02111-1301 USA
24 *
25 */
26
27#include <linux/module.h>
28#include <linux/errno.h>
29#include <linux/fs.h>
30#include <linux/file.h>
31#include <linux/pagemap.h>
32#include <linux/stat.h>
33#include <linux/string.h>
34#include <linux/smp_lock.h>
35#include <linux/inet.h>
36#include <linux/namei.h>
37#include <linux/idr.h>
38
39#include "debug.h"
40#include "v9fs.h"
41#include "9p.h"
42#include "v9fs_vfs.h"
43#include "conv.h"
44#include "fid.h"
45
46/**
47 * v9fs_dentry_validate - VFS dcache hook to validate cache
48 * @dentry: dentry that is being validated
49 * @nd: path data
50 *
51 * dcache really shouldn't be used for 9P2000 as at all due to
52 * potential attached semantics to directory traversal (walk).
53 *
54 * FUTURE: look into how to use dcache to allow multi-stage
55 * walks in Plan 9 & potential for better dcache operation which
56 * would remain valid for Plan 9 semantics. Older versions
57 * had validation via stat for those interested. However, since
58 * stat has the same approximate overhead as walk there really
59 * is no difference. The only improvement would be from a
60 * time-decay cache like NFS has and that undermines the
61 * synchronous nature of 9P2000.
62 *
63 */
64
65static int v9fs_dentry_validate(struct dentry *dentry, struct nameidata *nd)
66{
67 struct dentry *dc = current->fs->pwd;
68
69 dprintk(DEBUG_VFS, "dentry: %s (%p)\n", dentry->d_iname, dentry);
70 if (v9fs_fid_lookup(dentry, FID_OP)) {
71 dprintk(DEBUG_VFS, "VALID\n");
72 return 1;
73 }
74
75 while (dc != NULL) {
76 if (dc == dentry) {
77 dprintk(DEBUG_VFS, "VALID\n");
78 return 1;
79 }
80 if (dc == dc->d_parent)
81 break;
82
83 dc = dc->d_parent;
84 }
85
86 dprintk(DEBUG_VFS, "INVALID\n");
87 return 0;
88}
89
90/**
91 * v9fs_dentry_release - called when dentry is going to be freed
92 * @dentry: dentry that is being release
93 *
94 */
95
96void v9fs_dentry_release(struct dentry *dentry)
97{
98 dprintk(DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry);
99
100 if (dentry->d_fsdata != NULL) {
101 struct list_head *fid_list = dentry->d_fsdata;
102 struct v9fs_fid *temp = NULL;
103 struct v9fs_fid *current_fid = NULL;
104 struct v9fs_fcall *fcall = NULL;
105
106 list_for_each_entry_safe(current_fid, temp, fid_list, list) {
107 if (v9fs_t_clunk
108 (current_fid->v9ses, current_fid->fid, &fcall))
109 dprintk(DEBUG_ERROR, "clunk failed: %s\n",
110 FCALL_ERROR(fcall));
111
112 v9fs_put_idpool(current_fid->fid,
113 &current_fid->v9ses->fidpool);
114
115 kfree(fcall);
116 v9fs_fid_destroy(current_fid);
117 }
118
119 kfree(dentry->d_fsdata); /* free the list_head */
120 }
121}
122
123struct dentry_operations v9fs_dentry_operations = {
124 .d_revalidate = v9fs_dentry_validate,
125 .d_release = v9fs_dentry_release,
126};
diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c
new file mode 100644
index 0000000000..c478a73841
--- /dev/null
+++ b/fs/9p/vfs_dir.c
@@ -0,0 +1,226 @@
1/*
2 * linux/fs/9p/vfs_dir.c
3 *
4 * This file contains vfs directory ops for the 9P2000 protocol.
5 *
6 * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
7 * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to:
21 * Free Software Foundation
22 * 51 Franklin Street, Fifth Floor
23 * Boston, MA 02111-1301 USA
24 *
25 */
26
27#include <linux/module.h>
28#include <linux/errno.h>
29#include <linux/fs.h>
30#include <linux/file.h>
31#include <linux/stat.h>
32#include <linux/string.h>
33#include <linux/smp_lock.h>
34#include <linux/inet.h>
35#include <linux/idr.h>
36
37#include "debug.h"
38#include "v9fs.h"
39#include "9p.h"
40#include "v9fs_vfs.h"
41#include "conv.h"
42#include "fid.h"
43
44/**
45 * dt_type - return file type
46 * @mistat: mistat structure
47 *
48 */
49
50static inline int dt_type(struct v9fs_stat *mistat)
51{
52 unsigned long perm = mistat->mode;
53 int rettype = DT_REG;
54
55 if (perm & V9FS_DMDIR)
56 rettype = DT_DIR;
57 if (perm & V9FS_DMSYMLINK)
58 rettype = DT_LNK;
59
60 return rettype;
61}
62
63/**
64 * v9fs_dir_readdir - read a directory
65 * @filep: opened file structure
66 * @dirent: directory structure ???
67 * @filldir: function to populate directory structure ???
68 *
69 */
70
71static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
72{
73 struct v9fs_fcall *fcall = NULL;
74 struct inode *inode = filp->f_dentry->d_inode;
75 struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode);
76 struct v9fs_fid *file = filp->private_data;
77 unsigned int i, n;
78 int fid = -1;
79 int ret = 0;
80 struct v9fs_stat *mi = NULL;
81 int over = 0;
82
83 dprintk(DEBUG_VFS, "name %s\n", filp->f_dentry->d_name.name);
84
85 fid = file->fid;
86
87 mi = kmalloc(v9ses->maxdata, GFP_KERNEL);
88 if (!mi)
89 return -ENOMEM;
90
91 if (file->rdir_fcall && (filp->f_pos != file->rdir_pos)) {
92 kfree(file->rdir_fcall);
93 file->rdir_fcall = NULL;
94 }
95
96 if (file->rdir_fcall) {
97 n = file->rdir_fcall->params.rread.count;
98 i = file->rdir_fpos;
99 while (i < n) {
100 int s = v9fs_deserialize_stat(v9ses,
101 file->rdir_fcall->params.rread.data + i,
102 n - i, mi, v9ses->maxdata);
103
104 if (s == 0) {
105 dprintk(DEBUG_ERROR,
106 "error while deserializing mistat\n");
107 ret = -EIO;
108 goto FreeStructs;
109 }
110
111 over = filldir(dirent, mi->name, strlen(mi->name),
112 filp->f_pos, v9fs_qid2ino(&mi->qid),
113 dt_type(mi));
114
115 if (over) {
116 file->rdir_fpos = i;
117 file->rdir_pos = filp->f_pos;
118 break;
119 }
120
121 i += s;
122 filp->f_pos += s;
123 }
124
125 if (!over) {
126 kfree(file->rdir_fcall);
127 file->rdir_fcall = NULL;
128 }
129 }
130
131 while (!over) {
132 ret = v9fs_t_read(v9ses, fid, filp->f_pos,
133 v9ses->maxdata-V9FS_IOHDRSZ, &fcall);
134 if (ret < 0) {
135 dprintk(DEBUG_ERROR, "error while reading: %d: %p\n",
136 ret, fcall);
137 goto FreeStructs;
138 } else if (ret == 0)
139 break;
140
141 n = ret;
142 i = 0;
143 while (i < n) {
144 int s = v9fs_deserialize_stat(v9ses,
145 fcall->params.rread.data + i, n - i, mi,
146 v9ses->maxdata);
147
148 if (s == 0) {
149 dprintk(DEBUG_ERROR,
150 "error while deserializing mistat\n");
151 return -EIO;
152 }
153
154 over = filldir(dirent, mi->name, strlen(mi->name),
155 filp->f_pos, v9fs_qid2ino(&mi->qid),
156 dt_type(mi));
157
158 if (over) {
159 file->rdir_fcall = fcall;
160 file->rdir_fpos = i;
161 file->rdir_pos = filp->f_pos;
162 fcall = NULL;
163 break;
164 }
165
166 i += s;
167 filp->f_pos += s;
168 }
169
170 kfree(fcall);
171 }
172
173 FreeStructs:
174 kfree(fcall);
175 kfree(mi);
176 return ret;
177}
178
179/**
180 * v9fs_dir_release - close a directory
181 * @inode: inode of the directory
182 * @filp: file pointer to a directory
183 *
184 */
185
186int v9fs_dir_release(struct inode *inode, struct file *filp)
187{
188 struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode);
189 struct v9fs_fid *fid = filp->private_data;
190 int fidnum = -1;
191
192 dprintk(DEBUG_VFS, "inode: %p filp: %p fid: %d\n", inode, filp,
193 fid->fid);
194 fidnum = fid->fid;
195
196 filemap_fdatawrite(inode->i_mapping);
197 filemap_fdatawait(inode->i_mapping);
198
199 if (fidnum >= 0) {
200 fid->fidopen--;
201 dprintk(DEBUG_VFS, "fidopen: %d v9f->fid: %d\n", fid->fidopen,
202 fid->fid);
203
204 if (fid->fidopen == 0) {
205 if (v9fs_t_clunk(v9ses, fidnum, NULL))
206 dprintk(DEBUG_ERROR, "clunk failed\n");
207
208 v9fs_put_idpool(fid->fid, &v9ses->fidpool);
209 }
210
211 kfree(fid->rdir_fcall);
212
213 filp->private_data = NULL;
214 v9fs_fid_destroy(fid);
215 }
216
217 d_drop(filp->f_dentry);
218 return 0;
219}
220
221struct file_operations v9fs_dir_operations = {
222 .read = generic_read_dir,
223 .readdir = v9fs_dir_readdir,
224 .open = v9fs_file_open,
225 .release = v9fs_dir_release,
226};
diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c
new file mode 100644
index 0000000000..1f8ae7d580
--- /dev/null
+++ b/fs/9p/vfs_file.c
@@ -0,0 +1,401 @@
1/*
2 * linux/fs/9p/vfs_file.c
3 *
4 * This file contians vfs file ops for 9P2000.
5 *
6 * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
7 * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to:
21 * Free Software Foundation
22 * 51 Franklin Street, Fifth Floor
23 * Boston, MA 02111-1301 USA
24 *
25 */
26
27#include <linux/module.h>
28#include <linux/errno.h>
29#include <linux/fs.h>
30#include <linux/file.h>
31#include <linux/stat.h>
32#include <linux/string.h>
33#include <linux/smp_lock.h>
34#include <linux/inet.h>
35#include <linux/version.h>
36#include <linux/list.h>
37#include <asm/uaccess.h>
38#include <linux/idr.h>
39
40#include "debug.h"
41#include "v9fs.h"
42#include "9p.h"
43#include "v9fs_vfs.h"
44#include "fid.h"
45
46/**
47 * v9fs_file_open - open a file (or directory)
48 * @inode: inode to be opened
49 * @file: file being opened
50 *
51 */
52
53int v9fs_file_open(struct inode *inode, struct file *file)
54{
55 struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode);
56 struct v9fs_fid *v9fid = v9fs_fid_lookup(file->f_dentry, FID_WALK);
57 struct v9fs_fid *v9newfid = NULL;
58 struct v9fs_fcall *fcall = NULL;
59 int open_mode = 0;
60 unsigned int iounit = 0;
61 int newfid = -1;
62 long result = -1;
63
64 dprintk(DEBUG_VFS, "inode: %p file: %p v9fid= %p\n", inode, file,
65 v9fid);
66
67 if (!v9fid) {
68 struct dentry *dentry = file->f_dentry;
69 dprintk(DEBUG_ERROR, "Couldn't resolve fid from dentry\n");
70
71 /* XXX - some duplication from lookup, generalize later */
72 /* basically vfs_lookup is too heavy weight */
73 v9fid = v9fs_fid_lookup(file->f_dentry, FID_OP);
74 if (!v9fid)
75 return -EBADF;
76
77 v9fid = v9fs_fid_lookup(dentry->d_parent, FID_WALK);
78 if (!v9fid)
79 return -EBADF;
80
81 newfid = v9fs_get_idpool(&v9ses->fidpool);
82 if (newfid < 0) {
83 eprintk(KERN_WARNING, "newfid fails!\n");
84 return -ENOSPC;
85 }
86
87 result =
88 v9fs_t_walk(v9ses, v9fid->fid, newfid,
89 (char *)file->f_dentry->d_name.name, NULL);
90 if (result < 0) {
91 v9fs_put_idpool(newfid, &v9ses->fidpool);
92 dprintk(DEBUG_ERROR, "rewalk didn't work\n");
93 return -EBADF;
94 }
95
96 v9fid = v9fs_fid_create(dentry);
97 if (v9fid == NULL) {
98 dprintk(DEBUG_ERROR, "couldn't insert\n");
99 return -ENOMEM;
100 }
101 v9fid->fid = newfid;
102 }
103
104 if (v9fid->fidcreate) {
105 /* create case */
106 newfid = v9fid->fid;
107 iounit = v9fid->iounit;
108 v9fid->fidcreate = 0;
109 } else {
110 if (!S_ISDIR(inode->i_mode))
111 newfid = v9fid->fid;
112 else {
113 newfid = v9fs_get_idpool(&v9ses->fidpool);
114 if (newfid < 0) {
115 eprintk(KERN_WARNING, "allocation failed\n");
116 return -ENOSPC;
117 }
118 /* This would be a somewhat critical clone */
119 result =
120 v9fs_t_walk(v9ses, v9fid->fid, newfid, NULL,
121 &fcall);
122 if (result < 0) {
123 dprintk(DEBUG_ERROR, "clone error: %s\n",
124 FCALL_ERROR(fcall));
125 kfree(fcall);
126 return result;
127 }
128
129 v9newfid = v9fs_fid_create(file->f_dentry);
130 v9newfid->fid = newfid;
131 v9newfid->qid = v9fid->qid;
132 v9newfid->iounit = v9fid->iounit;
133 v9newfid->fidopen = 0;
134 v9newfid->fidclunked = 0;
135 v9newfid->v9ses = v9ses;
136 v9fid = v9newfid;
137 kfree(fcall);
138 }
139
140 /* TODO: do special things for O_EXCL, O_NOFOLLOW, O_SYNC */
141 /* translate open mode appropriately */
142 open_mode = file->f_flags & 0x3;
143
144 if (file->f_flags & O_EXCL)
145 open_mode |= V9FS_OEXCL;
146
147 if (v9ses->extended) {
148 if (file->f_flags & O_TRUNC)
149 open_mode |= V9FS_OTRUNC;
150
151 if (file->f_flags & O_APPEND)
152 open_mode |= V9FS_OAPPEND;
153 }
154
155 result = v9fs_t_open(v9ses, newfid, open_mode, &fcall);
156 if (result < 0) {
157 dprintk(DEBUG_ERROR,
158 "open failed, open_mode 0x%x: %s\n", open_mode,
159 FCALL_ERROR(fcall));
160 kfree(fcall);
161 return result;
162 }
163
164 iounit = fcall->params.ropen.iounit;
165 kfree(fcall);
166 }
167
168
169 file->private_data = v9fid;
170
171 v9fid->rdir_pos = 0;
172 v9fid->rdir_fcall = NULL;
173 v9fid->fidopen = 1;
174 v9fid->filp = file;
175 v9fid->iounit = iounit;
176
177 return 0;
178}
179
180/**
181 * v9fs_file_lock - lock a file (or directory)
182 * @inode: inode to be opened
183 * @file: file being opened
184 *
185 * XXX - this looks like a local only lock, we should extend into 9P
186 * by using open exclusive
187 */
188
189static int v9fs_file_lock(struct file *filp, int cmd, struct file_lock *fl)
190{
191 int res = 0;
192 struct inode *inode = filp->f_dentry->d_inode;
193
194 dprintk(DEBUG_VFS, "filp: %p lock: %p\n", filp, fl);
195
196 /* No mandatory locks */
197 if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
198 return -ENOLCK;
199
200 if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) {
201 filemap_fdatawrite(inode->i_mapping);
202 filemap_fdatawait(inode->i_mapping);
203 invalidate_inode_pages(&inode->i_data);
204 }
205
206 return res;
207}
208
209/**
210 * v9fs_read - read from a file (internal)
211 * @filep: file pointer to read
212 * @data: data buffer to read data into
213 * @count: size of buffer
214 * @offset: offset at which to read data
215 *
216 */
217
218static ssize_t
219v9fs_read(struct file *filp, char *buffer, size_t count, loff_t * offset)
220{
221 struct inode *inode = filp->f_dentry->d_inode;
222 struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode);
223 struct v9fs_fid *v9f = filp->private_data;
224 struct v9fs_fcall *fcall = NULL;
225 int fid = v9f->fid;
226 int rsize = 0;
227 int result = 0;
228 int total = 0;
229
230 dprintk(DEBUG_VFS, "\n");
231
232 rsize = v9ses->maxdata - V9FS_IOHDRSZ;
233 if (v9f->iounit != 0 && rsize > v9f->iounit)
234 rsize = v9f->iounit;
235
236 do {
237 if (count < rsize)
238 rsize = count;
239
240 result = v9fs_t_read(v9ses, fid, *offset, rsize, &fcall);
241
242 if (result < 0) {
243 printk(KERN_ERR "9P2000: v9fs_t_read returned %d\n",
244 result);
245
246 kfree(fcall);
247 return total;
248 } else
249 *offset += result;
250
251 /* XXX - extra copy */
252 memcpy(buffer, fcall->params.rread.data, result);
253 count -= result;
254 buffer += result;
255 total += result;
256
257 kfree(fcall);
258
259 if (result < rsize)
260 break;
261 } while (count);
262
263 return total;
264}
265
266/**
267 * v9fs_file_read - read from a file
268 * @filep: file pointer to read
269 * @data: data buffer to read data into
270 * @count: size of buffer
271 * @offset: offset at which to read data
272 *
273 */
274
275static ssize_t
276v9fs_file_read(struct file *filp, char __user * data, size_t count,
277 loff_t * offset)
278{
279 int retval = -1;
280 int ret = 0;
281 char *buffer;
282
283 buffer = kmalloc(count, GFP_KERNEL);
284 if (!buffer)
285 return -ENOMEM;
286
287 retval = v9fs_read(filp, buffer, count, offset);
288 if (retval > 0) {
289 if ((ret = copy_to_user(data, buffer, retval)) != 0) {
290 dprintk(DEBUG_ERROR, "Problem copying to user %d\n",
291 ret);
292 retval = ret;
293 }
294 }
295
296 kfree(buffer);
297
298 return retval;
299}
300
301/**
302 * v9fs_write - write to a file
303 * @filep: file pointer to write
304 * @data: data buffer to write data from
305 * @count: size of buffer
306 * @offset: offset at which to write data
307 *
308 */
309
310static ssize_t
311v9fs_write(struct file *filp, char *buffer, size_t count, loff_t * offset)
312{
313 struct inode *inode = filp->f_dentry->d_inode;
314 struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode);
315 struct v9fs_fid *v9fid = filp->private_data;
316 struct v9fs_fcall *fcall;
317 int fid = v9fid->fid;
318 int result = -EIO;
319 int rsize = 0;
320 int total = 0;
321
322 dprintk(DEBUG_VFS, "data %p count %d offset %x\n", buffer, (int)count,
323 (int)*offset);
324 rsize = v9ses->maxdata - V9FS_IOHDRSZ;
325 if (v9fid->iounit != 0 && rsize > v9fid->iounit)
326 rsize = v9fid->iounit;
327
328 dump_data(buffer, count);
329
330 do {
331 if (count < rsize)
332 rsize = count;
333
334 result =
335 v9fs_t_write(v9ses, fid, *offset, rsize, buffer, &fcall);
336 if (result < 0) {
337 eprintk(KERN_ERR, "error while writing: %s(%d)\n",
338 FCALL_ERROR(fcall), result);
339 kfree(fcall);
340 return result;
341 } else
342 *offset += result;
343
344 kfree(fcall);
345
346 if (result != rsize) {
347 eprintk(KERN_ERR,
348 "short write: v9fs_t_write returned %d\n",
349 result);
350 break;
351 }
352
353 count -= result;
354 buffer += result;
355 total += result;
356 } while (count);
357
358 return total;
359}
360
361/**
362 * v9fs_file_write - write to a file
363 * @filep: file pointer to write
364 * @data: data buffer to write data from
365 * @count: size of buffer
366 * @offset: offset at which to write data
367 *
368 */
369
370static ssize_t
371v9fs_file_write(struct file *filp, const char __user * data,
372 size_t count, loff_t * offset)
373{
374 int ret = -1;
375 char *buffer;
376
377 buffer = kmalloc(count, GFP_KERNEL);
378 if (buffer == NULL)
379 return -ENOMEM;
380
381 ret = copy_from_user(buffer, data, count);
382 if (ret) {
383 dprintk(DEBUG_ERROR, "Problem copying from user\n");
384 ret = -EFAULT;
385 } else {
386 ret = v9fs_write(filp, buffer, count, offset);
387 }
388
389 kfree(buffer);
390
391 return ret;
392}
393
394struct file_operations v9fs_file_operations = {
395 .llseek = generic_file_llseek,
396 .read = v9fs_file_read,
397 .write = v9fs_file_write,
398 .open = v9fs_file_open,
399 .release = v9fs_dir_release,
400 .lock = v9fs_file_lock,
401};
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
new file mode 100644
index 0000000000..0c13fc6000
--- /dev/null
+++ b/fs/9p/vfs_inode.c
@@ -0,0 +1,1338 @@
1/*
2 * linux/fs/9p/vfs_inode.c
3 *
4 * This file contains vfs inode ops for the 9P2000 protocol.
5 *
6 * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
7 * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to:
21 * Free Software Foundation
22 * 51 Franklin Street, Fifth Floor
23 * Boston, MA 02111-1301 USA
24 *
25 */
26
27#include <linux/module.h>
28#include <linux/errno.h>
29#include <linux/fs.h>
30#include <linux/file.h>
31#include <linux/pagemap.h>
32#include <linux/stat.h>
33#include <linux/string.h>
34#include <linux/smp_lock.h>
35#include <linux/inet.h>
36#include <linux/namei.h>
37#include <linux/idr.h>
38
39#include "debug.h"
40#include "v9fs.h"
41#include "9p.h"
42#include "v9fs_vfs.h"
43#include "conv.h"
44#include "fid.h"
45
46static struct inode_operations v9fs_dir_inode_operations;
47static struct inode_operations v9fs_dir_inode_operations_ext;
48static struct inode_operations v9fs_file_inode_operations;
49static struct inode_operations v9fs_symlink_inode_operations;
50
51/**
52 * unixmode2p9mode - convert unix mode bits to plan 9
53 * @v9ses: v9fs session information
54 * @mode: mode to convert
55 *
56 */
57
58static int unixmode2p9mode(struct v9fs_session_info *v9ses, int mode)
59{
60 int res;
61 res = mode & 0777;
62 if (S_ISDIR(mode))
63 res |= V9FS_DMDIR;
64 if (v9ses->extended) {
65 if (S_ISLNK(mode))
66 res |= V9FS_DMSYMLINK;
67 if (v9ses->nodev == 0) {
68 if (S_ISSOCK(mode))
69 res |= V9FS_DMSOCKET;
70 if (S_ISFIFO(mode))
71 res |= V9FS_DMNAMEDPIPE;
72 if (S_ISBLK(mode))
73 res |= V9FS_DMDEVICE;
74 if (S_ISCHR(mode))
75 res |= V9FS_DMDEVICE;
76 }
77
78 if ((mode & S_ISUID) == S_ISUID)
79 res |= V9FS_DMSETUID;
80 if ((mode & S_ISGID) == S_ISGID)
81 res |= V9FS_DMSETGID;
82 if ((mode & V9FS_DMLINK))
83 res |= V9FS_DMLINK;
84 }
85
86 return res;
87}
88
89/**
90 * p9mode2unixmode- convert plan9 mode bits to unix mode bits
91 * @v9ses: v9fs session information
92 * @mode: mode to convert
93 *
94 */
95
96static int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode)
97{
98 int res;
99
100 res = mode & 0777;
101
102 if ((mode & V9FS_DMDIR) == V9FS_DMDIR)
103 res |= S_IFDIR;
104 else if ((mode & V9FS_DMSYMLINK) && (v9ses->extended))
105 res |= S_IFLNK;
106 else if ((mode & V9FS_DMSOCKET) && (v9ses->extended)
107 && (v9ses->nodev == 0))
108 res |= S_IFSOCK;
109 else if ((mode & V9FS_DMNAMEDPIPE) && (v9ses->extended)
110 && (v9ses->nodev == 0))
111 res |= S_IFIFO;
112 else if ((mode & V9FS_DMDEVICE) && (v9ses->extended)
113 && (v9ses->nodev == 0))
114 res |= S_IFBLK;
115 else
116 res |= S_IFREG;
117
118 if (v9ses->extended) {
119 if ((mode & V9FS_DMSETUID) == V9FS_DMSETUID)
120 res |= S_ISUID;
121
122 if ((mode & V9FS_DMSETGID) == V9FS_DMSETGID)
123 res |= S_ISGID;
124 }
125
126 return res;
127}
128
129/**
130 * v9fs_blank_mistat - helper function to setup a 9P stat structure
131 * @v9ses: 9P session info (for determining extended mode)
132 * @mistat: structure to initialize
133 *
134 */
135
136static void
137v9fs_blank_mistat(struct v9fs_session_info *v9ses, struct v9fs_stat *mistat)
138{
139 mistat->type = ~0;
140 mistat->dev = ~0;
141 mistat->qid.type = ~0;
142 mistat->qid.version = ~0;
143 *((long long *)&mistat->qid.path) = ~0;
144 mistat->mode = ~0;
145 mistat->atime = ~0;
146 mistat->mtime = ~0;
147 mistat->length = ~0;
148 mistat->name = mistat->data;
149 mistat->uid = mistat->data;
150 mistat->gid = mistat->data;
151 mistat->muid = mistat->data;
152 if (v9ses->extended) {
153 mistat->n_uid = ~0;
154 mistat->n_gid = ~0;
155 mistat->n_muid = ~0;
156 mistat->extension = mistat->data;
157 }
158 *mistat->data = 0;
159}
160
161/**
162 * v9fs_mistat2unix - convert mistat to unix stat
163 * @mistat: Plan 9 metadata (mistat) structure
164 * @buf: unix metadata (stat) structure to populate
165 * @sb: superblock
166 *
167 */
168
169static void
170v9fs_mistat2unix(struct v9fs_stat *mistat, struct stat *buf,
171 struct super_block *sb)
172{
173 struct v9fs_session_info *v9ses = sb ? sb->s_fs_info : NULL;
174
175 buf->st_nlink = 1;
176
177 buf->st_atime = mistat->atime;
178 buf->st_mtime = mistat->mtime;
179 buf->st_ctime = mistat->mtime;
180
181 buf->st_uid = (unsigned short)-1;
182 buf->st_gid = (unsigned short)-1;
183
184 if (v9ses && v9ses->extended) {
185 /* TODO: string to uid mapping via user-space daemon */
186 if (mistat->n_uid != -1)
187 sscanf(mistat->uid, "%x", (unsigned int *)&buf->st_uid);
188
189 if (mistat->n_gid != -1)
190 sscanf(mistat->gid, "%x", (unsigned int *)&buf->st_gid);
191 }
192
193 if (buf->st_uid == (unsigned short)-1)
194 buf->st_uid = v9ses->uid;
195 if (buf->st_gid == (unsigned short)-1)
196 buf->st_gid = v9ses->gid;
197
198 buf->st_mode = p9mode2unixmode(v9ses, mistat->mode);
199 if ((S_ISBLK(buf->st_mode)) || (S_ISCHR(buf->st_mode))) {
200 char type = 0;
201 int major = -1;
202 int minor = -1;
203 sscanf(mistat->extension, "%c %u %u", &type, &major, &minor);
204 switch (type) {
205 case 'c':
206 buf->st_mode &= ~S_IFBLK;
207 buf->st_mode |= S_IFCHR;
208 break;
209 case 'b':
210 break;
211 default:
212 dprintk(DEBUG_ERROR, "Unknown special type %c (%s)\n",
213 type, mistat->extension);
214 };
215 buf->st_rdev = MKDEV(major, minor);
216 } else
217 buf->st_rdev = 0;
218
219 buf->st_size = mistat->length;
220
221 buf->st_blksize = sb->s_blocksize;
222 buf->st_blocks =
223 (buf->st_size + buf->st_blksize - 1) >> sb->s_blocksize_bits;
224}
225
226/**
227 * v9fs_get_inode - helper function to setup an inode
228 * @sb: superblock
229 * @mode: mode to setup inode with
230 *
231 */
232
233struct inode *v9fs_get_inode(struct super_block *sb, int mode)
234{
235 struct inode *inode = NULL;
236 struct v9fs_session_info *v9ses = sb->s_fs_info;
237
238 dprintk(DEBUG_VFS, "super block: %p mode: %o\n", sb, mode);
239
240 inode = new_inode(sb);
241 if (inode) {
242 inode->i_mode = mode;
243 inode->i_uid = current->fsuid;
244 inode->i_gid = current->fsgid;
245 inode->i_blksize = sb->s_blocksize;
246 inode->i_blocks = 0;
247 inode->i_rdev = 0;
248 inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
249
250 switch (mode & S_IFMT) {
251 case S_IFIFO:
252 case S_IFBLK:
253 case S_IFCHR:
254 case S_IFSOCK:
255 if(!v9ses->extended) {
256 dprintk(DEBUG_ERROR, "special files without extended mode\n");
257 return ERR_PTR(-EINVAL);
258 }
259 init_special_inode(inode, inode->i_mode,
260 inode->i_rdev);
261 break;
262 case S_IFREG:
263 inode->i_op = &v9fs_file_inode_operations;
264 inode->i_fop = &v9fs_file_operations;
265 break;
266 case S_IFLNK:
267 if(!v9ses->extended) {
268 dprintk(DEBUG_ERROR, "extended modes used w/o 9P2000.u\n");
269 return ERR_PTR(-EINVAL);
270 }
271 inode->i_op = &v9fs_symlink_inode_operations;
272 break;
273 case S_IFDIR:
274 inode->i_nlink++;
275 if(v9ses->extended)
276 inode->i_op = &v9fs_dir_inode_operations_ext;
277 else
278 inode->i_op = &v9fs_dir_inode_operations;
279 inode->i_fop = &v9fs_dir_operations;
280 break;
281 default:
282 dprintk(DEBUG_ERROR, "BAD mode 0x%x S_IFMT 0x%x\n",
283 mode, mode & S_IFMT);
284 return ERR_PTR(-EINVAL);
285 }
286 } else {
287 eprintk(KERN_WARNING, "Problem allocating inode\n");
288 return ERR_PTR(-ENOMEM);
289 }
290 return inode;
291}
292
293/**
294 * v9fs_create - helper function to create files and directories
295 * @dir: directory inode file is being created in
296 * @file_dentry: dentry file is being created in
297 * @perm: permissions file is being created with
298 * @open_mode: resulting open mode for file
299 *
300 */
301
302static int
303v9fs_create(struct inode *dir,
304 struct dentry *file_dentry,
305 unsigned int perm, unsigned int open_mode)
306{
307 struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir);
308 struct super_block *sb = dir->i_sb;
309 struct v9fs_fid *dirfid =
310 v9fs_fid_lookup(file_dentry->d_parent, FID_WALK);
311 struct v9fs_fid *fid = NULL;
312 struct inode *file_inode = NULL;
313 struct v9fs_fcall *fcall = NULL;
314 struct v9fs_qid qid;
315 struct stat newstat;
316 int dirfidnum = -1;
317 long newfid = -1;
318 int result = 0;
319 unsigned int iounit = 0;
320
321 perm = unixmode2p9mode(v9ses, perm);
322
323 dprintk(DEBUG_VFS, "dir: %p dentry: %p perm: %o mode: %o\n", dir,
324 file_dentry, perm, open_mode);
325
326 if (!dirfid)
327 return -EBADF;
328
329 dirfidnum = dirfid->fid;
330 if (dirfidnum < 0) {
331 dprintk(DEBUG_ERROR, "No fid for the directory #%lu\n",
332 dir->i_ino);
333 return -EBADF;
334 }
335
336 if (file_dentry->d_inode) {
337 dprintk(DEBUG_ERROR,
338 "Odd. There is an inode for dir %lu, name :%s:\n",
339 dir->i_ino, file_dentry->d_name.name);
340 return -EEXIST;
341 }
342
343 newfid = v9fs_get_idpool(&v9ses->fidpool);
344 if (newfid < 0) {
345 eprintk(KERN_WARNING, "no free fids available\n");
346 return -ENOSPC;
347 }
348
349 result = v9fs_t_walk(v9ses, dirfidnum, newfid, NULL, &fcall);
350 if (result < 0) {
351 dprintk(DEBUG_ERROR, "clone error: %s\n", FCALL_ERROR(fcall));
352 v9fs_put_idpool(newfid, &v9ses->fidpool);
353 newfid = 0;
354 goto CleanUpFid;
355 }
356
357 kfree(fcall);
358
359 result = v9fs_t_create(v9ses, newfid, (char *)file_dentry->d_name.name,
360 perm, open_mode, &fcall);
361 if (result < 0) {
362 dprintk(DEBUG_ERROR, "create fails: %s(%d)\n",
363 FCALL_ERROR(fcall), result);
364
365 goto CleanUpFid;
366 }
367
368 iounit = fcall->params.rcreate.iounit;
369 qid = fcall->params.rcreate.qid;
370 kfree(fcall);
371
372 fid = v9fs_fid_create(file_dentry);
373 if (!fid) {
374 result = -ENOMEM;
375 goto CleanUpFid;
376 }
377
378 fid->fid = newfid;
379 fid->fidopen = 0;
380 fid->fidcreate = 1;
381 fid->qid = qid;
382 fid->iounit = iounit;
383 fid->rdir_pos = 0;
384 fid->rdir_fcall = NULL;
385 fid->v9ses = v9ses;
386
387 if ((perm & V9FS_DMSYMLINK) || (perm & V9FS_DMLINK) ||
388 (perm & V9FS_DMNAMEDPIPE) || (perm & V9FS_DMSOCKET) ||
389 (perm & V9FS_DMDEVICE))
390 return 0;
391
392 result = v9fs_t_stat(v9ses, newfid, &fcall);
393 if (result < 0) {
394 dprintk(DEBUG_ERROR, "stat error: %s(%d)\n", FCALL_ERROR(fcall),
395 result);
396 goto CleanUpFid;
397 }
398
399 v9fs_mistat2unix(fcall->params.rstat.stat, &newstat, sb);
400
401 file_inode = v9fs_get_inode(sb, newstat.st_mode);
402 if ((!file_inode) || IS_ERR(file_inode)) {
403 dprintk(DEBUG_ERROR, "create inode failed\n");
404 result = -EBADF;
405 goto CleanUpFid;
406 }
407
408 v9fs_mistat2inode(fcall->params.rstat.stat, file_inode, sb);
409 kfree(fcall);
410 d_instantiate(file_dentry, file_inode);
411
412 if (perm & V9FS_DMDIR) {
413 if (v9fs_t_clunk(v9ses, newfid, &fcall))
414 dprintk(DEBUG_ERROR, "clunk for mkdir failed: %s\n",
415 FCALL_ERROR(fcall));
416
417 v9fs_put_idpool(newfid, &v9ses->fidpool);
418 kfree(fcall);
419 fid->fidopen = 0;
420 fid->fidcreate = 0;
421 d_drop(file_dentry);
422 }
423
424 return 0;
425
426 CleanUpFid:
427 kfree(fcall);
428
429 if (newfid) {
430 if (v9fs_t_clunk(v9ses, newfid, &fcall))
431 dprintk(DEBUG_ERROR, "clunk failed: %s\n",
432 FCALL_ERROR(fcall));
433
434 v9fs_put_idpool(newfid, &v9ses->fidpool);
435 kfree(fcall);
436 }
437 return result;
438}
439
440/**
441 * v9fs_remove - helper function to remove files and directories
442 * @dir: directory inode that is being deleted
443 * @file: dentry that is being deleted
444 * @rmdir: removing a directory
445 *
446 */
447
448static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir)
449{
450 struct v9fs_fcall *fcall = NULL;
451 struct super_block *sb = NULL;
452 struct v9fs_session_info *v9ses = NULL;
453 struct v9fs_fid *v9fid = NULL;
454 struct inode *file_inode = NULL;
455 int fid = -1;
456 int result = 0;
457
458 dprintk(DEBUG_VFS, "inode: %p dentry: %p rmdir: %d\n", dir, file,
459 rmdir);
460
461 file_inode = file->d_inode;
462 sb = file_inode->i_sb;
463 v9ses = v9fs_inode2v9ses(file_inode);
464 v9fid = v9fs_fid_lookup(file, FID_OP);
465
466 if (!v9fid) {
467 dprintk(DEBUG_ERROR,
468 "no v9fs_fid\n");
469 return -EBADF;
470 }
471
472 fid = v9fid->fid;
473 if (fid < 0) {
474 dprintk(DEBUG_ERROR, "inode #%lu, no fid!\n",
475 file_inode->i_ino);
476 return -EBADF;
477 }
478
479 result = v9fs_t_remove(v9ses, fid, &fcall);
480 if (result < 0)
481 dprintk(DEBUG_ERROR, "remove of file fails: %s(%d)\n",
482 FCALL_ERROR(fcall), result);
483 else {
484 v9fs_put_idpool(fid, &v9ses->fidpool);
485 v9fs_fid_destroy(v9fid);
486 }
487
488 kfree(fcall);
489 return result;
490}
491
492/**
493 * v9fs_vfs_create - VFS hook to create files
494 * @inode: directory inode that is being deleted
495 * @dentry: dentry that is being deleted
496 * @perm: create permissions
497 * @nd: path information
498 *
499 */
500
501static int
502v9fs_vfs_create(struct inode *inode, struct dentry *dentry, int perm,
503 struct nameidata *nd)
504{
505 return v9fs_create(inode, dentry, perm, O_RDWR);
506}
507
508/**
509 * v9fs_vfs_mkdir - VFS mkdir hook to create a directory
510 * @inode: inode that is being unlinked
511 * @dentry: dentry that is being unlinked
512 * @mode: mode for new directory
513 *
514 */
515
516static int v9fs_vfs_mkdir(struct inode *inode, struct dentry *dentry, int mode)
517{
518 return v9fs_create(inode, dentry, mode | S_IFDIR, O_RDONLY);
519}
520
521/**
522 * v9fs_vfs_lookup - VFS lookup hook to "walk" to a new inode
523 * @dir: inode that is being walked from
524 * @dentry: dentry that is being walked to?
525 * @nameidata: path data
526 *
527 */
528
529static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
530 struct nameidata *nameidata)
531{
532 struct super_block *sb;
533 struct v9fs_session_info *v9ses;
534 struct v9fs_fid *dirfid;
535 struct v9fs_fid *fid;
536 struct inode *inode;
537 struct v9fs_fcall *fcall = NULL;
538 struct stat newstat;
539 int dirfidnum = -1;
540 int newfid = -1;
541 int result = 0;
542
543 dprintk(DEBUG_VFS, "dir: %p dentry: (%s) %p nameidata: %p\n",
544 dir, dentry->d_iname, dentry, nameidata);
545
546 sb = dir->i_sb;
547 v9ses = v9fs_inode2v9ses(dir);
548 dirfid = v9fs_fid_lookup(dentry->d_parent, FID_WALK);
549
550 if (!dirfid) {
551 dprintk(DEBUG_ERROR, "no dirfid\n");
552 return ERR_PTR(-EINVAL);
553 }
554
555 dirfidnum = dirfid->fid;
556
557 if (dirfidnum < 0) {
558 dprintk(DEBUG_ERROR, "no dirfid for inode %p, #%lu\n",
559 dir, dir->i_ino);
560 return ERR_PTR(-EBADF);
561 }
562
563 newfid = v9fs_get_idpool(&v9ses->fidpool);
564 if (newfid < 0) {
565 eprintk(KERN_WARNING, "newfid fails!\n");
566 return ERR_PTR(-ENOSPC);
567 }
568
569 result =
570 v9fs_t_walk(v9ses, dirfidnum, newfid, (char *)dentry->d_name.name,
571 NULL);
572 if (result < 0) {
573 v9fs_put_idpool(newfid, &v9ses->fidpool);
574 if (result == -ENOENT) {
575 d_add(dentry, NULL);
576 dprintk(DEBUG_ERROR,
577 "Return negative dentry %p count %d\n",
578 dentry, atomic_read(&dentry->d_count));
579 return NULL;
580 }
581 dprintk(DEBUG_ERROR, "walk error:%d\n", result);
582 goto FreeFcall;
583 }
584
585 result = v9fs_t_stat(v9ses, newfid, &fcall);
586 if (result < 0) {
587 dprintk(DEBUG_ERROR, "stat error\n");
588 goto FreeFcall;
589 }
590
591 v9fs_mistat2unix(fcall->params.rstat.stat, &newstat, sb);
592 inode = v9fs_get_inode(sb, newstat.st_mode);
593
594 if (IS_ERR(inode) && (PTR_ERR(inode) == -ENOSPC)) {
595 eprintk(KERN_WARNING, "inode alloc failes, returns %ld\n",
596 PTR_ERR(inode));
597
598 result = -ENOSPC;
599 goto FreeFcall;
600 }
601
602 inode->i_ino = v9fs_qid2ino(&fcall->params.rstat.stat->qid);
603
604 fid = v9fs_fid_create(dentry);
605 if (fid == NULL) {
606 dprintk(DEBUG_ERROR, "couldn't insert\n");
607 result = -ENOMEM;
608 goto FreeFcall;
609 }
610
611 fid->fid = newfid;
612 fid->fidopen = 0;
613 fid->v9ses = v9ses;
614 fid->qid = fcall->params.rstat.stat->qid;
615
616 dentry->d_op = &v9fs_dentry_operations;
617 v9fs_mistat2inode(fcall->params.rstat.stat, inode, inode->i_sb);
618
619 d_add(dentry, inode);
620 kfree(fcall);
621
622 return NULL;
623
624 FreeFcall:
625 kfree(fcall);
626 return ERR_PTR(result);
627}
628
629/**
630 * v9fs_vfs_unlink - VFS unlink hook to delete an inode
631 * @i: inode that is being unlinked
632 * @d: dentry that is being unlinked
633 *
634 */
635
636static int v9fs_vfs_unlink(struct inode *i, struct dentry *d)
637{
638 return v9fs_remove(i, d, 0);
639}
640
641/**
642 * v9fs_vfs_rmdir - VFS unlink hook to delete a directory
643 * @i: inode that is being unlinked
644 * @d: dentry that is being unlinked
645 *
646 */
647
648static int v9fs_vfs_rmdir(struct inode *i, struct dentry *d)
649{
650 return v9fs_remove(i, d, 1);
651}
652
653/**
654 * v9fs_vfs_rename - VFS hook to rename an inode
655 * @old_dir: old dir inode
656 * @old_dentry: old dentry
657 * @new_dir: new dir inode
658 * @new_dentry: new dentry
659 *
660 */
661
662static int
663v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
664 struct inode *new_dir, struct dentry *new_dentry)
665{
666 struct inode *old_inode = old_dentry->d_inode;
667 struct v9fs_session_info *v9ses = v9fs_inode2v9ses(old_inode);
668 struct v9fs_fid *oldfid = v9fs_fid_lookup(old_dentry, FID_WALK);
669 struct v9fs_fid *olddirfid =
670 v9fs_fid_lookup(old_dentry->d_parent, FID_WALK);
671 struct v9fs_fid *newdirfid =
672 v9fs_fid_lookup(new_dentry->d_parent, FID_WALK);
673 struct v9fs_stat *mistat = kmalloc(v9ses->maxdata, GFP_KERNEL);
674 struct v9fs_fcall *fcall = NULL;
675 int fid = -1;
676 int olddirfidnum = -1;
677 int newdirfidnum = -1;
678 int retval = 0;
679
680 dprintk(DEBUG_VFS, "\n");
681
682 if (!mistat)
683 return -ENOMEM;
684
685 if ((!oldfid) || (!olddirfid) || (!newdirfid)) {
686 dprintk(DEBUG_ERROR, "problem with arguments\n");
687 return -EBADF;
688 }
689
690 /* 9P can only handle file rename in the same directory */
691 if (memcmp(&olddirfid->qid, &newdirfid->qid, sizeof(newdirfid->qid))) {
692 dprintk(DEBUG_ERROR, "old dir and new dir are different\n");
693 retval = -EPERM;
694 goto FreeFcallnBail;
695 }
696
697 fid = oldfid->fid;
698 olddirfidnum = olddirfid->fid;
699 newdirfidnum = newdirfid->fid;
700
701 if (fid < 0) {
702 dprintk(DEBUG_ERROR, "no fid for old file #%lu\n",
703 old_inode->i_ino);
704 retval = -EBADF;
705 goto FreeFcallnBail;
706 }
707
708 v9fs_blank_mistat(v9ses, mistat);
709
710 strcpy(mistat->data + 1, v9ses->name);
711 mistat->name = mistat->data + 1 + strlen(v9ses->name);
712
713 if (new_dentry->d_name.len >
714 (v9ses->maxdata - strlen(v9ses->name) - sizeof(struct v9fs_stat))) {
715 dprintk(DEBUG_ERROR, "new name too long\n");
716 goto FreeFcallnBail;
717 }
718
719 strcpy(mistat->name, new_dentry->d_name.name);
720 retval = v9fs_t_wstat(v9ses, fid, mistat, &fcall);
721
722 FreeFcallnBail:
723 kfree(mistat);
724
725 if (retval < 0)
726 dprintk(DEBUG_ERROR, "v9fs_t_wstat error: %s\n",
727 FCALL_ERROR(fcall));
728
729 kfree(fcall);
730 return retval;
731}
732
733/**
734 * v9fs_vfs_getattr - retreive file metadata
735 * @mnt - mount information
736 * @dentry - file to get attributes on
737 * @stat - metadata structure to populate
738 *
739 */
740
741static int
742v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
743 struct kstat *stat)
744{
745 struct v9fs_fcall *fcall = NULL;
746 struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode);
747 struct v9fs_fid *fid = v9fs_fid_lookup(dentry, FID_OP);
748 int err = -EPERM;
749
750 dprintk(DEBUG_VFS, "dentry: %p\n", dentry);
751 if (!fid) {
752 dprintk(DEBUG_ERROR,
753 "couldn't find fid associated with dentry\n");
754 return -EBADF;
755 }
756
757 err = v9fs_t_stat(v9ses, fid->fid, &fcall);
758
759 if (err < 0)
760 dprintk(DEBUG_ERROR, "stat error\n");
761 else {
762 v9fs_mistat2inode(fcall->params.rstat.stat, dentry->d_inode,
763 dentry->d_inode->i_sb);
764 generic_fillattr(dentry->d_inode, stat);
765 }
766
767 kfree(fcall);
768 return err;
769}
770
771/**
772 * v9fs_vfs_setattr - set file metadata
773 * @dentry: file whose metadata to set
774 * @iattr: metadata assignment structure
775 *
776 */
777
778static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
779{
780 struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode);
781 struct v9fs_fid *fid = v9fs_fid_lookup(dentry, FID_OP);
782 struct v9fs_fcall *fcall = NULL;
783 struct v9fs_stat *mistat = kmalloc(v9ses->maxdata, GFP_KERNEL);
784 int res = -EPERM;
785
786 dprintk(DEBUG_VFS, "\n");
787
788 if (!mistat)
789 return -ENOMEM;
790
791 if (!fid) {
792 dprintk(DEBUG_ERROR,
793 "Couldn't find fid associated with dentry\n");
794 return -EBADF;
795 }
796
797 v9fs_blank_mistat(v9ses, mistat);
798 if (iattr->ia_valid & ATTR_MODE)
799 mistat->mode = unixmode2p9mode(v9ses, iattr->ia_mode);
800
801 if (iattr->ia_valid & ATTR_MTIME)
802 mistat->mtime = iattr->ia_mtime.tv_sec;
803
804 if (iattr->ia_valid & ATTR_ATIME)
805 mistat->atime = iattr->ia_atime.tv_sec;
806
807 if (iattr->ia_valid & ATTR_SIZE)
808 mistat->length = iattr->ia_size;
809
810 if (v9ses->extended) {
811 char *ptr = mistat->data+1;
812
813 if (iattr->ia_valid & ATTR_UID) {
814 mistat->uid = ptr;
815 ptr += 1+sprintf(ptr, "%08x", iattr->ia_uid);
816 mistat->n_uid = iattr->ia_uid;
817 }
818
819 if (iattr->ia_valid & ATTR_GID) {
820 mistat->gid = ptr;
821 ptr += 1+sprintf(ptr, "%08x", iattr->ia_gid);
822 mistat->n_gid = iattr->ia_gid;
823 }
824 }
825
826 res = v9fs_t_wstat(v9ses, fid->fid, mistat, &fcall);
827
828 if (res < 0)
829 dprintk(DEBUG_ERROR, "wstat error: %s\n", FCALL_ERROR(fcall));
830
831 kfree(mistat);
832 kfree(fcall);
833
834 if (res >= 0)
835 res = inode_setattr(dentry->d_inode, iattr);
836
837 return res;
838}
839
840/**
841 * v9fs_mistat2inode - populate an inode structure with mistat info
842 * @mistat: Plan 9 metadata (mistat) structure
843 * @inode: inode to populate
844 * @sb: superblock of filesystem
845 *
846 */
847
848void
849v9fs_mistat2inode(struct v9fs_stat *mistat, struct inode *inode,
850 struct super_block *sb)
851{
852 struct v9fs_session_info *v9ses = sb->s_fs_info;
853
854 inode->i_nlink = 1;
855
856 inode->i_atime.tv_sec = mistat->atime;
857 inode->i_mtime.tv_sec = mistat->mtime;
858 inode->i_ctime.tv_sec = mistat->mtime;
859
860 inode->i_uid = -1;
861 inode->i_gid = -1;
862
863 if (v9ses->extended) {
864 /* TODO: string to uid mapping via user-space daemon */
865 inode->i_uid = mistat->n_uid;
866 inode->i_gid = mistat->n_gid;
867
868 if (mistat->n_uid == -1)
869 sscanf(mistat->uid, "%x", &inode->i_uid);
870
871 if (mistat->n_gid == -1)
872 sscanf(mistat->gid, "%x", &inode->i_gid);
873 }
874
875 if (inode->i_uid == -1)
876 inode->i_uid = v9ses->uid;
877 if (inode->i_gid == -1)
878 inode->i_gid = v9ses->gid;
879
880 inode->i_mode = p9mode2unixmode(v9ses, mistat->mode);
881 if ((S_ISBLK(inode->i_mode)) || (S_ISCHR(inode->i_mode))) {
882 char type = 0;
883 int major = -1;
884 int minor = -1;
885 sscanf(mistat->extension, "%c %u %u", &type, &major, &minor);
886 switch (type) {
887 case 'c':
888 inode->i_mode &= ~S_IFBLK;
889 inode->i_mode |= S_IFCHR;
890 break;
891 case 'b':
892 break;
893 default:
894 dprintk(DEBUG_ERROR, "Unknown special type %c (%s)\n",
895 type, mistat->extension);
896 };
897 inode->i_rdev = MKDEV(major, minor);
898 } else
899 inode->i_rdev = 0;
900
901 inode->i_size = mistat->length;
902
903 inode->i_blksize = sb->s_blocksize;
904 inode->i_blocks =
905 (inode->i_size + inode->i_blksize - 1) >> sb->s_blocksize_bits;
906}
907
908/**
909 * v9fs_qid2ino - convert qid into inode number
910 * @qid: qid to hash
911 *
912 * BUG: potential for inode number collisions?
913 */
914
915ino_t v9fs_qid2ino(struct v9fs_qid *qid)
916{
917 u64 path = qid->path + 2;
918 ino_t i = 0;
919
920 if (sizeof(ino_t) == sizeof(path))
921 memcpy(&i, &path, sizeof(ino_t));
922 else
923 i = (ino_t) (path ^ (path >> 32));
924
925 return i;
926}
927
928/**
929 * v9fs_vfs_symlink - helper function to create symlinks
930 * @dir: directory inode containing symlink
931 * @dentry: dentry for symlink
932 * @symname: symlink data
933 *
934 * See 9P2000.u RFC for more information
935 *
936 */
937
938static int
939v9fs_vfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
940{
941 int retval = -EPERM;
942 struct v9fs_fid *newfid;
943 struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir);
944 struct v9fs_fcall *fcall = NULL;
945 struct v9fs_stat *mistat = kmalloc(v9ses->maxdata, GFP_KERNEL);
946
947 dprintk(DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name,
948 symname);
949
950 if (!mistat)
951 return -ENOMEM;
952
953 if (!v9ses->extended) {
954 dprintk(DEBUG_ERROR, "not extended\n");
955 goto FreeFcall;
956 }
957
958 /* issue a create */
959 retval = v9fs_create(dir, dentry, S_IFLNK, 0);
960 if (retval != 0)
961 goto FreeFcall;
962
963 newfid = v9fs_fid_lookup(dentry, FID_OP);
964
965 /* issue a twstat */
966 v9fs_blank_mistat(v9ses, mistat);
967 strcpy(mistat->data + 1, symname);
968 mistat->extension = mistat->data + 1;
969 retval = v9fs_t_wstat(v9ses, newfid->fid, mistat, &fcall);
970 if (retval < 0) {
971 dprintk(DEBUG_ERROR, "v9fs_t_wstat error: %s\n",
972 FCALL_ERROR(fcall));
973 goto FreeFcall;
974 }
975
976 kfree(fcall);
977
978 if (v9fs_t_clunk(v9ses, newfid->fid, &fcall)) {
979 dprintk(DEBUG_ERROR, "clunk for symlink failed: %s\n",
980 FCALL_ERROR(fcall));
981 goto FreeFcall;
982 }
983
984 d_drop(dentry); /* FID - will this also clunk? */
985
986 FreeFcall:
987 kfree(mistat);
988 kfree(fcall);
989
990 return retval;
991}
992
993/**
994 * v9fs_readlink - read a symlink's location (internal version)
995 * @dentry: dentry for symlink
996 * @buffer: buffer to load symlink location into
997 * @buflen: length of buffer
998 *
999 */
1000
1001static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen)
1002{
1003 int retval = -EPERM;
1004
1005 struct v9fs_fcall *fcall = NULL;
1006 struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode);
1007 struct v9fs_fid *fid = v9fs_fid_lookup(dentry, FID_OP);
1008
1009 if (!fid) {
1010 dprintk(DEBUG_ERROR, "could not resolve fid from dentry\n");
1011 retval = -EBADF;
1012 goto FreeFcall;
1013 }
1014
1015 if (!v9ses->extended) {
1016 retval = -EBADF;
1017 dprintk(DEBUG_ERROR, "not extended\n");
1018 goto FreeFcall;
1019 }
1020
1021 dprintk(DEBUG_VFS, " %s\n", dentry->d_name.name);
1022 retval = v9fs_t_stat(v9ses, fid->fid, &fcall);
1023
1024 if (retval < 0) {
1025 dprintk(DEBUG_ERROR, "stat error\n");
1026 goto FreeFcall;
1027 }
1028
1029 if (!fcall)
1030 return -EIO;
1031
1032 if (!(fcall->params.rstat.stat->mode & V9FS_DMSYMLINK)) {
1033 retval = -EINVAL;
1034 goto FreeFcall;
1035 }
1036
1037 /* copy extension buffer into buffer */
1038 if (strlen(fcall->params.rstat.stat->extension) < buflen)
1039 buflen = strlen(fcall->params.rstat.stat->extension);
1040
1041 memcpy(buffer, fcall->params.rstat.stat->extension, buflen + 1);
1042
1043 retval = buflen;
1044
1045 FreeFcall:
1046 kfree(fcall);
1047
1048 return retval;
1049}
1050
1051/**
1052 * v9fs_vfs_readlink - read a symlink's location
1053 * @dentry: dentry for symlink
1054 * @buf: buffer to load symlink location into
1055 * @buflen: length of buffer
1056 *
1057 */
1058
1059static int v9fs_vfs_readlink(struct dentry *dentry, char __user * buffer,
1060 int buflen)
1061{
1062 int retval;
1063 int ret;
1064 char *link = __getname();
1065
1066 if (strlen(link) < buflen)
1067 buflen = strlen(link);
1068
1069 dprintk(DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry);
1070
1071 retval = v9fs_readlink(dentry, link, buflen);
1072
1073 if (retval > 0) {
1074 if ((ret = copy_to_user(buffer, link, retval)) != 0) {
1075 dprintk(DEBUG_ERROR, "problem copying to user: %d\n",
1076 ret);
1077 retval = ret;
1078 }
1079 }
1080
1081 putname(link);
1082 return retval;
1083}
1084
1085/**
1086 * v9fs_vfs_follow_link - follow a symlink path
1087 * @dentry: dentry for symlink
1088 * @nd: nameidata
1089 *
1090 */
1091
1092static void *v9fs_vfs_follow_link(struct dentry *dentry, struct nameidata *nd)
1093{
1094 int len = 0;
1095 char *link = __getname();
1096
1097 dprintk(DEBUG_VFS, "%s n", dentry->d_name.name);
1098
1099 if (!link)
1100 link = ERR_PTR(-ENOMEM);
1101 else {
1102 len = v9fs_readlink(dentry, link, strlen(link));
1103
1104 if (len < 0) {
1105 putname(link);
1106 link = ERR_PTR(len);
1107 } else
1108 link[len] = 0;
1109 }
1110 nd_set_link(nd, link);
1111
1112 return NULL;
1113}
1114
1115/**
1116 * v9fs_vfs_put_link - release a symlink path
1117 * @dentry: dentry for symlink
1118 * @nd: nameidata
1119 *
1120 */
1121
1122static void v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd, void *p)
1123{
1124 char *s = nd_get_link(nd);
1125
1126 dprintk(DEBUG_VFS, " %s %s\n", dentry->d_name.name, s);
1127 if (!IS_ERR(s))
1128 putname(s);
1129}
1130
1131/**
1132 * v9fs_vfs_link - create a hardlink
1133 * @old_dentry: dentry for file to link to
1134 * @dir: inode destination for new link
1135 * @dentry: dentry for link
1136 *
1137 */
1138
1139/* XXX - lots of code dup'd from symlink and creates,
1140 * figure out a better reuse strategy
1141 */
1142
1143static int
1144v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir,
1145 struct dentry *dentry)
1146{
1147 int retval = -EPERM;
1148 struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir);
1149 struct v9fs_fcall *fcall = NULL;
1150 struct v9fs_stat *mistat = kmalloc(v9ses->maxdata, GFP_KERNEL);
1151 struct v9fs_fid *oldfid = v9fs_fid_lookup(old_dentry, FID_OP);
1152 struct v9fs_fid *newfid = NULL;
1153 char *symname = __getname();
1154
1155 dprintk(DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name,
1156 old_dentry->d_name.name);
1157
1158 if (!v9ses->extended) {
1159 dprintk(DEBUG_ERROR, "not extended\n");
1160 goto FreeMem;
1161 }
1162
1163 /* get fid of old_dentry */
1164 sprintf(symname, "hardlink(%d)\n", oldfid->fid);
1165
1166 /* issue a create */
1167 retval = v9fs_create(dir, dentry, V9FS_DMLINK, 0);
1168 if (retval != 0)
1169 goto FreeMem;
1170
1171 newfid = v9fs_fid_lookup(dentry, FID_OP);
1172 if (!newfid) {
1173 dprintk(DEBUG_ERROR, "couldn't resolve fid from dentry\n");
1174 goto FreeMem;
1175 }
1176
1177 /* issue a twstat */
1178 v9fs_blank_mistat(v9ses, mistat);
1179 strcpy(mistat->data + 1, symname);
1180 mistat->extension = mistat->data + 1;
1181 retval = v9fs_t_wstat(v9ses, newfid->fid, mistat, &fcall);
1182 if (retval < 0) {
1183 dprintk(DEBUG_ERROR, "v9fs_t_wstat error: %s\n",
1184 FCALL_ERROR(fcall));
1185 goto FreeMem;
1186 }
1187
1188 kfree(fcall);
1189
1190 if (v9fs_t_clunk(v9ses, newfid->fid, &fcall)) {
1191 dprintk(DEBUG_ERROR, "clunk for symlink failed: %s\n",
1192 FCALL_ERROR(fcall));
1193 goto FreeMem;
1194 }
1195
1196 d_drop(dentry); /* FID - will this also clunk? */
1197
1198 kfree(fcall);
1199 fcall = NULL;
1200
1201 FreeMem:
1202 kfree(mistat);
1203 kfree(fcall);
1204 putname(symname);
1205 return retval;
1206}
1207
1208/**
1209 * v9fs_vfs_mknod - create a special file
1210 * @dir: inode destination for new link
1211 * @dentry: dentry for file
1212 * @mode: mode for creation
1213 * @dev_t: device associated with special file
1214 *
1215 */
1216
1217static int
1218v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev)
1219{
1220 int retval = -EPERM;
1221 struct v9fs_fid *newfid;
1222 struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir);
1223 struct v9fs_fcall *fcall = NULL;
1224 struct v9fs_stat *mistat = kmalloc(v9ses->maxdata, GFP_KERNEL);
1225 char *symname = __getname();
1226
1227 dprintk(DEBUG_VFS, " %lu,%s mode: %x MAJOR: %u MINOR: %u\n", dir->i_ino,
1228 dentry->d_name.name, mode, MAJOR(rdev), MINOR(rdev));
1229
1230 if (!mistat)
1231 return -ENOMEM;
1232
1233 if (!new_valid_dev(rdev)) {
1234 retval = -EINVAL;
1235 goto FreeMem;
1236 }
1237
1238 if (!v9ses->extended) {
1239 dprintk(DEBUG_ERROR, "not extended\n");
1240 goto FreeMem;
1241 }
1242
1243 /* issue a create */
1244 retval = v9fs_create(dir, dentry, mode, 0);
1245
1246 if (retval != 0)
1247 goto FreeMem;
1248
1249 newfid = v9fs_fid_lookup(dentry, FID_OP);
1250 if (!newfid) {
1251 dprintk(DEBUG_ERROR, "coudn't resove fid from dentry\n");
1252 retval = -EINVAL;
1253 goto FreeMem;
1254 }
1255
1256 /* build extension */
1257 if (S_ISBLK(mode))
1258 sprintf(symname, "b %u %u", MAJOR(rdev), MINOR(rdev));
1259 else if (S_ISCHR(mode))
1260 sprintf(symname, "c %u %u", MAJOR(rdev), MINOR(rdev));
1261 else if (S_ISFIFO(mode))
1262 ; /* DO NOTHING */
1263 else {
1264 retval = -EINVAL;
1265 goto FreeMem;
1266 }
1267
1268 if (!S_ISFIFO(mode)) {
1269 /* issue a twstat */
1270 v9fs_blank_mistat(v9ses, mistat);
1271 strcpy(mistat->data + 1, symname);
1272 mistat->extension = mistat->data + 1;
1273 retval = v9fs_t_wstat(v9ses, newfid->fid, mistat, &fcall);
1274 if (retval < 0) {
1275 dprintk(DEBUG_ERROR, "v9fs_t_wstat error: %s\n",
1276 FCALL_ERROR(fcall));
1277 goto FreeMem;
1278 }
1279 }
1280
1281 /* need to update dcache so we show up */
1282 kfree(fcall);
1283
1284 if (v9fs_t_clunk(v9ses, newfid->fid, &fcall)) {
1285 dprintk(DEBUG_ERROR, "clunk for symlink failed: %s\n",
1286 FCALL_ERROR(fcall));
1287 goto FreeMem;
1288 }
1289
1290 d_drop(dentry); /* FID - will this also clunk? */
1291
1292 FreeMem:
1293 kfree(mistat);
1294 kfree(fcall);
1295 putname(symname);
1296
1297 return retval;
1298}
1299
1300static struct inode_operations v9fs_dir_inode_operations_ext = {
1301 .create = v9fs_vfs_create,
1302 .lookup = v9fs_vfs_lookup,
1303 .symlink = v9fs_vfs_symlink,
1304 .link = v9fs_vfs_link,
1305 .unlink = v9fs_vfs_unlink,
1306 .mkdir = v9fs_vfs_mkdir,
1307 .rmdir = v9fs_vfs_rmdir,
1308 .mknod = v9fs_vfs_mknod,
1309 .rename = v9fs_vfs_rename,
1310 .readlink = v9fs_vfs_readlink,
1311 .getattr = v9fs_vfs_getattr,
1312 .setattr = v9fs_vfs_setattr,
1313};
1314
1315static struct inode_operations v9fs_dir_inode_operations = {
1316 .create = v9fs_vfs_create,
1317 .lookup = v9fs_vfs_lookup,
1318 .unlink = v9fs_vfs_unlink,
1319 .mkdir = v9fs_vfs_mkdir,
1320 .rmdir = v9fs_vfs_rmdir,
1321 .mknod = v9fs_vfs_mknod,
1322 .rename = v9fs_vfs_rename,
1323 .getattr = v9fs_vfs_getattr,
1324 .setattr = v9fs_vfs_setattr,
1325};
1326
1327static struct inode_operations v9fs_file_inode_operations = {
1328 .getattr = v9fs_vfs_getattr,
1329 .setattr = v9fs_vfs_setattr,
1330};
1331
1332static struct inode_operations v9fs_symlink_inode_operations = {
1333 .readlink = v9fs_vfs_readlink,
1334 .follow_link = v9fs_vfs_follow_link,
1335 .put_link = v9fs_vfs_put_link,
1336 .getattr = v9fs_vfs_getattr,
1337 .setattr = v9fs_vfs_setattr,
1338};
diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c
new file mode 100644
index 0000000000..868f350b2c
--- /dev/null
+++ b/fs/9p/vfs_super.c
@@ -0,0 +1,280 @@
1/*
2 * linux/fs/9p/vfs_super.c
3 *
4 * This file contians superblock ops for 9P2000. It is intended that
5 * you mount this file system on directories.
6 *
7 * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
8 * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to:
22 * Free Software Foundation
23 * 51 Franklin Street, Fifth Floor
24 * Boston, MA 02111-1301 USA
25 *
26 */
27
28#include <linux/kernel.h>
29#include <linux/config.h>
30#include <linux/module.h>
31#include <linux/errno.h>
32#include <linux/fs.h>
33#include <linux/file.h>
34#include <linux/stat.h>
35#include <linux/string.h>
36#include <linux/smp_lock.h>
37#include <linux/inet.h>
38#include <linux/pagemap.h>
39#include <linux/seq_file.h>
40#include <linux/mount.h>
41#include <linux/idr.h>
42
43#include "debug.h"
44#include "v9fs.h"
45#include "9p.h"
46#include "v9fs_vfs.h"
47#include "conv.h"
48#include "fid.h"
49
50static void v9fs_clear_inode(struct inode *);
51static struct super_operations v9fs_super_ops;
52
53/**
54 * v9fs_clear_inode - release an inode
55 * @inode: inode to release
56 *
57 */
58
59static void v9fs_clear_inode(struct inode *inode)
60{
61 filemap_fdatawrite(inode->i_mapping);
62}
63
64/**
65 * v9fs_set_super - set the superblock
66 * @s: super block
67 * @data: file system specific data
68 *
69 */
70
71static int v9fs_set_super(struct super_block *s, void *data)
72{
73 s->s_fs_info = data;
74 return set_anon_super(s, data);
75}
76
77/**
78 * v9fs_fill_super - populate superblock with info
79 * @sb: superblock
80 * @v9ses: session information
81 *
82 */
83
84static void
85v9fs_fill_super(struct super_block *sb, struct v9fs_session_info *v9ses,
86 int flags)
87{
88 sb->s_maxbytes = MAX_LFS_FILESIZE;
89 sb->s_blocksize_bits = fls(v9ses->maxdata - 1);
90 sb->s_blocksize = 1 << sb->s_blocksize_bits;
91 sb->s_magic = V9FS_MAGIC;
92 sb->s_op = &v9fs_super_ops;
93
94 sb->s_flags = flags | MS_ACTIVE | MS_SYNCHRONOUS | MS_DIRSYNC |
95 MS_NODIRATIME | MS_NOATIME;
96}
97
98/**
99 * v9fs_get_sb - mount a superblock
100 * @fs_type: file system type
101 * @flags: mount flags
102 * @dev_name: device name that was mounted
103 * @data: mount options
104 *
105 */
106
107static struct super_block *v9fs_get_sb(struct file_system_type
108 *fs_type, int flags,
109 const char *dev_name, void *data)
110{
111 struct super_block *sb = NULL;
112 struct v9fs_fcall *fcall = NULL;
113 struct inode *inode = NULL;
114 struct dentry *root = NULL;
115 struct v9fs_session_info *v9ses = NULL;
116 struct v9fs_fid *root_fid = NULL;
117 int mode = S_IRWXUGO | S_ISVTX;
118 uid_t uid = current->fsuid;
119 gid_t gid = current->fsgid;
120 int stat_result = 0;
121 int newfid = 0;
122 int retval = 0;
123
124 dprintk(DEBUG_VFS, " \n");
125
126 v9ses = kcalloc(1, sizeof(struct v9fs_session_info), GFP_KERNEL);
127 if (!v9ses)
128 return ERR_PTR(-ENOMEM);
129
130 if ((newfid = v9fs_session_init(v9ses, dev_name, data)) < 0) {
131 dprintk(DEBUG_ERROR, "problem initiating session\n");
132 retval = newfid;
133 goto free_session;
134 }
135
136 sb = sget(fs_type, NULL, v9fs_set_super, v9ses);
137
138 v9fs_fill_super(sb, v9ses, flags);
139
140 inode = v9fs_get_inode(sb, S_IFDIR | mode);
141 if (IS_ERR(inode)) {
142 retval = PTR_ERR(inode);
143 goto put_back_sb;
144 }
145
146 inode->i_uid = uid;
147 inode->i_gid = gid;
148
149 root = d_alloc_root(inode);
150
151 if (!root) {
152 retval = -ENOMEM;
153 goto release_inode;
154 }
155
156 sb->s_root = root;
157
158 /* Setup the Root Inode */
159 root_fid = v9fs_fid_create(root);
160 if (root_fid == NULL) {
161 retval = -ENOMEM;
162 goto release_dentry;
163 }
164
165 root_fid->fidopen = 0;
166 root_fid->v9ses = v9ses;
167
168 stat_result = v9fs_t_stat(v9ses, newfid, &fcall);
169 if (stat_result < 0) {
170 dprintk(DEBUG_ERROR, "stat error\n");
171 v9fs_t_clunk(v9ses, newfid, NULL);
172 v9fs_put_idpool(newfid, &v9ses->fidpool);
173 } else {
174 root_fid->fid = newfid;
175 root_fid->qid = fcall->params.rstat.stat->qid;
176 root->d_inode->i_ino =
177 v9fs_qid2ino(&fcall->params.rstat.stat->qid);
178 v9fs_mistat2inode(fcall->params.rstat.stat, root->d_inode, sb);
179 }
180
181 kfree(fcall);
182
183 if (stat_result < 0) {
184 retval = stat_result;
185 goto release_dentry;
186 }
187
188 return sb;
189
190 release_dentry:
191 dput(sb->s_root);
192
193 release_inode:
194 iput(inode);
195
196 put_back_sb:
197 up_write(&sb->s_umount);
198 deactivate_super(sb);
199 v9fs_session_close(v9ses);
200
201 free_session:
202 kfree(v9ses);
203
204 return ERR_PTR(retval);
205}
206
207/**
208 * v9fs_kill_super - Kill Superblock
209 * @s: superblock
210 *
211 */
212
213static void v9fs_kill_super(struct super_block *s)
214{
215 struct v9fs_session_info *v9ses = s->s_fs_info;
216
217 dprintk(DEBUG_VFS, " %p\n", s);
218
219 v9fs_dentry_release(s->s_root); /* clunk root */
220
221 kill_anon_super(s);
222
223 v9fs_session_close(v9ses);
224 kfree(v9ses);
225 dprintk(DEBUG_VFS, "exiting kill_super\n");
226}
227
228/**
229 * v9fs_show_options - Show mount options in /proc/mounts
230 * @m: seq_file to write to
231 * @mnt: mount descriptor
232 *
233 */
234
235static int v9fs_show_options(struct seq_file *m, struct vfsmount *mnt)
236{
237 struct v9fs_session_info *v9ses = mnt->mnt_sb->s_fs_info;
238
239 if (v9ses->debug != 0)
240 seq_printf(m, ",debug=%u", v9ses->debug);
241 if (v9ses->port != V9FS_PORT)
242 seq_printf(m, ",port=%u", v9ses->port);
243 if (v9ses->maxdata != 9000)
244 seq_printf(m, ",msize=%u", v9ses->maxdata);
245 if (v9ses->afid != ~0)
246 seq_printf(m, ",afid=%u", v9ses->afid);
247 if (v9ses->proto == PROTO_UNIX)
248 seq_puts(m, ",proto=unix");
249 if (v9ses->extended == 0)
250 seq_puts(m, ",noextend");
251 if (v9ses->nodev == 1)
252 seq_puts(m, ",nodevmap");
253 seq_printf(m, ",name=%s", v9ses->name);
254 seq_printf(m, ",aname=%s", v9ses->remotename);
255 seq_printf(m, ",uid=%u", v9ses->uid);
256 seq_printf(m, ",gid=%u", v9ses->gid);
257 return 0;
258}
259
260static void
261v9fs_umount_begin(struct super_block *sb)
262{
263 struct v9fs_session_info *v9ses = sb->s_fs_info;
264
265 v9fs_session_cancel(v9ses);
266}
267
268static struct super_operations v9fs_super_ops = {
269 .statfs = simple_statfs,
270 .clear_inode = v9fs_clear_inode,
271 .show_options = v9fs_show_options,
272 .umount_begin = v9fs_umount_begin,
273};
274
275struct file_system_type v9fs_fs_type = {
276 .name = "9P",
277 .get_sb = v9fs_get_sb,
278 .kill_sb = v9fs_kill_super,
279 .owner = THIS_MODULE,
280};
diff --git a/fs/Kconfig b/fs/Kconfig
index 5e817902cb..068ccea2f1 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -462,6 +462,19 @@ config AUTOFS4_FS
462 local network, you probably do not need an automounter, and can say 462 local network, you probably do not need an automounter, and can say
463 N here. 463 N here.
464 464
465config FUSE_FS
466 tristate "Filesystem in Userspace support"
467 help
468 With FUSE it is possible to implement a fully functional filesystem
469 in a userspace program.
470
471 There's also companion library: libfuse. This library along with
472 utilities is available from the FUSE homepage:
473 <http://fuse.sourceforge.net/>
474
475 If you want to develop a userspace FS, or if you want to use
476 a filesystem based on FUSE, answer Y or M.
477
465menu "CD-ROM/DVD Filesystems" 478menu "CD-ROM/DVD Filesystems"
466 479
467config ISO9660_FS 480config ISO9660_FS
@@ -1703,6 +1716,17 @@ config AFS_FS
1703config RXRPC 1716config RXRPC
1704 tristate 1717 tristate
1705 1718
1719config 9P_FS
1720 tristate "Plan 9 Resource Sharing Support (9P2000) (Experimental)"
1721 depends on INET && EXPERIMENTAL
1722 help
1723 If you say Y here, you will get experimental support for
1724 Plan 9 resource sharing via the 9P2000 protocol.
1725
1726 See <http://v9fs.sf.net> for more information.
1727
1728 If unsure, say N.
1729
1706endmenu 1730endmenu
1707 1731
1708menu "Partition Types" 1732menu "Partition Types"
diff --git a/fs/Makefile b/fs/Makefile
index 15158309de..1972da1862 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -89,11 +89,13 @@ obj-$(CONFIG_QNX4FS_FS) += qnx4/
89obj-$(CONFIG_AUTOFS_FS) += autofs/ 89obj-$(CONFIG_AUTOFS_FS) += autofs/
90obj-$(CONFIG_AUTOFS4_FS) += autofs4/ 90obj-$(CONFIG_AUTOFS4_FS) += autofs4/
91obj-$(CONFIG_ADFS_FS) += adfs/ 91obj-$(CONFIG_ADFS_FS) += adfs/
92obj-$(CONFIG_FUSE_FS) += fuse/
92obj-$(CONFIG_UDF_FS) += udf/ 93obj-$(CONFIG_UDF_FS) += udf/
93obj-$(CONFIG_RELAYFS_FS) += relayfs/ 94obj-$(CONFIG_RELAYFS_FS) += relayfs/
94obj-$(CONFIG_SUN_OPENPROMFS) += openpromfs/ 95obj-$(CONFIG_SUN_OPENPROMFS) += openpromfs/
95obj-$(CONFIG_JFS_FS) += jfs/ 96obj-$(CONFIG_JFS_FS) += jfs/
96obj-$(CONFIG_XFS_FS) += xfs/ 97obj-$(CONFIG_XFS_FS) += xfs/
98obj-$(CONFIG_9P_FS) += 9p/
97obj-$(CONFIG_AFS_FS) += afs/ 99obj-$(CONFIG_AFS_FS) += afs/
98obj-$(CONFIG_BEFS_FS) += befs/ 100obj-$(CONFIG_BEFS_FS) += befs/
99obj-$(CONFIG_HOSTFS) += hostfs/ 101obj-$(CONFIG_HOSTFS) += hostfs/
diff --git a/fs/affs/inode.c b/fs/affs/inode.c
index 7aa6f20045..9ebe881c67 100644
--- a/fs/affs/inode.c
+++ b/fs/affs/inode.c
@@ -255,6 +255,7 @@ void
255affs_delete_inode(struct inode *inode) 255affs_delete_inode(struct inode *inode)
256{ 256{
257 pr_debug("AFFS: delete_inode(ino=%lu, nlink=%u)\n", inode->i_ino, inode->i_nlink); 257 pr_debug("AFFS: delete_inode(ino=%lu, nlink=%u)\n", inode->i_ino, inode->i_nlink);
258 truncate_inode_pages(&inode->i_data, 0);
258 inode->i_size = 0; 259 inode->i_size = 0;
259 if (S_ISREG(inode->i_mode)) 260 if (S_ISREG(inode->i_mode))
260 affs_truncate(inode); 261 affs_truncate(inode);
diff --git a/fs/aio.c b/fs/aio.c
index 4f641abac3..38f62680fd 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -29,6 +29,7 @@
29#include <linux/highmem.h> 29#include <linux/highmem.h>
30#include <linux/workqueue.h> 30#include <linux/workqueue.h>
31#include <linux/security.h> 31#include <linux/security.h>
32#include <linux/rcuref.h>
32 33
33#include <asm/kmap_types.h> 34#include <asm/kmap_types.h>
34#include <asm/uaccess.h> 35#include <asm/uaccess.h>
@@ -499,7 +500,7 @@ static int __aio_put_req(struct kioctx *ctx, struct kiocb *req)
499 /* Must be done under the lock to serialise against cancellation. 500 /* Must be done under the lock to serialise against cancellation.
500 * Call this aio_fput as it duplicates fput via the fput_work. 501 * Call this aio_fput as it duplicates fput via the fput_work.
501 */ 502 */
502 if (unlikely(atomic_dec_and_test(&req->ki_filp->f_count))) { 503 if (unlikely(rcuref_dec_and_test(&req->ki_filp->f_count))) {
503 get_ioctx(ctx); 504 get_ioctx(ctx);
504 spin_lock(&fput_lock); 505 spin_lock(&fput_lock);
505 list_add(&req->ki_list, &fput_head); 506 list_add(&req->ki_list, &fput_head);
@@ -546,6 +547,24 @@ struct kioctx *lookup_ioctx(unsigned long ctx_id)
546 return ioctx; 547 return ioctx;
547} 548}
548 549
550static int lock_kiocb_action(void *param)
551{
552 schedule();
553 return 0;
554}
555
556static inline void lock_kiocb(struct kiocb *iocb)
557{
558 wait_on_bit_lock(&iocb->ki_flags, KIF_LOCKED, lock_kiocb_action,
559 TASK_UNINTERRUPTIBLE);
560}
561
562static inline void unlock_kiocb(struct kiocb *iocb)
563{
564 kiocbClearLocked(iocb);
565 wake_up_bit(&iocb->ki_flags, KIF_LOCKED);
566}
567
549/* 568/*
550 * use_mm 569 * use_mm
551 * Makes the calling kernel thread take on the specified 570 * Makes the calling kernel thread take on the specified
@@ -786,7 +805,9 @@ static int __aio_run_iocbs(struct kioctx *ctx)
786 * Hold an extra reference while retrying i/o. 805 * Hold an extra reference while retrying i/o.
787 */ 806 */
788 iocb->ki_users++; /* grab extra reference */ 807 iocb->ki_users++; /* grab extra reference */
808 lock_kiocb(iocb);
789 aio_run_iocb(iocb); 809 aio_run_iocb(iocb);
810 unlock_kiocb(iocb);
790 if (__aio_put_req(ctx, iocb)) /* drop extra ref */ 811 if (__aio_put_req(ctx, iocb)) /* drop extra ref */
791 put_ioctx(ctx); 812 put_ioctx(ctx);
792 } 813 }
@@ -1527,10 +1548,9 @@ int fastcall io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb,
1527 goto out_put_req; 1548 goto out_put_req;
1528 1549
1529 spin_lock_irq(&ctx->ctx_lock); 1550 spin_lock_irq(&ctx->ctx_lock);
1530 if (likely(list_empty(&ctx->run_list))) { 1551 aio_run_iocb(req);
1531 aio_run_iocb(req); 1552 unlock_kiocb(req);
1532 } else { 1553 if (!list_empty(&ctx->run_list)) {
1533 list_add_tail(&req->ki_run_list, &ctx->run_list);
1534 /* drain the run list */ 1554 /* drain the run list */
1535 while (__aio_run_iocbs(ctx)) 1555 while (__aio_run_iocbs(ctx))
1536 ; 1556 ;
@@ -1661,6 +1681,7 @@ asmlinkage long sys_io_cancel(aio_context_t ctx_id, struct iocb __user *iocb,
1661 if (NULL != cancel) { 1681 if (NULL != cancel) {
1662 struct io_event tmp; 1682 struct io_event tmp;
1663 pr_debug("calling cancel\n"); 1683 pr_debug("calling cancel\n");
1684 lock_kiocb(kiocb);
1664 memset(&tmp, 0, sizeof(tmp)); 1685 memset(&tmp, 0, sizeof(tmp));
1665 tmp.obj = (u64)(unsigned long)kiocb->ki_obj.user; 1686 tmp.obj = (u64)(unsigned long)kiocb->ki_obj.user;
1666 tmp.data = kiocb->ki_user_data; 1687 tmp.data = kiocb->ki_user_data;
@@ -1672,8 +1693,9 @@ asmlinkage long sys_io_cancel(aio_context_t ctx_id, struct iocb __user *iocb,
1672 if (copy_to_user(result, &tmp, sizeof(tmp))) 1693 if (copy_to_user(result, &tmp, sizeof(tmp)))
1673 ret = -EFAULT; 1694 ret = -EFAULT;
1674 } 1695 }
1696 unlock_kiocb(kiocb);
1675 } else 1697 } else
1676 printk(KERN_DEBUG "iocb has no cancel operation\n"); 1698 ret = -EINVAL;
1677 1699
1678 put_ioctx(ctx); 1700 put_ioctx(ctx);
1679 1701
diff --git a/fs/autofs/autofs_i.h b/fs/autofs/autofs_i.h
index 6171431272..990c28da5a 100644
--- a/fs/autofs/autofs_i.h
+++ b/fs/autofs/autofs_i.h
@@ -105,6 +105,7 @@ struct autofs_sb_info {
105 struct file *pipe; 105 struct file *pipe;
106 pid_t oz_pgrp; 106 pid_t oz_pgrp;
107 int catatonic; 107 int catatonic;
108 struct super_block *sb;
108 unsigned long exp_timeout; 109 unsigned long exp_timeout;
109 ino_t next_dir_ino; 110 ino_t next_dir_ino;
110 struct autofs_wait_queue *queues; /* Wait queue pointer */ 111 struct autofs_wait_queue *queues; /* Wait queue pointer */
@@ -134,7 +135,7 @@ void autofs_hash_insert(struct autofs_dirhash *,struct autofs_dir_ent *);
134void autofs_hash_delete(struct autofs_dir_ent *); 135void autofs_hash_delete(struct autofs_dir_ent *);
135struct autofs_dir_ent *autofs_hash_enum(const struct autofs_dirhash *,off_t *,struct autofs_dir_ent *); 136struct autofs_dir_ent *autofs_hash_enum(const struct autofs_dirhash *,off_t *,struct autofs_dir_ent *);
136void autofs_hash_dputall(struct autofs_dirhash *); 137void autofs_hash_dputall(struct autofs_dirhash *);
137void autofs_hash_nuke(struct autofs_dirhash *); 138void autofs_hash_nuke(struct autofs_sb_info *);
138 139
139/* Expiration-handling functions */ 140/* Expiration-handling functions */
140 141
diff --git a/fs/autofs/dirhash.c b/fs/autofs/dirhash.c
index 448143fd07..5ccfcf2631 100644
--- a/fs/autofs/dirhash.c
+++ b/fs/autofs/dirhash.c
@@ -232,13 +232,13 @@ void autofs_hash_dputall(struct autofs_dirhash *dh)
232 232
233/* Delete everything. This is used on filesystem destruction, so we 233/* Delete everything. This is used on filesystem destruction, so we
234 make no attempt to keep the pointers valid */ 234 make no attempt to keep the pointers valid */
235void autofs_hash_nuke(struct autofs_dirhash *dh) 235void autofs_hash_nuke(struct autofs_sb_info *sbi)
236{ 236{
237 int i; 237 int i;
238 struct autofs_dir_ent *ent, *nent; 238 struct autofs_dir_ent *ent, *nent;
239 239
240 for ( i = 0 ; i < AUTOFS_HASH_SIZE ; i++ ) { 240 for ( i = 0 ; i < AUTOFS_HASH_SIZE ; i++ ) {
241 for ( ent = dh->h[i] ; ent ; ent = nent ) { 241 for ( ent = sbi->dirhash.h[i] ; ent ; ent = nent ) {
242 nent = ent->next; 242 nent = ent->next;
243 if ( ent->dentry ) 243 if ( ent->dentry )
244 dput(ent->dentry); 244 dput(ent->dentry);
@@ -246,4 +246,5 @@ void autofs_hash_nuke(struct autofs_dirhash *dh)
246 kfree(ent); 246 kfree(ent);
247 } 247 }
248 } 248 }
249 shrink_dcache_sb(sbi->sb);
249} 250}
diff --git a/fs/autofs/inode.c b/fs/autofs/inode.c
index 4888c1fabb..65e5ed4219 100644
--- a/fs/autofs/inode.c
+++ b/fs/autofs/inode.c
@@ -27,7 +27,7 @@ static void autofs_put_super(struct super_block *sb)
27 if ( !sbi->catatonic ) 27 if ( !sbi->catatonic )
28 autofs_catatonic_mode(sbi); /* Free wait queues, close pipe */ 28 autofs_catatonic_mode(sbi); /* Free wait queues, close pipe */
29 29
30 autofs_hash_nuke(&sbi->dirhash); 30 autofs_hash_nuke(sbi);
31 for ( n = 0 ; n < AUTOFS_MAX_SYMLINKS ; n++ ) { 31 for ( n = 0 ; n < AUTOFS_MAX_SYMLINKS ; n++ ) {
32 if ( test_bit(n, sbi->symlink_bitmap) ) 32 if ( test_bit(n, sbi->symlink_bitmap) )
33 kfree(sbi->symlink[n].data); 33 kfree(sbi->symlink[n].data);
@@ -148,6 +148,7 @@ int autofs_fill_super(struct super_block *s, void *data, int silent)
148 s->s_magic = AUTOFS_SUPER_MAGIC; 148 s->s_magic = AUTOFS_SUPER_MAGIC;
149 s->s_op = &autofs_sops; 149 s->s_op = &autofs_sops;
150 s->s_time_gran = 1; 150 s->s_time_gran = 1;
151 sbi->sb = s;
151 152
152 root_inode = iget(s, AUTOFS_ROOT_INO); 153 root_inode = iget(s, AUTOFS_ROOT_INO);
153 root = d_alloc_root(root_inode); 154 root = d_alloc_root(root_inode);
diff --git a/fs/bfs/bfs.h b/fs/bfs/bfs.h
index 1020dbc88b..1fbc53f14a 100644
--- a/fs/bfs/bfs.h
+++ b/fs/bfs/bfs.h
@@ -20,7 +20,6 @@ struct bfs_sb_info {
20 unsigned long si_lasti; 20 unsigned long si_lasti;
21 unsigned long * si_imap; 21 unsigned long * si_imap;
22 struct buffer_head * si_sbh; /* buffer header w/superblock */ 22 struct buffer_head * si_sbh; /* buffer header w/superblock */
23 struct bfs_super_block * si_bfs_sb; /* superblock in si_sbh->b_data */
24}; 23};
25 24
26/* 25/*
diff --git a/fs/bfs/dir.c b/fs/bfs/dir.c
index 5a1e5ce057..e240c335eb 100644
--- a/fs/bfs/dir.c
+++ b/fs/bfs/dir.c
@@ -2,6 +2,7 @@
2 * fs/bfs/dir.c 2 * fs/bfs/dir.c
3 * BFS directory operations. 3 * BFS directory operations.
4 * Copyright (C) 1999,2000 Tigran Aivazian <tigran@veritas.com> 4 * Copyright (C) 1999,2000 Tigran Aivazian <tigran@veritas.com>
5 * Made endianness-clean by Andrew Stribblehill <ads@wompom.org> 2005
5 */ 6 */
6 7
7#include <linux/time.h> 8#include <linux/time.h>
@@ -20,9 +21,9 @@
20#define dprintf(x...) 21#define dprintf(x...)
21#endif 22#endif
22 23
23static int bfs_add_entry(struct inode * dir, const char * name, int namelen, int ino); 24static int bfs_add_entry(struct inode * dir, const unsigned char * name, int namelen, int ino);
24static struct buffer_head * bfs_find_entry(struct inode * dir, 25static struct buffer_head * bfs_find_entry(struct inode * dir,
25 const char * name, int namelen, struct bfs_dirent ** res_dir); 26 const unsigned char * name, int namelen, struct bfs_dirent ** res_dir);
26 27
27static int bfs_readdir(struct file * f, void * dirent, filldir_t filldir) 28static int bfs_readdir(struct file * f, void * dirent, filldir_t filldir)
28{ 29{
@@ -53,7 +54,7 @@ static int bfs_readdir(struct file * f, void * dirent, filldir_t filldir)
53 de = (struct bfs_dirent *)(bh->b_data + offset); 54 de = (struct bfs_dirent *)(bh->b_data + offset);
54 if (de->ino) { 55 if (de->ino) {
55 int size = strnlen(de->name, BFS_NAMELEN); 56 int size = strnlen(de->name, BFS_NAMELEN);
56 if (filldir(dirent, de->name, size, f->f_pos, de->ino, DT_UNKNOWN) < 0) { 57 if (filldir(dirent, de->name, size, f->f_pos, le16_to_cpu(de->ino), DT_UNKNOWN) < 0) {
57 brelse(bh); 58 brelse(bh);
58 unlock_kernel(); 59 unlock_kernel();
59 return 0; 60 return 0;
@@ -107,7 +108,7 @@ static int bfs_create(struct inode * dir, struct dentry * dentry, int mode,
107 inode->i_mapping->a_ops = &bfs_aops; 108 inode->i_mapping->a_ops = &bfs_aops;
108 inode->i_mode = mode; 109 inode->i_mode = mode;
109 inode->i_ino = ino; 110 inode->i_ino = ino;
110 BFS_I(inode)->i_dsk_ino = ino; 111 BFS_I(inode)->i_dsk_ino = cpu_to_le16(ino);
111 BFS_I(inode)->i_sblock = 0; 112 BFS_I(inode)->i_sblock = 0;
112 BFS_I(inode)->i_eblock = 0; 113 BFS_I(inode)->i_eblock = 0;
113 insert_inode_hash(inode); 114 insert_inode_hash(inode);
@@ -139,7 +140,7 @@ static struct dentry * bfs_lookup(struct inode * dir, struct dentry * dentry, st
139 lock_kernel(); 140 lock_kernel();
140 bh = bfs_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de); 141 bh = bfs_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de);
141 if (bh) { 142 if (bh) {
142 unsigned long ino = le32_to_cpu(de->ino); 143 unsigned long ino = (unsigned long)le16_to_cpu(de->ino);
143 brelse(bh); 144 brelse(bh);
144 inode = iget(dir->i_sb, ino); 145 inode = iget(dir->i_sb, ino);
145 if (!inode) { 146 if (!inode) {
@@ -183,7 +184,7 @@ static int bfs_unlink(struct inode * dir, struct dentry * dentry)
183 inode = dentry->d_inode; 184 inode = dentry->d_inode;
184 lock_kernel(); 185 lock_kernel();
185 bh = bfs_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de); 186 bh = bfs_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de);
186 if (!bh || de->ino != inode->i_ino) 187 if (!bh || le16_to_cpu(de->ino) != inode->i_ino)
187 goto out_brelse; 188 goto out_brelse;
188 189
189 if (!inode->i_nlink) { 190 if (!inode->i_nlink) {
@@ -224,7 +225,7 @@ static int bfs_rename(struct inode * old_dir, struct dentry * old_dentry,
224 old_dentry->d_name.name, 225 old_dentry->d_name.name,
225 old_dentry->d_name.len, &old_de); 226 old_dentry->d_name.len, &old_de);
226 227
227 if (!old_bh || old_de->ino != old_inode->i_ino) 228 if (!old_bh || le16_to_cpu(old_de->ino) != old_inode->i_ino)
228 goto end_rename; 229 goto end_rename;
229 230
230 error = -EPERM; 231 error = -EPERM;
@@ -270,7 +271,7 @@ struct inode_operations bfs_dir_inops = {
270 .rename = bfs_rename, 271 .rename = bfs_rename,
271}; 272};
272 273
273static int bfs_add_entry(struct inode * dir, const char * name, int namelen, int ino) 274static int bfs_add_entry(struct inode * dir, const unsigned char * name, int namelen, int ino)
274{ 275{
275 struct buffer_head * bh; 276 struct buffer_head * bh;
276 struct bfs_dirent * de; 277 struct bfs_dirent * de;
@@ -304,7 +305,7 @@ static int bfs_add_entry(struct inode * dir, const char * name, int namelen, int
304 } 305 }
305 dir->i_mtime = CURRENT_TIME_SEC; 306 dir->i_mtime = CURRENT_TIME_SEC;
306 mark_inode_dirty(dir); 307 mark_inode_dirty(dir);
307 de->ino = ino; 308 de->ino = cpu_to_le16((u16)ino);
308 for (i=0; i<BFS_NAMELEN; i++) 309 for (i=0; i<BFS_NAMELEN; i++)
309 de->name[i] = (i < namelen) ? name[i] : 0; 310 de->name[i] = (i < namelen) ? name[i] : 0;
310 mark_buffer_dirty(bh); 311 mark_buffer_dirty(bh);
@@ -317,7 +318,7 @@ static int bfs_add_entry(struct inode * dir, const char * name, int namelen, int
317 return -ENOSPC; 318 return -ENOSPC;
318} 319}
319 320
320static inline int bfs_namecmp(int len, const char * name, const char * buffer) 321static inline int bfs_namecmp(int len, const unsigned char * name, const char * buffer)
321{ 322{
322 if (len < BFS_NAMELEN && buffer[len]) 323 if (len < BFS_NAMELEN && buffer[len])
323 return 0; 324 return 0;
@@ -325,7 +326,7 @@ static inline int bfs_namecmp(int len, const char * name, const char * buffer)
325} 326}
326 327
327static struct buffer_head * bfs_find_entry(struct inode * dir, 328static struct buffer_head * bfs_find_entry(struct inode * dir,
328 const char * name, int namelen, struct bfs_dirent ** res_dir) 329 const unsigned char * name, int namelen, struct bfs_dirent ** res_dir)
329{ 330{
330 unsigned long block, offset; 331 unsigned long block, offset;
331 struct buffer_head * bh; 332 struct buffer_head * bh;
@@ -346,7 +347,7 @@ static struct buffer_head * bfs_find_entry(struct inode * dir,
346 } 347 }
347 de = (struct bfs_dirent *)(bh->b_data + offset); 348 de = (struct bfs_dirent *)(bh->b_data + offset);
348 offset += BFS_DIRENT_SIZE; 349 offset += BFS_DIRENT_SIZE;
349 if (de->ino && bfs_namecmp(namelen, name, de->name)) { 350 if (le16_to_cpu(de->ino) && bfs_namecmp(namelen, name, de->name)) {
350 *res_dir = de; 351 *res_dir = de;
351 return bh; 352 return bh;
352 } 353 }
diff --git a/fs/bfs/file.c b/fs/bfs/file.c
index 747fd1ea55..807723b65d 100644
--- a/fs/bfs/file.c
+++ b/fs/bfs/file.c
@@ -40,8 +40,8 @@ static int bfs_move_block(unsigned long from, unsigned long to, struct super_blo
40 return 0; 40 return 0;
41} 41}
42 42
43static int bfs_move_blocks(struct super_block *sb, unsigned long start, unsigned long end, 43static int bfs_move_blocks(struct super_block *sb, unsigned long start,
44 unsigned long where) 44 unsigned long end, unsigned long where)
45{ 45{
46 unsigned long i; 46 unsigned long i;
47 47
@@ -57,20 +57,21 @@ static int bfs_move_blocks(struct super_block *sb, unsigned long start, unsigned
57static int bfs_get_block(struct inode * inode, sector_t block, 57static int bfs_get_block(struct inode * inode, sector_t block,
58 struct buffer_head * bh_result, int create) 58 struct buffer_head * bh_result, int create)
59{ 59{
60 long phys; 60 unsigned long phys;
61 int err; 61 int err;
62 struct super_block *sb = inode->i_sb; 62 struct super_block *sb = inode->i_sb;
63 struct bfs_sb_info *info = BFS_SB(sb); 63 struct bfs_sb_info *info = BFS_SB(sb);
64 struct bfs_inode_info *bi = BFS_I(inode); 64 struct bfs_inode_info *bi = BFS_I(inode);
65 struct buffer_head *sbh = info->si_sbh; 65 struct buffer_head *sbh = info->si_sbh;
66 66
67 if (block < 0 || block > info->si_blocks) 67 if (block > info->si_blocks)
68 return -EIO; 68 return -EIO;
69 69
70 phys = bi->i_sblock + block; 70 phys = bi->i_sblock + block;
71 if (!create) { 71 if (!create) {
72 if (phys <= bi->i_eblock) { 72 if (phys <= bi->i_eblock) {
73 dprintf("c=%d, b=%08lx, phys=%08lx (granted)\n", create, block, phys); 73 dprintf("c=%d, b=%08lx, phys=%09lx (granted)\n",
74 create, (unsigned long)block, phys);
74 map_bh(bh_result, sb, phys); 75 map_bh(bh_result, sb, phys);
75 } 76 }
76 return 0; 77 return 0;
@@ -80,7 +81,7 @@ static int bfs_get_block(struct inode * inode, sector_t block,
80 of blocks allocated for this file, we can grant it */ 81 of blocks allocated for this file, we can grant it */
81 if (inode->i_size && phys <= bi->i_eblock) { 82 if (inode->i_size && phys <= bi->i_eblock) {
82 dprintf("c=%d, b=%08lx, phys=%08lx (interim block granted)\n", 83 dprintf("c=%d, b=%08lx, phys=%08lx (interim block granted)\n",
83 create, block, phys); 84 create, (unsigned long)block, phys);
84 map_bh(bh_result, sb, phys); 85 map_bh(bh_result, sb, phys);
85 return 0; 86 return 0;
86 } 87 }
@@ -88,11 +89,12 @@ static int bfs_get_block(struct inode * inode, sector_t block,
88 /* the rest has to be protected against itself */ 89 /* the rest has to be protected against itself */
89 lock_kernel(); 90 lock_kernel();
90 91
91 /* if the last data block for this file is the last allocated block, we can 92 /* if the last data block for this file is the last allocated
92 extend the file trivially, without moving it anywhere */ 93 block, we can extend the file trivially, without moving it
94 anywhere */
93 if (bi->i_eblock == info->si_lf_eblk) { 95 if (bi->i_eblock == info->si_lf_eblk) {
94 dprintf("c=%d, b=%08lx, phys=%08lx (simple extension)\n", 96 dprintf("c=%d, b=%08lx, phys=%08lx (simple extension)\n",
95 create, block, phys); 97 create, (unsigned long)block, phys);
96 map_bh(bh_result, sb, phys); 98 map_bh(bh_result, sb, phys);
97 info->si_freeb -= phys - bi->i_eblock; 99 info->si_freeb -= phys - bi->i_eblock;
98 info->si_lf_eblk = bi->i_eblock = phys; 100 info->si_lf_eblk = bi->i_eblock = phys;
@@ -114,7 +116,8 @@ static int bfs_get_block(struct inode * inode, sector_t block,
114 } else 116 } else
115 err = 0; 117 err = 0;
116 118
117 dprintf("c=%d, b=%08lx, phys=%08lx (moved)\n", create, block, phys); 119 dprintf("c=%d, b=%08lx, phys=%08lx (moved)\n",
120 create, (unsigned long)block, phys);
118 bi->i_sblock = phys; 121 bi->i_sblock = phys;
119 phys += block; 122 phys += block;
120 info->si_lf_eblk = bi->i_eblock = phys; 123 info->si_lf_eblk = bi->i_eblock = phys;
diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c
index 64e0fb33fc..c7b39aa279 100644
--- a/fs/bfs/inode.c
+++ b/fs/bfs/inode.c
@@ -3,6 +3,8 @@
3 * BFS superblock and inode operations. 3 * BFS superblock and inode operations.
4 * Copyright (C) 1999,2000 Tigran Aivazian <tigran@veritas.com> 4 * Copyright (C) 1999,2000 Tigran Aivazian <tigran@veritas.com>
5 * From fs/minix, Copyright (C) 1991, 1992 Linus Torvalds. 5 * From fs/minix, Copyright (C) 1991, 1992 Linus Torvalds.
6 *
7 * Made endianness-clean by Andrew Stribblehill <ads@wompom.org>, 2005.
6 */ 8 */
7 9
8#include <linux/module.h> 10#include <linux/module.h>
@@ -54,46 +56,50 @@ static void bfs_read_inode(struct inode * inode)
54 off = (ino - BFS_ROOT_INO) % BFS_INODES_PER_BLOCK; 56 off = (ino - BFS_ROOT_INO) % BFS_INODES_PER_BLOCK;
55 di = (struct bfs_inode *)bh->b_data + off; 57 di = (struct bfs_inode *)bh->b_data + off;
56 58
57 inode->i_mode = 0x0000FFFF & di->i_mode; 59 inode->i_mode = 0x0000FFFF & le32_to_cpu(di->i_mode);
58 if (di->i_vtype == BFS_VDIR) { 60 if (le32_to_cpu(di->i_vtype) == BFS_VDIR) {
59 inode->i_mode |= S_IFDIR; 61 inode->i_mode |= S_IFDIR;
60 inode->i_op = &bfs_dir_inops; 62 inode->i_op = &bfs_dir_inops;
61 inode->i_fop = &bfs_dir_operations; 63 inode->i_fop = &bfs_dir_operations;
62 } else if (di->i_vtype == BFS_VREG) { 64 } else if (le32_to_cpu(di->i_vtype) == BFS_VREG) {
63 inode->i_mode |= S_IFREG; 65 inode->i_mode |= S_IFREG;
64 inode->i_op = &bfs_file_inops; 66 inode->i_op = &bfs_file_inops;
65 inode->i_fop = &bfs_file_operations; 67 inode->i_fop = &bfs_file_operations;
66 inode->i_mapping->a_ops = &bfs_aops; 68 inode->i_mapping->a_ops = &bfs_aops;
67 } 69 }
68 70
69 inode->i_uid = di->i_uid; 71 BFS_I(inode)->i_sblock = le32_to_cpu(di->i_sblock);
70 inode->i_gid = di->i_gid; 72 BFS_I(inode)->i_eblock = le32_to_cpu(di->i_eblock);
71 inode->i_nlink = di->i_nlink; 73 inode->i_uid = le32_to_cpu(di->i_uid);
74 inode->i_gid = le32_to_cpu(di->i_gid);
75 inode->i_nlink = le32_to_cpu(di->i_nlink);
72 inode->i_size = BFS_FILESIZE(di); 76 inode->i_size = BFS_FILESIZE(di);
73 inode->i_blocks = BFS_FILEBLOCKS(di); 77 inode->i_blocks = BFS_FILEBLOCKS(di);
78 if (inode->i_size || inode->i_blocks) dprintf("Registered inode with %lld size, %ld blocks\n", inode->i_size, inode->i_blocks);
74 inode->i_blksize = PAGE_SIZE; 79 inode->i_blksize = PAGE_SIZE;
75 inode->i_atime.tv_sec = di->i_atime; 80 inode->i_atime.tv_sec = le32_to_cpu(di->i_atime);
76 inode->i_mtime.tv_sec = di->i_mtime; 81 inode->i_mtime.tv_sec = le32_to_cpu(di->i_mtime);
77 inode->i_ctime.tv_sec = di->i_ctime; 82 inode->i_ctime.tv_sec = le32_to_cpu(di->i_ctime);
78 inode->i_atime.tv_nsec = 0; 83 inode->i_atime.tv_nsec = 0;
79 inode->i_mtime.tv_nsec = 0; 84 inode->i_mtime.tv_nsec = 0;
80 inode->i_ctime.tv_nsec = 0; 85 inode->i_ctime.tv_nsec = 0;
81 BFS_I(inode)->i_dsk_ino = di->i_ino; /* can be 0 so we store a copy */ 86 BFS_I(inode)->i_dsk_ino = le16_to_cpu(di->i_ino); /* can be 0 so we store a copy */
82 BFS_I(inode)->i_sblock = di->i_sblock;
83 BFS_I(inode)->i_eblock = di->i_eblock;
84 87
85 brelse(bh); 88 brelse(bh);
86} 89}
87 90
88static int bfs_write_inode(struct inode * inode, int unused) 91static int bfs_write_inode(struct inode * inode, int unused)
89{ 92{
90 unsigned long ino = inode->i_ino; 93 unsigned int ino = (u16)inode->i_ino;
94 unsigned long i_sblock;
91 struct bfs_inode * di; 95 struct bfs_inode * di;
92 struct buffer_head * bh; 96 struct buffer_head * bh;
93 int block, off; 97 int block, off;
94 98
99 dprintf("ino=%08x\n", ino);
100
95 if (ino < BFS_ROOT_INO || ino > BFS_SB(inode->i_sb)->si_lasti) { 101 if (ino < BFS_ROOT_INO || ino > BFS_SB(inode->i_sb)->si_lasti) {
96 printf("Bad inode number %s:%08lx\n", inode->i_sb->s_id, ino); 102 printf("Bad inode number %s:%08x\n", inode->i_sb->s_id, ino);
97 return -EIO; 103 return -EIO;
98 } 104 }
99 105
@@ -101,7 +107,7 @@ static int bfs_write_inode(struct inode * inode, int unused)
101 block = (ino - BFS_ROOT_INO)/BFS_INODES_PER_BLOCK + 1; 107 block = (ino - BFS_ROOT_INO)/BFS_INODES_PER_BLOCK + 1;
102 bh = sb_bread(inode->i_sb, block); 108 bh = sb_bread(inode->i_sb, block);
103 if (!bh) { 109 if (!bh) {
104 printf("Unable to read inode %s:%08lx\n", inode->i_sb->s_id, ino); 110 printf("Unable to read inode %s:%08x\n", inode->i_sb->s_id, ino);
105 unlock_kernel(); 111 unlock_kernel();
106 return -EIO; 112 return -EIO;
107 } 113 }
@@ -109,24 +115,26 @@ static int bfs_write_inode(struct inode * inode, int unused)
109 off = (ino - BFS_ROOT_INO)%BFS_INODES_PER_BLOCK; 115 off = (ino - BFS_ROOT_INO)%BFS_INODES_PER_BLOCK;
110 di = (struct bfs_inode *)bh->b_data + off; 116 di = (struct bfs_inode *)bh->b_data + off;
111 117
112 if (inode->i_ino == BFS_ROOT_INO) 118 if (ino == BFS_ROOT_INO)
113 di->i_vtype = BFS_VDIR; 119 di->i_vtype = cpu_to_le32(BFS_VDIR);
114 else 120 else
115 di->i_vtype = BFS_VREG; 121 di->i_vtype = cpu_to_le32(BFS_VREG);
116 122
117 di->i_ino = inode->i_ino; 123 di->i_ino = cpu_to_le16(ino);
118 di->i_mode = inode->i_mode; 124 di->i_mode = cpu_to_le32(inode->i_mode);
119 di->i_uid = inode->i_uid; 125 di->i_uid = cpu_to_le32(inode->i_uid);
120 di->i_gid = inode->i_gid; 126 di->i_gid = cpu_to_le32(inode->i_gid);
121 di->i_nlink = inode->i_nlink; 127 di->i_nlink = cpu_to_le32(inode->i_nlink);
122 di->i_atime = inode->i_atime.tv_sec; 128 di->i_atime = cpu_to_le32(inode->i_atime.tv_sec);
123 di->i_mtime = inode->i_mtime.tv_sec; 129 di->i_mtime = cpu_to_le32(inode->i_mtime.tv_sec);
124 di->i_ctime = inode->i_ctime.tv_sec; 130 di->i_ctime = cpu_to_le32(inode->i_ctime.tv_sec);
125 di->i_sblock = BFS_I(inode)->i_sblock; 131 i_sblock = BFS_I(inode)->i_sblock;
126 di->i_eblock = BFS_I(inode)->i_eblock; 132 di->i_sblock = cpu_to_le32(i_sblock);
127 di->i_eoffset = di->i_sblock * BFS_BSIZE + inode->i_size - 1; 133 di->i_eblock = cpu_to_le32(BFS_I(inode)->i_eblock);
134 di->i_eoffset = cpu_to_le32(i_sblock * BFS_BSIZE + inode->i_size - 1);
128 135
129 mark_buffer_dirty(bh); 136 mark_buffer_dirty(bh);
137 dprintf("Written ino=%d into %d:%d\n",le16_to_cpu(di->i_ino),block,off);
130 brelse(bh); 138 brelse(bh);
131 unlock_kernel(); 139 unlock_kernel();
132 return 0; 140 return 0;
@@ -140,11 +148,14 @@ static void bfs_delete_inode(struct inode * inode)
140 int block, off; 148 int block, off;
141 struct super_block * s = inode->i_sb; 149 struct super_block * s = inode->i_sb;
142 struct bfs_sb_info * info = BFS_SB(s); 150 struct bfs_sb_info * info = BFS_SB(s);
151 struct bfs_inode_info * bi = BFS_I(inode);
143 152
144 dprintf("ino=%08lx\n", inode->i_ino); 153 dprintf("ino=%08lx\n", ino);
145 154
146 if (inode->i_ino < BFS_ROOT_INO || inode->i_ino > info->si_lasti) { 155 truncate_inode_pages(&inode->i_data, 0);
147 printf("invalid ino=%08lx\n", inode->i_ino); 156
157 if (ino < BFS_ROOT_INO || ino > info->si_lasti) {
158 printf("invalid ino=%08lx\n", ino);
148 return; 159 return;
149 } 160 }
150 161
@@ -160,13 +171,13 @@ static void bfs_delete_inode(struct inode * inode)
160 return; 171 return;
161 } 172 }
162 off = (ino - BFS_ROOT_INO)%BFS_INODES_PER_BLOCK; 173 off = (ino - BFS_ROOT_INO)%BFS_INODES_PER_BLOCK;
163 di = (struct bfs_inode *)bh->b_data + off; 174 di = (struct bfs_inode *) bh->b_data + off;
164 if (di->i_ino) { 175 if (bi->i_dsk_ino) {
165 info->si_freeb += BFS_FILEBLOCKS(di); 176 info->si_freeb += 1 + bi->i_eblock - bi->i_sblock;
166 info->si_freei++; 177 info->si_freei++;
167 clear_bit(di->i_ino, info->si_imap); 178 clear_bit(ino, info->si_imap);
168 dump_imap("delete_inode", s); 179 dump_imap("delete_inode", s);
169 } 180 }
170 di->i_ino = 0; 181 di->i_ino = 0;
171 di->i_sblock = 0; 182 di->i_sblock = 0;
172 mark_buffer_dirty(bh); 183 mark_buffer_dirty(bh);
@@ -272,14 +283,14 @@ static struct super_operations bfs_sops = {
272 283
273void dump_imap(const char *prefix, struct super_block * s) 284void dump_imap(const char *prefix, struct super_block * s)
274{ 285{
275#if 0 286#ifdef DEBUG
276 int i; 287 int i;
277 char *tmpbuf = (char *)get_zeroed_page(GFP_KERNEL); 288 char *tmpbuf = (char *)get_zeroed_page(GFP_KERNEL);
278 289
279 if (!tmpbuf) 290 if (!tmpbuf)
280 return; 291 return;
281 for (i=BFS_SB(s)->si_lasti; i>=0; i--) { 292 for (i=BFS_SB(s)->si_lasti; i>=0; i--) {
282 if (i>PAGE_SIZE-100) break; 293 if (i > PAGE_SIZE-100) break;
283 if (test_bit(i, BFS_SB(s)->si_imap)) 294 if (test_bit(i, BFS_SB(s)->si_imap))
284 strcat(tmpbuf, "1"); 295 strcat(tmpbuf, "1");
285 else 296 else
@@ -295,7 +306,7 @@ static int bfs_fill_super(struct super_block *s, void *data, int silent)
295 struct buffer_head * bh; 306 struct buffer_head * bh;
296 struct bfs_super_block * bfs_sb; 307 struct bfs_super_block * bfs_sb;
297 struct inode * inode; 308 struct inode * inode;
298 int i, imap_len; 309 unsigned i, imap_len;
299 struct bfs_sb_info * info; 310 struct bfs_sb_info * info;
300 311
301 info = kmalloc(sizeof(*info), GFP_KERNEL); 312 info = kmalloc(sizeof(*info), GFP_KERNEL);
@@ -310,19 +321,18 @@ static int bfs_fill_super(struct super_block *s, void *data, int silent)
310 if(!bh) 321 if(!bh)
311 goto out; 322 goto out;
312 bfs_sb = (struct bfs_super_block *)bh->b_data; 323 bfs_sb = (struct bfs_super_block *)bh->b_data;
313 if (bfs_sb->s_magic != BFS_MAGIC) { 324 if (le32_to_cpu(bfs_sb->s_magic) != BFS_MAGIC) {
314 if (!silent) 325 if (!silent)
315 printf("No BFS filesystem on %s (magic=%08x)\n", 326 printf("No BFS filesystem on %s (magic=%08x)\n",
316 s->s_id, bfs_sb->s_magic); 327 s->s_id, le32_to_cpu(bfs_sb->s_magic));
317 goto out; 328 goto out;
318 } 329 }
319 if (BFS_UNCLEAN(bfs_sb, s) && !silent) 330 if (BFS_UNCLEAN(bfs_sb, s) && !silent)
320 printf("%s is unclean, continuing\n", s->s_id); 331 printf("%s is unclean, continuing\n", s->s_id);
321 332
322 s->s_magic = BFS_MAGIC; 333 s->s_magic = BFS_MAGIC;
323 info->si_bfs_sb = bfs_sb;
324 info->si_sbh = bh; 334 info->si_sbh = bh;
325 info->si_lasti = (bfs_sb->s_start - BFS_BSIZE)/sizeof(struct bfs_inode) 335 info->si_lasti = (le32_to_cpu(bfs_sb->s_start) - BFS_BSIZE)/sizeof(struct bfs_inode)
326 + BFS_ROOT_INO - 1; 336 + BFS_ROOT_INO - 1;
327 337
328 imap_len = info->si_lasti/8 + 1; 338 imap_len = info->si_lasti/8 + 1;
@@ -346,8 +356,8 @@ static int bfs_fill_super(struct super_block *s, void *data, int silent)
346 goto out; 356 goto out;
347 } 357 }
348 358
349 info->si_blocks = (bfs_sb->s_end + 1)>>BFS_BSIZE_BITS; /* for statfs(2) */ 359 info->si_blocks = (le32_to_cpu(bfs_sb->s_end) + 1)>>BFS_BSIZE_BITS; /* for statfs(2) */
350 info->si_freeb = (bfs_sb->s_end + 1 - bfs_sb->s_start)>>BFS_BSIZE_BITS; 360 info->si_freeb = (le32_to_cpu(bfs_sb->s_end) + 1 - cpu_to_le32(bfs_sb->s_start))>>BFS_BSIZE_BITS;
351 info->si_freei = 0; 361 info->si_freei = 0;
352 info->si_lf_eblk = 0; 362 info->si_lf_eblk = 0;
353 info->si_lf_sblk = 0; 363 info->si_lf_sblk = 0;
diff --git a/fs/buffer.c b/fs/buffer.c
index 1c62203a49..6cbfceabd9 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -40,6 +40,7 @@
40#include <linux/cpu.h> 40#include <linux/cpu.h>
41#include <linux/bitops.h> 41#include <linux/bitops.h>
42#include <linux/mpage.h> 42#include <linux/mpage.h>
43#include <linux/bit_spinlock.h>
43 44
44static int fsync_buffers_list(spinlock_t *lock, struct list_head *list); 45static int fsync_buffers_list(spinlock_t *lock, struct list_head *list);
45static void invalidate_bh_lrus(void); 46static void invalidate_bh_lrus(void);
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 3217ac5f6b..2335f14a15 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -3215,10 +3215,8 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3215 } 3215 }
3216 3216
3217 cifs_sb->tcon = NULL; 3217 cifs_sb->tcon = NULL;
3218 if (ses) { 3218 if (ses)
3219 set_current_state(TASK_INTERRUPTIBLE); 3219 schedule_timeout_interruptible(msecs_to_jiffies(500));
3220 schedule_timeout(HZ / 2);
3221 }
3222 if (ses) 3220 if (ses)
3223 sesInfoFree(ses); 3221 sesInfoFree(ses);
3224 3222
diff --git a/fs/compat.c b/fs/compat.c
index 8c665705c6..ac3fb9ed8e 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -1619,6 +1619,7 @@ compat_sys_select(int n, compat_ulong_t __user *inp, compat_ulong_t __user *outp
1619 char *bits; 1619 char *bits;
1620 long timeout; 1620 long timeout;
1621 int size, max_fdset, ret = -EINVAL; 1621 int size, max_fdset, ret = -EINVAL;
1622 struct fdtable *fdt;
1622 1623
1623 timeout = MAX_SCHEDULE_TIMEOUT; 1624 timeout = MAX_SCHEDULE_TIMEOUT;
1624 if (tvp) { 1625 if (tvp) {
@@ -1644,7 +1645,10 @@ compat_sys_select(int n, compat_ulong_t __user *inp, compat_ulong_t __user *outp
1644 goto out_nofds; 1645 goto out_nofds;
1645 1646
1646 /* max_fdset can increase, so grab it once to avoid race */ 1647 /* max_fdset can increase, so grab it once to avoid race */
1647 max_fdset = current->files->max_fdset; 1648 rcu_read_lock();
1649 fdt = files_fdtable(current->files);
1650 max_fdset = fdt->max_fdset;
1651 rcu_read_unlock();
1648 if (n > max_fdset) 1652 if (n > max_fdset)
1649 n = max_fdset; 1653 n = max_fdset;
1650 1654
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index 155e612635..e28a74203f 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -798,13 +798,16 @@ static int routing_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
798 r = (void *) &r4; 798 r = (void *) &r4;
799 } 799 }
800 800
801 if (ret) 801 if (ret) {
802 return -EFAULT; 802 ret = -EFAULT;
803 goto out;
804 }
803 805
804 set_fs (KERNEL_DS); 806 set_fs (KERNEL_DS);
805 ret = sys_ioctl (fd, cmd, (unsigned long) r); 807 ret = sys_ioctl (fd, cmd, (unsigned long) r);
806 set_fs (old_fs); 808 set_fs (old_fs);
807 809
810out:
808 if (mysock) 811 if (mysock)
809 sockfd_put(mysock); 812 sockfd_put(mysock);
810 813
diff --git a/fs/cramfs/uncompress.c b/fs/cramfs/uncompress.c
index 5034365b06..8def89f2c4 100644
--- a/fs/cramfs/uncompress.c
+++ b/fs/cramfs/uncompress.c
@@ -19,6 +19,7 @@
19#include <linux/errno.h> 19#include <linux/errno.h>
20#include <linux/vmalloc.h> 20#include <linux/vmalloc.h>
21#include <linux/zlib.h> 21#include <linux/zlib.h>
22#include <linux/cramfs_fs.h>
22 23
23static z_stream stream; 24static z_stream stream;
24static int initialized; 25static int initialized;
diff --git a/fs/dcache.c b/fs/dcache.c
index a15a2e1f55..7376b61269 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -337,12 +337,10 @@ struct dentry * d_find_alias(struct inode *inode)
337 */ 337 */
338void d_prune_aliases(struct inode *inode) 338void d_prune_aliases(struct inode *inode)
339{ 339{
340 struct list_head *tmp, *head = &inode->i_dentry; 340 struct dentry *dentry;
341restart: 341restart:
342 spin_lock(&dcache_lock); 342 spin_lock(&dcache_lock);
343 tmp = head; 343 list_for_each_entry(dentry, &inode->i_dentry, d_alias) {
344 while ((tmp = tmp->next) != head) {
345 struct dentry *dentry = list_entry(tmp, struct dentry, d_alias);
346 spin_lock(&dentry->d_lock); 344 spin_lock(&dentry->d_lock);
347 if (!atomic_read(&dentry->d_count)) { 345 if (!atomic_read(&dentry->d_count)) {
348 __dget_locked(dentry); 346 __dget_locked(dentry);
@@ -463,10 +461,7 @@ void shrink_dcache_sb(struct super_block * sb)
463 * superblock to the most recent end of the unused list. 461 * superblock to the most recent end of the unused list.
464 */ 462 */
465 spin_lock(&dcache_lock); 463 spin_lock(&dcache_lock);
466 next = dentry_unused.next; 464 list_for_each_safe(tmp, next, &dentry_unused) {
467 while (next != &dentry_unused) {
468 tmp = next;
469 next = tmp->next;
470 dentry = list_entry(tmp, struct dentry, d_lru); 465 dentry = list_entry(tmp, struct dentry, d_lru);
471 if (dentry->d_sb != sb) 466 if (dentry->d_sb != sb)
472 continue; 467 continue;
@@ -478,10 +473,7 @@ void shrink_dcache_sb(struct super_block * sb)
478 * Pass two ... free the dentries for this superblock. 473 * Pass two ... free the dentries for this superblock.
479 */ 474 */
480repeat: 475repeat:
481 next = dentry_unused.next; 476 list_for_each_safe(tmp, next, &dentry_unused) {
482 while (next != &dentry_unused) {
483 tmp = next;
484 next = tmp->next;
485 dentry = list_entry(tmp, struct dentry, d_lru); 477 dentry = list_entry(tmp, struct dentry, d_lru);
486 if (dentry->d_sb != sb) 478 if (dentry->d_sb != sb)
487 continue; 479 continue;
diff --git a/fs/exec.c b/fs/exec.c
index 222ab1c572..14dd03907c 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -798,6 +798,7 @@ no_thread_group:
798static inline void flush_old_files(struct files_struct * files) 798static inline void flush_old_files(struct files_struct * files)
799{ 799{
800 long j = -1; 800 long j = -1;
801 struct fdtable *fdt;
801 802
802 spin_lock(&files->file_lock); 803 spin_lock(&files->file_lock);
803 for (;;) { 804 for (;;) {
@@ -805,12 +806,13 @@ static inline void flush_old_files(struct files_struct * files)
805 806
806 j++; 807 j++;
807 i = j * __NFDBITS; 808 i = j * __NFDBITS;
808 if (i >= files->max_fds || i >= files->max_fdset) 809 fdt = files_fdtable(files);
810 if (i >= fdt->max_fds || i >= fdt->max_fdset)
809 break; 811 break;
810 set = files->close_on_exec->fds_bits[j]; 812 set = fdt->close_on_exec->fds_bits[j];
811 if (!set) 813 if (!set)
812 continue; 814 continue;
813 files->close_on_exec->fds_bits[j] = 0; 815 fdt->close_on_exec->fds_bits[j] = 0;
814 spin_unlock(&files->file_lock); 816 spin_unlock(&files->file_lock);
815 for ( ; set ; i++,set >>= 1) { 817 for ( ; set ; i++,set >>= 1) {
816 if (set & 1) { 818 if (set & 1) {
diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c
index 161f156d98..c8d07030c8 100644
--- a/fs/ext2/ialloc.c
+++ b/fs/ext2/ialloc.c
@@ -615,6 +615,11 @@ got:
615 DQUOT_DROP(inode); 615 DQUOT_DROP(inode);
616 goto fail2; 616 goto fail2;
617 } 617 }
618 err = ext2_init_security(inode,dir);
619 if (err) {
620 DQUOT_FREE_INODE(inode);
621 goto fail2;
622 }
618 mark_inode_dirty(inode); 623 mark_inode_dirty(inode);
619 ext2_debug("allocating inode %lu\n", inode->i_ino); 624 ext2_debug("allocating inode %lu\n", inode->i_ino);
620 ext2_preread_inode(inode); 625 ext2_preread_inode(inode);
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index 53dceb0c65..fdba4d1d3c 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -71,6 +71,8 @@ void ext2_put_inode(struct inode *inode)
71 */ 71 */
72void ext2_delete_inode (struct inode * inode) 72void ext2_delete_inode (struct inode * inode)
73{ 73{
74 truncate_inode_pages(&inode->i_data, 0);
75
74 if (is_bad_inode(inode)) 76 if (is_bad_inode(inode))
75 goto no_delete; 77 goto no_delete;
76 EXT2_I(inode)->i_dtime = get_seconds(); 78 EXT2_I(inode)->i_dtime = get_seconds();
diff --git a/fs/ext2/xattr.h b/fs/ext2/xattr.h
index 5f3bfde3b8..67cfeb66e8 100644
--- a/fs/ext2/xattr.h
+++ b/fs/ext2/xattr.h
@@ -116,3 +116,11 @@ exit_ext2_xattr(void)
116 116
117# endif /* CONFIG_EXT2_FS_XATTR */ 117# endif /* CONFIG_EXT2_FS_XATTR */
118 118
119#ifdef CONFIG_EXT2_FS_SECURITY
120extern int ext2_init_security(struct inode *inode, struct inode *dir);
121#else
122static inline int ext2_init_security(struct inode *inode, struct inode *dir)
123{
124 return 0;
125}
126#endif
diff --git a/fs/ext2/xattr_security.c b/fs/ext2/xattr_security.c
index 6a6c59fbe5..a266127984 100644
--- a/fs/ext2/xattr_security.c
+++ b/fs/ext2/xattr_security.c
@@ -8,6 +8,7 @@
8#include <linux/fs.h> 8#include <linux/fs.h>
9#include <linux/smp_lock.h> 9#include <linux/smp_lock.h>
10#include <linux/ext2_fs.h> 10#include <linux/ext2_fs.h>
11#include <linux/security.h>
11#include "xattr.h" 12#include "xattr.h"
12 13
13static size_t 14static size_t
@@ -45,6 +46,27 @@ ext2_xattr_security_set(struct inode *inode, const char *name,
45 value, size, flags); 46 value, size, flags);
46} 47}
47 48
49int
50ext2_init_security(struct inode *inode, struct inode *dir)
51{
52 int err;
53 size_t len;
54 void *value;
55 char *name;
56
57 err = security_inode_init_security(inode, dir, &name, &value, &len);
58 if (err) {
59 if (err == -EOPNOTSUPP)
60 return 0;
61 return err;
62 }
63 err = ext2_xattr_set(inode, EXT2_XATTR_INDEX_SECURITY,
64 name, value, len, 0);
65 kfree(name);
66 kfree(value);
67 return err;
68}
69
48struct xattr_handler ext2_xattr_security_handler = { 70struct xattr_handler ext2_xattr_security_handler = {
49 .prefix = XATTR_SECURITY_PREFIX, 71 .prefix = XATTR_SECURITY_PREFIX,
50 .list = ext2_xattr_security_list, 72 .list = ext2_xattr_security_list,
diff --git a/fs/ext3/ialloc.c b/fs/ext3/ialloc.c
index 6981bd014e..96552769d0 100644
--- a/fs/ext3/ialloc.c
+++ b/fs/ext3/ialloc.c
@@ -607,6 +607,11 @@ got:
607 DQUOT_DROP(inode); 607 DQUOT_DROP(inode);
608 goto fail2; 608 goto fail2;
609 } 609 }
610 err = ext3_init_security(handle,inode, dir);
611 if (err) {
612 DQUOT_FREE_INODE(inode);
613 goto fail2;
614 }
610 err = ext3_mark_inode_dirty(handle, inode); 615 err = ext3_mark_inode_dirty(handle, inode);
611 if (err) { 616 if (err) {
612 ext3_std_error(sb, err); 617 ext3_std_error(sb, err);
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
index 9989fdcf4d..b5177c90d6 100644
--- a/fs/ext3/inode.c
+++ b/fs/ext3/inode.c
@@ -187,6 +187,8 @@ void ext3_delete_inode (struct inode * inode)
187{ 187{
188 handle_t *handle; 188 handle_t *handle;
189 189
190 truncate_inode_pages(&inode->i_data, 0);
191
190 if (is_bad_inode(inode)) 192 if (is_bad_inode(inode))
191 goto no_delete; 193 goto no_delete;
192 194
diff --git a/fs/ext3/xattr.h b/fs/ext3/xattr.h
index eb31a69e82..2ceae38f3d 100644
--- a/fs/ext3/xattr.h
+++ b/fs/ext3/xattr.h
@@ -133,3 +133,14 @@ exit_ext3_xattr(void)
133#define ext3_xattr_handlers NULL 133#define ext3_xattr_handlers NULL
134 134
135# endif /* CONFIG_EXT3_FS_XATTR */ 135# endif /* CONFIG_EXT3_FS_XATTR */
136
137#ifdef CONFIG_EXT3_FS_SECURITY
138extern int ext3_init_security(handle_t *handle, struct inode *inode,
139 struct inode *dir);
140#else
141static inline int ext3_init_security(handle_t *handle, struct inode *inode,
142 struct inode *dir)
143{
144 return 0;
145}
146#endif
diff --git a/fs/ext3/xattr_security.c b/fs/ext3/xattr_security.c
index ddc1c41750..b9c40c1564 100644
--- a/fs/ext3/xattr_security.c
+++ b/fs/ext3/xattr_security.c
@@ -9,6 +9,7 @@
9#include <linux/smp_lock.h> 9#include <linux/smp_lock.h>
10#include <linux/ext3_jbd.h> 10#include <linux/ext3_jbd.h>
11#include <linux/ext3_fs.h> 11#include <linux/ext3_fs.h>
12#include <linux/security.h>
12#include "xattr.h" 13#include "xattr.h"
13 14
14static size_t 15static size_t
@@ -47,6 +48,27 @@ ext3_xattr_security_set(struct inode *inode, const char *name,
47 value, size, flags); 48 value, size, flags);
48} 49}
49 50
51int
52ext3_init_security(handle_t *handle, struct inode *inode, struct inode *dir)
53{
54 int err;
55 size_t len;
56 void *value;
57 char *name;
58
59 err = security_inode_init_security(inode, dir, &name, &value, &len);
60 if (err) {
61 if (err == -EOPNOTSUPP)
62 return 0;
63 return err;
64 }
65 err = ext3_xattr_set_handle(handle, inode, EXT3_XATTR_INDEX_SECURITY,
66 name, value, len, 0);
67 kfree(name);
68 kfree(value);
69 return err;
70}
71
50struct xattr_handler ext3_xattr_security_handler = { 72struct xattr_handler ext3_xattr_security_handler = {
51 .prefix = XATTR_SECURITY_PREFIX, 73 .prefix = XATTR_SECURITY_PREFIX,
52 .list = ext3_xattr_security_list, 74 .list = ext3_xattr_security_list,
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index 96ae85b67e..a7cbe68e22 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -335,6 +335,8 @@ EXPORT_SYMBOL(fat_build_inode);
335 335
336static void fat_delete_inode(struct inode *inode) 336static void fat_delete_inode(struct inode *inode)
337{ 337{
338 truncate_inode_pages(&inode->i_data, 0);
339
338 if (!is_bad_inode(inode)) { 340 if (!is_bad_inode(inode)) {
339 inode->i_size = 0; 341 inode->i_size = 0;
340 fat_truncate(inode); 342 fat_truncate(inode);
diff --git a/fs/fcntl.c b/fs/fcntl.c
index 6fbc9d8fcc..863b46e0d7 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -16,6 +16,7 @@
16#include <linux/security.h> 16#include <linux/security.h>
17#include <linux/ptrace.h> 17#include <linux/ptrace.h>
18#include <linux/signal.h> 18#include <linux/signal.h>
19#include <linux/rcupdate.h>
19 20
20#include <asm/poll.h> 21#include <asm/poll.h>
21#include <asm/siginfo.h> 22#include <asm/siginfo.h>
@@ -24,21 +25,25 @@
24void fastcall set_close_on_exec(unsigned int fd, int flag) 25void fastcall set_close_on_exec(unsigned int fd, int flag)
25{ 26{
26 struct files_struct *files = current->files; 27 struct files_struct *files = current->files;
28 struct fdtable *fdt;
27 spin_lock(&files->file_lock); 29 spin_lock(&files->file_lock);
30 fdt = files_fdtable(files);
28 if (flag) 31 if (flag)
29 FD_SET(fd, files->close_on_exec); 32 FD_SET(fd, fdt->close_on_exec);
30 else 33 else
31 FD_CLR(fd, files->close_on_exec); 34 FD_CLR(fd, fdt->close_on_exec);
32 spin_unlock(&files->file_lock); 35 spin_unlock(&files->file_lock);
33} 36}
34 37
35static inline int get_close_on_exec(unsigned int fd) 38static inline int get_close_on_exec(unsigned int fd)
36{ 39{
37 struct files_struct *files = current->files; 40 struct files_struct *files = current->files;
41 struct fdtable *fdt;
38 int res; 42 int res;
39 spin_lock(&files->file_lock); 43 rcu_read_lock();
40 res = FD_ISSET(fd, files->close_on_exec); 44 fdt = files_fdtable(files);
41 spin_unlock(&files->file_lock); 45 res = FD_ISSET(fd, fdt->close_on_exec);
46 rcu_read_unlock();
42 return res; 47 return res;
43} 48}
44 49
@@ -54,24 +59,26 @@ static int locate_fd(struct files_struct *files,
54 unsigned int newfd; 59 unsigned int newfd;
55 unsigned int start; 60 unsigned int start;
56 int error; 61 int error;
62 struct fdtable *fdt;
57 63
58 error = -EINVAL; 64 error = -EINVAL;
59 if (orig_start >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur) 65 if (orig_start >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur)
60 goto out; 66 goto out;
61 67
62repeat: 68repeat:
69 fdt = files_fdtable(files);
63 /* 70 /*
64 * Someone might have closed fd's in the range 71 * Someone might have closed fd's in the range
65 * orig_start..files->next_fd 72 * orig_start..fdt->next_fd
66 */ 73 */
67 start = orig_start; 74 start = orig_start;
68 if (start < files->next_fd) 75 if (start < fdt->next_fd)
69 start = files->next_fd; 76 start = fdt->next_fd;
70 77
71 newfd = start; 78 newfd = start;
72 if (start < files->max_fdset) { 79 if (start < fdt->max_fdset) {
73 newfd = find_next_zero_bit(files->open_fds->fds_bits, 80 newfd = find_next_zero_bit(fdt->open_fds->fds_bits,
74 files->max_fdset, start); 81 fdt->max_fdset, start);
75 } 82 }
76 83
77 error = -EMFILE; 84 error = -EMFILE;
@@ -89,9 +96,15 @@ repeat:
89 if (error) 96 if (error)
90 goto repeat; 97 goto repeat;
91 98
92 if (start <= files->next_fd) 99 /*
93 files->next_fd = newfd + 1; 100 * We reacquired files_lock, so we are safe as long as
94 101 * we reacquire the fdtable pointer and use it while holding
102 * the lock, no one can free it during that time.
103 */
104 fdt = files_fdtable(files);
105 if (start <= fdt->next_fd)
106 fdt->next_fd = newfd + 1;
107
95 error = newfd; 108 error = newfd;
96 109
97out: 110out:
@@ -101,13 +114,16 @@ out:
101static int dupfd(struct file *file, unsigned int start) 114static int dupfd(struct file *file, unsigned int start)
102{ 115{
103 struct files_struct * files = current->files; 116 struct files_struct * files = current->files;
117 struct fdtable *fdt;
104 int fd; 118 int fd;
105 119
106 spin_lock(&files->file_lock); 120 spin_lock(&files->file_lock);
107 fd = locate_fd(files, file, start); 121 fd = locate_fd(files, file, start);
108 if (fd >= 0) { 122 if (fd >= 0) {
109 FD_SET(fd, files->open_fds); 123 /* locate_fd() may have expanded fdtable, load the ptr */
110 FD_CLR(fd, files->close_on_exec); 124 fdt = files_fdtable(files);
125 FD_SET(fd, fdt->open_fds);
126 FD_CLR(fd, fdt->close_on_exec);
111 spin_unlock(&files->file_lock); 127 spin_unlock(&files->file_lock);
112 fd_install(fd, file); 128 fd_install(fd, file);
113 } else { 129 } else {
@@ -123,6 +139,7 @@ asmlinkage long sys_dup2(unsigned int oldfd, unsigned int newfd)
123 int err = -EBADF; 139 int err = -EBADF;
124 struct file * file, *tofree; 140 struct file * file, *tofree;
125 struct files_struct * files = current->files; 141 struct files_struct * files = current->files;
142 struct fdtable *fdt;
126 143
127 spin_lock(&files->file_lock); 144 spin_lock(&files->file_lock);
128 if (!(file = fcheck(oldfd))) 145 if (!(file = fcheck(oldfd)))
@@ -148,13 +165,14 @@ asmlinkage long sys_dup2(unsigned int oldfd, unsigned int newfd)
148 165
149 /* Yes. It's a race. In user space. Nothing sane to do */ 166 /* Yes. It's a race. In user space. Nothing sane to do */
150 err = -EBUSY; 167 err = -EBUSY;
151 tofree = files->fd[newfd]; 168 fdt = files_fdtable(files);
152 if (!tofree && FD_ISSET(newfd, files->open_fds)) 169 tofree = fdt->fd[newfd];
170 if (!tofree && FD_ISSET(newfd, fdt->open_fds))
153 goto out_fput; 171 goto out_fput;
154 172
155 files->fd[newfd] = file; 173 rcu_assign_pointer(fdt->fd[newfd], file);
156 FD_SET(newfd, files->open_fds); 174 FD_SET(newfd, fdt->open_fds);
157 FD_CLR(newfd, files->close_on_exec); 175 FD_CLR(newfd, fdt->close_on_exec);
158 spin_unlock(&files->file_lock); 176 spin_unlock(&files->file_lock);
159 177
160 if (tofree) 178 if (tofree)
diff --git a/fs/file.c b/fs/file.c
index 92b5f25985..2127a7b9dc 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -13,6 +13,25 @@
13#include <linux/vmalloc.h> 13#include <linux/vmalloc.h>
14#include <linux/file.h> 14#include <linux/file.h>
15#include <linux/bitops.h> 15#include <linux/bitops.h>
16#include <linux/interrupt.h>
17#include <linux/spinlock.h>
18#include <linux/rcupdate.h>
19#include <linux/workqueue.h>
20
21struct fdtable_defer {
22 spinlock_t lock;
23 struct work_struct wq;
24 struct timer_list timer;
25 struct fdtable *next;
26};
27
28/*
29 * We use this list to defer free fdtables that have vmalloced
30 * sets/arrays. By keeping a per-cpu list, we avoid having to embed
31 * the work_struct in fdtable itself which avoids a 64 byte (i386) increase in
32 * this per-task structure.
33 */
34static DEFINE_PER_CPU(struct fdtable_defer, fdtable_defer_list);
16 35
17 36
18/* 37/*
@@ -48,82 +67,143 @@ void free_fd_array(struct file **array, int num)
48 vfree(array); 67 vfree(array);
49} 68}
50 69
51/* 70static void __free_fdtable(struct fdtable *fdt)
52 * Expand the fd array in the files_struct. Called with the files 71{
53 * spinlock held for write. 72 int fdset_size, fdarray_size;
54 */
55 73
56static int expand_fd_array(struct files_struct *files, int nr) 74 fdset_size = fdt->max_fdset / 8;
57 __releases(files->file_lock) 75 fdarray_size = fdt->max_fds * sizeof(struct file *);
58 __acquires(files->file_lock) 76 free_fdset(fdt->open_fds, fdset_size);
77 free_fdset(fdt->close_on_exec, fdset_size);
78 free_fd_array(fdt->fd, fdarray_size);
79 kfree(fdt);
80}
81
82static void fdtable_timer(unsigned long data)
59{ 83{
60 struct file **new_fds; 84 struct fdtable_defer *fddef = (struct fdtable_defer *)data;
61 int error, nfds;
62 85
63 86 spin_lock(&fddef->lock);
64 error = -EMFILE; 87 /*
65 if (files->max_fds >= NR_OPEN || nr >= NR_OPEN) 88 * If someone already emptied the queue return.
89 */
90 if (!fddef->next)
66 goto out; 91 goto out;
92 if (!schedule_work(&fddef->wq))
93 mod_timer(&fddef->timer, 5);
94out:
95 spin_unlock(&fddef->lock);
96}
67 97
68 nfds = files->max_fds; 98static void free_fdtable_work(struct fdtable_defer *f)
69 spin_unlock(&files->file_lock); 99{
100 struct fdtable *fdt;
70 101
71 /* 102 spin_lock_bh(&f->lock);
72 * Expand to the max in easy steps, and keep expanding it until 103 fdt = f->next;
73 * we have enough for the requested fd array size. 104 f->next = NULL;
74 */ 105 spin_unlock_bh(&f->lock);
106 while(fdt) {
107 struct fdtable *next = fdt->next;
108 __free_fdtable(fdt);
109 fdt = next;
110 }
111}
75 112
76 do { 113static void free_fdtable_rcu(struct rcu_head *rcu)
77#if NR_OPEN_DEFAULT < 256 114{
78 if (nfds < 256) 115 struct fdtable *fdt = container_of(rcu, struct fdtable, rcu);
79 nfds = 256; 116 int fdset_size, fdarray_size;
80 else 117 struct fdtable_defer *fddef;
81#endif
82 if (nfds < (PAGE_SIZE / sizeof(struct file *)))
83 nfds = PAGE_SIZE / sizeof(struct file *);
84 else {
85 nfds = nfds * 2;
86 if (nfds > NR_OPEN)
87 nfds = NR_OPEN;
88 }
89 } while (nfds <= nr);
90 118
91 error = -ENOMEM; 119 BUG_ON(!fdt);
92 new_fds = alloc_fd_array(nfds); 120 fdset_size = fdt->max_fdset / 8;
93 spin_lock(&files->file_lock); 121 fdarray_size = fdt->max_fds * sizeof(struct file *);
94 if (!new_fds)
95 goto out;
96 122
97 /* Copy the existing array and install the new pointer */ 123 if (fdt->free_files) {
98 124 /*
99 if (nfds > files->max_fds) { 125 * The this fdtable was embedded in the files structure
100 struct file **old_fds; 126 * and the files structure itself was getting destroyed.
101 int i; 127 * It is now safe to free the files structure.
102 128 */
103 old_fds = xchg(&files->fd, new_fds); 129 kmem_cache_free(files_cachep, fdt->free_files);
104 i = xchg(&files->max_fds, nfds); 130 return;
105 131 }
106 /* Don't copy/clear the array if we are creating a new 132 if (fdt->max_fdset <= __FD_SETSIZE && fdt->max_fds <= NR_OPEN_DEFAULT) {
107 fd array for fork() */ 133 /*
108 if (i) { 134 * The fdtable was embedded
109 memcpy(new_fds, old_fds, i * sizeof(struct file *)); 135 */
110 /* clear the remainder of the array */ 136 return;
111 memset(&new_fds[i], 0, 137 }
112 (nfds-i) * sizeof(struct file *)); 138 if (fdset_size <= PAGE_SIZE && fdarray_size <= PAGE_SIZE) {
113 139 kfree(fdt->open_fds);
114 spin_unlock(&files->file_lock); 140 kfree(fdt->close_on_exec);
115 free_fd_array(old_fds, i); 141 kfree(fdt->fd);
116 spin_lock(&files->file_lock); 142 kfree(fdt);
117 }
118 } else { 143 } else {
119 /* Somebody expanded the array while we slept ... */ 144 fddef = &get_cpu_var(fdtable_defer_list);
120 spin_unlock(&files->file_lock); 145 spin_lock(&fddef->lock);
121 free_fd_array(new_fds, nfds); 146 fdt->next = fddef->next;
122 spin_lock(&files->file_lock); 147 fddef->next = fdt;
148 /*
149 * vmallocs are handled from the workqueue context.
150 * If the per-cpu workqueue is running, then we
151 * defer work scheduling through a timer.
152 */
153 if (!schedule_work(&fddef->wq))
154 mod_timer(&fddef->timer, 5);
155 spin_unlock(&fddef->lock);
156 put_cpu_var(fdtable_defer_list);
123 } 157 }
124 error = 0; 158}
125out: 159
126 return error; 160void free_fdtable(struct fdtable *fdt)
161{
162 if (fdt->free_files || fdt->max_fdset > __FD_SETSIZE ||
163 fdt->max_fds > NR_OPEN_DEFAULT)
164 call_rcu(&fdt->rcu, free_fdtable_rcu);
165}
166
167/*
168 * Expand the fdset in the files_struct. Called with the files spinlock
169 * held for write.
170 */
171static void copy_fdtable(struct fdtable *nfdt, struct fdtable *fdt)
172{
173 int i;
174 int count;
175
176 BUG_ON(nfdt->max_fdset < fdt->max_fdset);
177 BUG_ON(nfdt->max_fds < fdt->max_fds);
178 /* Copy the existing tables and install the new pointers */
179
180 i = fdt->max_fdset / (sizeof(unsigned long) * 8);
181 count = (nfdt->max_fdset - fdt->max_fdset) / 8;
182
183 /*
184 * Don't copy the entire array if the current fdset is
185 * not yet initialised.
186 */
187 if (i) {
188 memcpy (nfdt->open_fds, fdt->open_fds,
189 fdt->max_fdset/8);
190 memcpy (nfdt->close_on_exec, fdt->close_on_exec,
191 fdt->max_fdset/8);
192 memset (&nfdt->open_fds->fds_bits[i], 0, count);
193 memset (&nfdt->close_on_exec->fds_bits[i], 0, count);
194 }
195
196 /* Don't copy/clear the array if we are creating a new
197 fd array for fork() */
198 if (fdt->max_fds) {
199 memcpy(nfdt->fd, fdt->fd,
200 fdt->max_fds * sizeof(struct file *));
201 /* clear the remainder of the array */
202 memset(&nfdt->fd[fdt->max_fds], 0,
203 (nfdt->max_fds - fdt->max_fds) *
204 sizeof(struct file *));
205 }
206 nfdt->next_fd = fdt->next_fd;
127} 207}
128 208
129/* 209/*
@@ -154,26 +234,21 @@ void free_fdset(fd_set *array, int num)
154 vfree(array); 234 vfree(array);
155} 235}
156 236
157/* 237static struct fdtable *alloc_fdtable(int nr)
158 * Expand the fdset in the files_struct. Called with the files spinlock
159 * held for write.
160 */
161static int expand_fdset(struct files_struct *files, int nr)
162 __releases(file->file_lock)
163 __acquires(file->file_lock)
164{ 238{
165 fd_set *new_openset = NULL, *new_execset = NULL; 239 struct fdtable *fdt = NULL;
166 int error, nfds = 0; 240 int nfds = 0;
167 241 fd_set *new_openset = NULL, *new_execset = NULL;
168 error = -EMFILE; 242 struct file **new_fds;
169 if (files->max_fdset >= NR_OPEN || nr >= NR_OPEN)
170 goto out;
171 243
172 nfds = files->max_fdset; 244 fdt = kmalloc(sizeof(*fdt), GFP_KERNEL);
173 spin_unlock(&files->file_lock); 245 if (!fdt)
246 goto out;
247 memset(fdt, 0, sizeof(*fdt));
174 248
175 /* Expand to the max in easy steps */ 249 nfds = __FD_SETSIZE;
176 do { 250 /* Expand to the max in easy steps */
251 do {
177 if (nfds < (PAGE_SIZE * 8)) 252 if (nfds < (PAGE_SIZE * 8))
178 nfds = PAGE_SIZE * 8; 253 nfds = PAGE_SIZE * 8;
179 else { 254 else {
@@ -183,49 +258,88 @@ static int expand_fdset(struct files_struct *files, int nr)
183 } 258 }
184 } while (nfds <= nr); 259 } while (nfds <= nr);
185 260
186 error = -ENOMEM; 261 new_openset = alloc_fdset(nfds);
187 new_openset = alloc_fdset(nfds); 262 new_execset = alloc_fdset(nfds);
188 new_execset = alloc_fdset(nfds); 263 if (!new_openset || !new_execset)
189 spin_lock(&files->file_lock); 264 goto out;
190 if (!new_openset || !new_execset) 265 fdt->open_fds = new_openset;
266 fdt->close_on_exec = new_execset;
267 fdt->max_fdset = nfds;
268
269 nfds = NR_OPEN_DEFAULT;
270 /*
271 * Expand to the max in easy steps, and keep expanding it until
272 * we have enough for the requested fd array size.
273 */
274 do {
275#if NR_OPEN_DEFAULT < 256
276 if (nfds < 256)
277 nfds = 256;
278 else
279#endif
280 if (nfds < (PAGE_SIZE / sizeof(struct file *)))
281 nfds = PAGE_SIZE / sizeof(struct file *);
282 else {
283 nfds = nfds * 2;
284 if (nfds > NR_OPEN)
285 nfds = NR_OPEN;
286 }
287 } while (nfds <= nr);
288 new_fds = alloc_fd_array(nfds);
289 if (!new_fds)
290 goto out;
291 fdt->fd = new_fds;
292 fdt->max_fds = nfds;
293 fdt->free_files = NULL;
294 return fdt;
295out:
296 if (new_openset)
297 free_fdset(new_openset, nfds);
298 if (new_execset)
299 free_fdset(new_execset, nfds);
300 kfree(fdt);
301 return NULL;
302}
303
304/*
305 * Expands the file descriptor table - it will allocate a new fdtable and
306 * both fd array and fdset. It is expected to be called with the
307 * files_lock held.
308 */
309static int expand_fdtable(struct files_struct *files, int nr)
310 __releases(files->file_lock)
311 __acquires(files->file_lock)
312{
313 int error = 0;
314 struct fdtable *fdt;
315 struct fdtable *nfdt = NULL;
316
317 spin_unlock(&files->file_lock);
318 nfdt = alloc_fdtable(nr);
319 if (!nfdt) {
320 error = -ENOMEM;
321 spin_lock(&files->file_lock);
191 goto out; 322 goto out;
323 }
192 324
193 error = 0; 325 spin_lock(&files->file_lock);
194 326 fdt = files_fdtable(files);
195 /* Copy the existing tables and install the new pointers */ 327 /*
196 if (nfds > files->max_fdset) { 328 * Check again since another task may have expanded the
197 int i = files->max_fdset / (sizeof(unsigned long) * 8); 329 * fd table while we dropped the lock
198 int count = (nfds - files->max_fdset) / 8; 330 */
199 331 if (nr >= fdt->max_fds || nr >= fdt->max_fdset) {
200 /* 332 copy_fdtable(nfdt, fdt);
201 * Don't copy the entire array if the current fdset is 333 } else {
202 * not yet initialised. 334 /* Somebody expanded while we dropped file_lock */
203 */
204 if (i) {
205 memcpy (new_openset, files->open_fds, files->max_fdset/8);
206 memcpy (new_execset, files->close_on_exec, files->max_fdset/8);
207 memset (&new_openset->fds_bits[i], 0, count);
208 memset (&new_execset->fds_bits[i], 0, count);
209 }
210
211 nfds = xchg(&files->max_fdset, nfds);
212 new_openset = xchg(&files->open_fds, new_openset);
213 new_execset = xchg(&files->close_on_exec, new_execset);
214 spin_unlock(&files->file_lock); 335 spin_unlock(&files->file_lock);
215 free_fdset (new_openset, nfds); 336 __free_fdtable(nfdt);
216 free_fdset (new_execset, nfds);
217 spin_lock(&files->file_lock); 337 spin_lock(&files->file_lock);
218 return 0; 338 goto out;
219 } 339 }
220 /* Somebody expanded the array while we slept ... */ 340 rcu_assign_pointer(files->fdt, nfdt);
221 341 free_fdtable(fdt);
222out: 342out:
223 spin_unlock(&files->file_lock);
224 if (new_openset)
225 free_fdset(new_openset, nfds);
226 if (new_execset)
227 free_fdset(new_execset, nfds);
228 spin_lock(&files->file_lock);
229 return error; 343 return error;
230} 344}
231 345
@@ -237,18 +351,39 @@ out:
237int expand_files(struct files_struct *files, int nr) 351int expand_files(struct files_struct *files, int nr)
238{ 352{
239 int err, expand = 0; 353 int err, expand = 0;
354 struct fdtable *fdt;
240 355
241 if (nr >= files->max_fdset) { 356 fdt = files_fdtable(files);
242 expand = 1; 357 if (nr >= fdt->max_fdset || nr >= fdt->max_fds) {
243 if ((err = expand_fdset(files, nr))) 358 if (fdt->max_fdset >= NR_OPEN ||
359 fdt->max_fds >= NR_OPEN || nr >= NR_OPEN) {
360 err = -EMFILE;
244 goto out; 361 goto out;
245 } 362 }
246 if (nr >= files->max_fds) {
247 expand = 1; 363 expand = 1;
248 if ((err = expand_fd_array(files, nr))) 364 if ((err = expand_fdtable(files, nr)))
249 goto out; 365 goto out;
250 } 366 }
251 err = expand; 367 err = expand;
252out: 368out:
253 return err; 369 return err;
254} 370}
371
372static void __devinit fdtable_defer_list_init(int cpu)
373{
374 struct fdtable_defer *fddef = &per_cpu(fdtable_defer_list, cpu);
375 spin_lock_init(&fddef->lock);
376 INIT_WORK(&fddef->wq, (void (*)(void *))free_fdtable_work, fddef);
377 init_timer(&fddef->timer);
378 fddef->timer.data = (unsigned long)fddef;
379 fddef->timer.function = fdtable_timer;
380 fddef->next = NULL;
381}
382
383void __init files_defer_init(void)
384{
385 int i;
386 /* Really early - can't use for_each_cpu */
387 for (i = 0; i < NR_CPUS; i++)
388 fdtable_defer_list_init(i);
389}
diff --git a/fs/file_table.c b/fs/file_table.c
index 43e9e1737d..86ec8ae985 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -14,6 +14,7 @@
14#include <linux/fs.h> 14#include <linux/fs.h>
15#include <linux/security.h> 15#include <linux/security.h>
16#include <linux/eventpoll.h> 16#include <linux/eventpoll.h>
17#include <linux/rcupdate.h>
17#include <linux/mount.h> 18#include <linux/mount.h>
18#include <linux/cdev.h> 19#include <linux/cdev.h>
19#include <linux/fsnotify.h> 20#include <linux/fsnotify.h>
@@ -53,11 +54,17 @@ void filp_dtor(void * objp, struct kmem_cache_s *cachep, unsigned long dflags)
53 spin_unlock_irqrestore(&filp_count_lock, flags); 54 spin_unlock_irqrestore(&filp_count_lock, flags);
54} 55}
55 56
56static inline void file_free(struct file *f) 57static inline void file_free_rcu(struct rcu_head *head)
57{ 58{
59 struct file *f = container_of(head, struct file, f_rcuhead);
58 kmem_cache_free(filp_cachep, f); 60 kmem_cache_free(filp_cachep, f);
59} 61}
60 62
63static inline void file_free(struct file *f)
64{
65 call_rcu(&f->f_rcuhead, file_free_rcu);
66}
67
61/* Find an unused file structure and return a pointer to it. 68/* Find an unused file structure and return a pointer to it.
62 * Returns NULL, if there are no more free file structures or 69 * Returns NULL, if there are no more free file structures or
63 * we run out of memory. 70 * we run out of memory.
@@ -110,7 +117,7 @@ EXPORT_SYMBOL(get_empty_filp);
110 117
111void fastcall fput(struct file *file) 118void fastcall fput(struct file *file)
112{ 119{
113 if (atomic_dec_and_test(&file->f_count)) 120 if (rcuref_dec_and_test(&file->f_count))
114 __fput(file); 121 __fput(file);
115} 122}
116 123
@@ -156,11 +163,17 @@ struct file fastcall *fget(unsigned int fd)
156 struct file *file; 163 struct file *file;
157 struct files_struct *files = current->files; 164 struct files_struct *files = current->files;
158 165
159 spin_lock(&files->file_lock); 166 rcu_read_lock();
160 file = fcheck_files(files, fd); 167 file = fcheck_files(files, fd);
161 if (file) 168 if (file) {
162 get_file(file); 169 if (!rcuref_inc_lf(&file->f_count)) {
163 spin_unlock(&files->file_lock); 170 /* File object ref couldn't be taken */
171 rcu_read_unlock();
172 return NULL;
173 }
174 }
175 rcu_read_unlock();
176
164 return file; 177 return file;
165} 178}
166 179
@@ -182,21 +195,25 @@ struct file fastcall *fget_light(unsigned int fd, int *fput_needed)
182 if (likely((atomic_read(&files->count) == 1))) { 195 if (likely((atomic_read(&files->count) == 1))) {
183 file = fcheck_files(files, fd); 196 file = fcheck_files(files, fd);
184 } else { 197 } else {
185 spin_lock(&files->file_lock); 198 rcu_read_lock();
186 file = fcheck_files(files, fd); 199 file = fcheck_files(files, fd);
187 if (file) { 200 if (file) {
188 get_file(file); 201 if (rcuref_inc_lf(&file->f_count))
189 *fput_needed = 1; 202 *fput_needed = 1;
203 else
204 /* Didn't get the reference, someone's freed */
205 file = NULL;
190 } 206 }
191 spin_unlock(&files->file_lock); 207 rcu_read_unlock();
192 } 208 }
209
193 return file; 210 return file;
194} 211}
195 212
196 213
197void put_filp(struct file *file) 214void put_filp(struct file *file)
198{ 215{
199 if (atomic_dec_and_test(&file->f_count)) { 216 if (rcuref_dec_and_test(&file->f_count)) {
200 security_file_free(file); 217 security_file_free(file);
201 file_kill(file); 218 file_kill(file);
202 file_free(file); 219 file_free(file);
@@ -257,4 +274,5 @@ void __init files_init(unsigned long mempages)
257 files_stat.max_files = n; 274 files_stat.max_files = n;
258 if (files_stat.max_files < NR_FILE) 275 if (files_stat.max_files < NR_FILE)
259 files_stat.max_files = NR_FILE; 276 files_stat.max_files = NR_FILE;
277 files_defer_init();
260} 278}
diff --git a/fs/fuse/Makefile b/fs/fuse/Makefile
new file mode 100644
index 0000000000..c3e1f760ca
--- /dev/null
+++ b/fs/fuse/Makefile
@@ -0,0 +1,7 @@
1#
2# Makefile for the FUSE filesystem.
3#
4
5obj-$(CONFIG_FUSE_FS) += fuse.o
6
7fuse-objs := dev.o dir.o file.o inode.o
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
new file mode 100644
index 0000000000..d4c869c6d0
--- /dev/null
+++ b/fs/fuse/dev.c
@@ -0,0 +1,877 @@
1/*
2 FUSE: Filesystem in Userspace
3 Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.hu>
4
5 This program can be distributed under the terms of the GNU GPL.
6 See the file COPYING.
7*/
8
9#include "fuse_i.h"
10
11#include <linux/init.h>
12#include <linux/module.h>
13#include <linux/poll.h>
14#include <linux/uio.h>
15#include <linux/miscdevice.h>
16#include <linux/pagemap.h>
17#include <linux/file.h>
18#include <linux/slab.h>
19
20MODULE_ALIAS_MISCDEV(FUSE_MINOR);
21
22static kmem_cache_t *fuse_req_cachep;
23
24static inline struct fuse_conn *fuse_get_conn(struct file *file)
25{
26 struct fuse_conn *fc;
27 spin_lock(&fuse_lock);
28 fc = file->private_data;
29 if (fc && !fc->mounted)
30 fc = NULL;
31 spin_unlock(&fuse_lock);
32 return fc;
33}
34
35static inline void fuse_request_init(struct fuse_req *req)
36{
37 memset(req, 0, sizeof(*req));
38 INIT_LIST_HEAD(&req->list);
39 init_waitqueue_head(&req->waitq);
40 atomic_set(&req->count, 1);
41}
42
43struct fuse_req *fuse_request_alloc(void)
44{
45 struct fuse_req *req = kmem_cache_alloc(fuse_req_cachep, SLAB_KERNEL);
46 if (req)
47 fuse_request_init(req);
48 return req;
49}
50
51void fuse_request_free(struct fuse_req *req)
52{
53 kmem_cache_free(fuse_req_cachep, req);
54}
55
56static inline void block_sigs(sigset_t *oldset)
57{
58 sigset_t mask;
59
60 siginitsetinv(&mask, sigmask(SIGKILL));
61 sigprocmask(SIG_BLOCK, &mask, oldset);
62}
63
64static inline void restore_sigs(sigset_t *oldset)
65{
66 sigprocmask(SIG_SETMASK, oldset, NULL);
67}
68
69void fuse_reset_request(struct fuse_req *req)
70{
71 int preallocated = req->preallocated;
72 BUG_ON(atomic_read(&req->count) != 1);
73 fuse_request_init(req);
74 req->preallocated = preallocated;
75}
76
77static void __fuse_get_request(struct fuse_req *req)
78{
79 atomic_inc(&req->count);
80}
81
82/* Must be called with > 1 refcount */
83static void __fuse_put_request(struct fuse_req *req)
84{
85 BUG_ON(atomic_read(&req->count) < 2);
86 atomic_dec(&req->count);
87}
88
89static struct fuse_req *do_get_request(struct fuse_conn *fc)
90{
91 struct fuse_req *req;
92
93 spin_lock(&fuse_lock);
94 BUG_ON(list_empty(&fc->unused_list));
95 req = list_entry(fc->unused_list.next, struct fuse_req, list);
96 list_del_init(&req->list);
97 spin_unlock(&fuse_lock);
98 fuse_request_init(req);
99 req->preallocated = 1;
100 req->in.h.uid = current->fsuid;
101 req->in.h.gid = current->fsgid;
102 req->in.h.pid = current->pid;
103 return req;
104}
105
106/* This can return NULL, but only in case it's interrupted by a SIGKILL */
107struct fuse_req *fuse_get_request(struct fuse_conn *fc)
108{
109 int intr;
110 sigset_t oldset;
111
112 block_sigs(&oldset);
113 intr = down_interruptible(&fc->outstanding_sem);
114 restore_sigs(&oldset);
115 return intr ? NULL : do_get_request(fc);
116}
117
118static void fuse_putback_request(struct fuse_conn *fc, struct fuse_req *req)
119{
120 spin_lock(&fuse_lock);
121 if (req->preallocated)
122 list_add(&req->list, &fc->unused_list);
123 else
124 fuse_request_free(req);
125
126 /* If we are in debt decrease that first */
127 if (fc->outstanding_debt)
128 fc->outstanding_debt--;
129 else
130 up(&fc->outstanding_sem);
131 spin_unlock(&fuse_lock);
132}
133
134void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req)
135{
136 if (atomic_dec_and_test(&req->count))
137 fuse_putback_request(fc, req);
138}
139
140void fuse_release_background(struct fuse_req *req)
141{
142 iput(req->inode);
143 iput(req->inode2);
144 if (req->file)
145 fput(req->file);
146 spin_lock(&fuse_lock);
147 list_del(&req->bg_entry);
148 spin_unlock(&fuse_lock);
149}
150
151/*
152 * This function is called when a request is finished. Either a reply
153 * has arrived or it was interrupted (and not yet sent) or some error
154 * occured during communication with userspace, or the device file was
155 * closed. It decreases the referece count for the request. In case
156 * of a background request the referece to the stored objects are
157 * released. The requester thread is woken up (if still waiting), and
158 * finally the request is either freed or put on the unused_list
159 *
160 * Called with fuse_lock, unlocks it
161 */
162static void request_end(struct fuse_conn *fc, struct fuse_req *req)
163{
164 int putback;
165 req->finished = 1;
166 putback = atomic_dec_and_test(&req->count);
167 spin_unlock(&fuse_lock);
168 if (req->background) {
169 down_read(&fc->sbput_sem);
170 if (fc->mounted)
171 fuse_release_background(req);
172 up_read(&fc->sbput_sem);
173 }
174 wake_up(&req->waitq);
175 if (req->in.h.opcode == FUSE_INIT) {
176 int i;
177
178 if (req->misc.init_in_out.major != FUSE_KERNEL_VERSION)
179 fc->conn_error = 1;
180
181 /* After INIT reply is received other requests can go
182 out. So do (FUSE_MAX_OUTSTANDING - 1) number of
183 up()s on outstanding_sem. The last up() is done in
184 fuse_putback_request() */
185 for (i = 1; i < FUSE_MAX_OUTSTANDING; i++)
186 up(&fc->outstanding_sem);
187 }
188 if (putback)
189 fuse_putback_request(fc, req);
190}
191
192/*
193 * Unfortunately request interruption not just solves the deadlock
194 * problem, it causes problems too. These stem from the fact, that an
195 * interrupted request is continued to be processed in userspace,
196 * while all the locks and object references (inode and file) held
197 * during the operation are released.
198 *
199 * To release the locks is exactly why there's a need to interrupt the
200 * request, so there's not a lot that can be done about this, except
201 * introduce additional locking in userspace.
202 *
203 * More important is to keep inode and file references until userspace
204 * has replied, otherwise FORGET and RELEASE could be sent while the
205 * inode/file is still used by the filesystem.
206 *
207 * For this reason the concept of "background" request is introduced.
208 * An interrupted request is backgrounded if it has been already sent
209 * to userspace. Backgrounding involves getting an extra reference to
210 * inode(s) or file used in the request, and adding the request to
211 * fc->background list. When a reply is received for a background
212 * request, the object references are released, and the request is
213 * removed from the list. If the filesystem is unmounted while there
214 * are still background requests, the list is walked and references
215 * are released as if a reply was received.
216 *
217 * There's one more use for a background request. The RELEASE message is
218 * always sent as background, since it doesn't return an error or
219 * data.
220 */
221static void background_request(struct fuse_conn *fc, struct fuse_req *req)
222{
223 req->background = 1;
224 list_add(&req->bg_entry, &fc->background);
225 if (req->inode)
226 req->inode = igrab(req->inode);
227 if (req->inode2)
228 req->inode2 = igrab(req->inode2);
229 if (req->file)
230 get_file(req->file);
231}
232
233/* Called with fuse_lock held. Releases, and then reacquires it. */
234static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req)
235{
236 sigset_t oldset;
237
238 spin_unlock(&fuse_lock);
239 block_sigs(&oldset);
240 wait_event_interruptible(req->waitq, req->finished);
241 restore_sigs(&oldset);
242 spin_lock(&fuse_lock);
243 if (req->finished)
244 return;
245
246 req->out.h.error = -EINTR;
247 req->interrupted = 1;
248 if (req->locked) {
249 /* This is uninterruptible sleep, because data is
250 being copied to/from the buffers of req. During
251 locked state, there mustn't be any filesystem
252 operation (e.g. page fault), since that could lead
253 to deadlock */
254 spin_unlock(&fuse_lock);
255 wait_event(req->waitq, !req->locked);
256 spin_lock(&fuse_lock);
257 }
258 if (!req->sent && !list_empty(&req->list)) {
259 list_del(&req->list);
260 __fuse_put_request(req);
261 } else if (!req->finished && req->sent)
262 background_request(fc, req);
263}
264
265static unsigned len_args(unsigned numargs, struct fuse_arg *args)
266{
267 unsigned nbytes = 0;
268 unsigned i;
269
270 for (i = 0; i < numargs; i++)
271 nbytes += args[i].size;
272
273 return nbytes;
274}
275
276static void queue_request(struct fuse_conn *fc, struct fuse_req *req)
277{
278 fc->reqctr++;
279 /* zero is special */
280 if (fc->reqctr == 0)
281 fc->reqctr = 1;
282 req->in.h.unique = fc->reqctr;
283 req->in.h.len = sizeof(struct fuse_in_header) +
284 len_args(req->in.numargs, (struct fuse_arg *) req->in.args);
285 if (!req->preallocated) {
286 /* If request is not preallocated (either FORGET or
287 RELEASE), then still decrease outstanding_sem, so
288 user can't open infinite number of files while not
289 processing the RELEASE requests. However for
290 efficiency do it without blocking, so if down()
291 would block, just increase the debt instead */
292 if (down_trylock(&fc->outstanding_sem))
293 fc->outstanding_debt++;
294 }
295 list_add_tail(&req->list, &fc->pending);
296 wake_up(&fc->waitq);
297}
298
299/*
300 * This can only be interrupted by a SIGKILL
301 */
302void request_send(struct fuse_conn *fc, struct fuse_req *req)
303{
304 req->isreply = 1;
305 spin_lock(&fuse_lock);
306 if (!fc->connected)
307 req->out.h.error = -ENOTCONN;
308 else if (fc->conn_error)
309 req->out.h.error = -ECONNREFUSED;
310 else {
311 queue_request(fc, req);
312 /* acquire extra reference, since request is still needed
313 after request_end() */
314 __fuse_get_request(req);
315
316 request_wait_answer(fc, req);
317 }
318 spin_unlock(&fuse_lock);
319}
320
321static void request_send_nowait(struct fuse_conn *fc, struct fuse_req *req)
322{
323 spin_lock(&fuse_lock);
324 if (fc->connected) {
325 queue_request(fc, req);
326 spin_unlock(&fuse_lock);
327 } else {
328 req->out.h.error = -ENOTCONN;
329 request_end(fc, req);
330 }
331}
332
333void request_send_noreply(struct fuse_conn *fc, struct fuse_req *req)
334{
335 req->isreply = 0;
336 request_send_nowait(fc, req);
337}
338
339void request_send_background(struct fuse_conn *fc, struct fuse_req *req)
340{
341 req->isreply = 1;
342 spin_lock(&fuse_lock);
343 background_request(fc, req);
344 spin_unlock(&fuse_lock);
345 request_send_nowait(fc, req);
346}
347
348void fuse_send_init(struct fuse_conn *fc)
349{
350 /* This is called from fuse_read_super() so there's guaranteed
351 to be a request available */
352 struct fuse_req *req = do_get_request(fc);
353 struct fuse_init_in_out *arg = &req->misc.init_in_out;
354 arg->major = FUSE_KERNEL_VERSION;
355 arg->minor = FUSE_KERNEL_MINOR_VERSION;
356 req->in.h.opcode = FUSE_INIT;
357 req->in.numargs = 1;
358 req->in.args[0].size = sizeof(*arg);
359 req->in.args[0].value = arg;
360 req->out.numargs = 1;
361 req->out.args[0].size = sizeof(*arg);
362 req->out.args[0].value = arg;
363 request_send_background(fc, req);
364}
365
366/*
367 * Lock the request. Up to the next unlock_request() there mustn't be
368 * anything that could cause a page-fault. If the request was already
369 * interrupted bail out.
370 */
371static inline int lock_request(struct fuse_req *req)
372{
373 int err = 0;
374 if (req) {
375 spin_lock(&fuse_lock);
376 if (req->interrupted)
377 err = -ENOENT;
378 else
379 req->locked = 1;
380 spin_unlock(&fuse_lock);
381 }
382 return err;
383}
384
385/*
386 * Unlock request. If it was interrupted during being locked, the
387 * requester thread is currently waiting for it to be unlocked, so
388 * wake it up.
389 */
390static inline void unlock_request(struct fuse_req *req)
391{
392 if (req) {
393 spin_lock(&fuse_lock);
394 req->locked = 0;
395 if (req->interrupted)
396 wake_up(&req->waitq);
397 spin_unlock(&fuse_lock);
398 }
399}
400
401struct fuse_copy_state {
402 int write;
403 struct fuse_req *req;
404 const struct iovec *iov;
405 unsigned long nr_segs;
406 unsigned long seglen;
407 unsigned long addr;
408 struct page *pg;
409 void *mapaddr;
410 void *buf;
411 unsigned len;
412};
413
414static void fuse_copy_init(struct fuse_copy_state *cs, int write,
415 struct fuse_req *req, const struct iovec *iov,
416 unsigned long nr_segs)
417{
418 memset(cs, 0, sizeof(*cs));
419 cs->write = write;
420 cs->req = req;
421 cs->iov = iov;
422 cs->nr_segs = nr_segs;
423}
424
425/* Unmap and put previous page of userspace buffer */
426static inline void fuse_copy_finish(struct fuse_copy_state *cs)
427{
428 if (cs->mapaddr) {
429 kunmap_atomic(cs->mapaddr, KM_USER0);
430 if (cs->write) {
431 flush_dcache_page(cs->pg);
432 set_page_dirty_lock(cs->pg);
433 }
434 put_page(cs->pg);
435 cs->mapaddr = NULL;
436 }
437}
438
439/*
440 * Get another pagefull of userspace buffer, and map it to kernel
441 * address space, and lock request
442 */
443static int fuse_copy_fill(struct fuse_copy_state *cs)
444{
445 unsigned long offset;
446 int err;
447
448 unlock_request(cs->req);
449 fuse_copy_finish(cs);
450 if (!cs->seglen) {
451 BUG_ON(!cs->nr_segs);
452 cs->seglen = cs->iov[0].iov_len;
453 cs->addr = (unsigned long) cs->iov[0].iov_base;
454 cs->iov ++;
455 cs->nr_segs --;
456 }
457 down_read(&current->mm->mmap_sem);
458 err = get_user_pages(current, current->mm, cs->addr, 1, cs->write, 0,
459 &cs->pg, NULL);
460 up_read(&current->mm->mmap_sem);
461 if (err < 0)
462 return err;
463 BUG_ON(err != 1);
464 offset = cs->addr % PAGE_SIZE;
465 cs->mapaddr = kmap_atomic(cs->pg, KM_USER0);
466 cs->buf = cs->mapaddr + offset;
467 cs->len = min(PAGE_SIZE - offset, cs->seglen);
468 cs->seglen -= cs->len;
469 cs->addr += cs->len;
470
471 return lock_request(cs->req);
472}
473
474/* Do as much copy to/from userspace buffer as we can */
475static inline int fuse_copy_do(struct fuse_copy_state *cs, void **val,
476 unsigned *size)
477{
478 unsigned ncpy = min(*size, cs->len);
479 if (val) {
480 if (cs->write)
481 memcpy(cs->buf, *val, ncpy);
482 else
483 memcpy(*val, cs->buf, ncpy);
484 *val += ncpy;
485 }
486 *size -= ncpy;
487 cs->len -= ncpy;
488 cs->buf += ncpy;
489 return ncpy;
490}
491
492/*
493 * Copy a page in the request to/from the userspace buffer. Must be
494 * done atomically
495 */
496static inline int fuse_copy_page(struct fuse_copy_state *cs, struct page *page,
497 unsigned offset, unsigned count, int zeroing)
498{
499 if (page && zeroing && count < PAGE_SIZE) {
500 void *mapaddr = kmap_atomic(page, KM_USER1);
501 memset(mapaddr, 0, PAGE_SIZE);
502 kunmap_atomic(mapaddr, KM_USER1);
503 }
504 while (count) {
505 int err;
506 if (!cs->len && (err = fuse_copy_fill(cs)))
507 return err;
508 if (page) {
509 void *mapaddr = kmap_atomic(page, KM_USER1);
510 void *buf = mapaddr + offset;
511 offset += fuse_copy_do(cs, &buf, &count);
512 kunmap_atomic(mapaddr, KM_USER1);
513 } else
514 offset += fuse_copy_do(cs, NULL, &count);
515 }
516 if (page && !cs->write)
517 flush_dcache_page(page);
518 return 0;
519}
520
521/* Copy pages in the request to/from userspace buffer */
522static int fuse_copy_pages(struct fuse_copy_state *cs, unsigned nbytes,
523 int zeroing)
524{
525 unsigned i;
526 struct fuse_req *req = cs->req;
527 unsigned offset = req->page_offset;
528 unsigned count = min(nbytes, (unsigned) PAGE_SIZE - offset);
529
530 for (i = 0; i < req->num_pages && (nbytes || zeroing); i++) {
531 struct page *page = req->pages[i];
532 int err = fuse_copy_page(cs, page, offset, count, zeroing);
533 if (err)
534 return err;
535
536 nbytes -= count;
537 count = min(nbytes, (unsigned) PAGE_SIZE);
538 offset = 0;
539 }
540 return 0;
541}
542
543/* Copy a single argument in the request to/from userspace buffer */
544static int fuse_copy_one(struct fuse_copy_state *cs, void *val, unsigned size)
545{
546 while (size) {
547 int err;
548 if (!cs->len && (err = fuse_copy_fill(cs)))
549 return err;
550 fuse_copy_do(cs, &val, &size);
551 }
552 return 0;
553}
554
555/* Copy request arguments to/from userspace buffer */
556static int fuse_copy_args(struct fuse_copy_state *cs, unsigned numargs,
557 unsigned argpages, struct fuse_arg *args,
558 int zeroing)
559{
560 int err = 0;
561 unsigned i;
562
563 for (i = 0; !err && i < numargs; i++) {
564 struct fuse_arg *arg = &args[i];
565 if (i == numargs - 1 && argpages)
566 err = fuse_copy_pages(cs, arg->size, zeroing);
567 else
568 err = fuse_copy_one(cs, arg->value, arg->size);
569 }
570 return err;
571}
572
573/* Wait until a request is available on the pending list */
574static void request_wait(struct fuse_conn *fc)
575{
576 DECLARE_WAITQUEUE(wait, current);
577
578 add_wait_queue_exclusive(&fc->waitq, &wait);
579 while (fc->mounted && list_empty(&fc->pending)) {
580 set_current_state(TASK_INTERRUPTIBLE);
581 if (signal_pending(current))
582 break;
583
584 spin_unlock(&fuse_lock);
585 schedule();
586 spin_lock(&fuse_lock);
587 }
588 set_current_state(TASK_RUNNING);
589 remove_wait_queue(&fc->waitq, &wait);
590}
591
592/*
593 * Read a single request into the userspace filesystem's buffer. This
594 * function waits until a request is available, then removes it from
595 * the pending list and copies request data to userspace buffer. If
596 * no reply is needed (FORGET) or request has been interrupted or
597 * there was an error during the copying then it's finished by calling
598 * request_end(). Otherwise add it to the processing list, and set
599 * the 'sent' flag.
600 */
601static ssize_t fuse_dev_readv(struct file *file, const struct iovec *iov,
602 unsigned long nr_segs, loff_t *off)
603{
604 int err;
605 struct fuse_conn *fc;
606 struct fuse_req *req;
607 struct fuse_in *in;
608 struct fuse_copy_state cs;
609 unsigned reqsize;
610
611 spin_lock(&fuse_lock);
612 fc = file->private_data;
613 err = -EPERM;
614 if (!fc)
615 goto err_unlock;
616 request_wait(fc);
617 err = -ENODEV;
618 if (!fc->mounted)
619 goto err_unlock;
620 err = -ERESTARTSYS;
621 if (list_empty(&fc->pending))
622 goto err_unlock;
623
624 req = list_entry(fc->pending.next, struct fuse_req, list);
625 list_del_init(&req->list);
626 spin_unlock(&fuse_lock);
627
628 in = &req->in;
629 reqsize = req->in.h.len;
630 fuse_copy_init(&cs, 1, req, iov, nr_segs);
631 err = -EINVAL;
632 if (iov_length(iov, nr_segs) >= reqsize) {
633 err = fuse_copy_one(&cs, &in->h, sizeof(in->h));
634 if (!err)
635 err = fuse_copy_args(&cs, in->numargs, in->argpages,
636 (struct fuse_arg *) in->args, 0);
637 }
638 fuse_copy_finish(&cs);
639
640 spin_lock(&fuse_lock);
641 req->locked = 0;
642 if (!err && req->interrupted)
643 err = -ENOENT;
644 if (err) {
645 if (!req->interrupted)
646 req->out.h.error = -EIO;
647 request_end(fc, req);
648 return err;
649 }
650 if (!req->isreply)
651 request_end(fc, req);
652 else {
653 req->sent = 1;
654 list_add_tail(&req->list, &fc->processing);
655 spin_unlock(&fuse_lock);
656 }
657 return reqsize;
658
659 err_unlock:
660 spin_unlock(&fuse_lock);
661 return err;
662}
663
664static ssize_t fuse_dev_read(struct file *file, char __user *buf,
665 size_t nbytes, loff_t *off)
666{
667 struct iovec iov;
668 iov.iov_len = nbytes;
669 iov.iov_base = buf;
670 return fuse_dev_readv(file, &iov, 1, off);
671}
672
673/* Look up request on processing list by unique ID */
674static struct fuse_req *request_find(struct fuse_conn *fc, u64 unique)
675{
676 struct list_head *entry;
677
678 list_for_each(entry, &fc->processing) {
679 struct fuse_req *req;
680 req = list_entry(entry, struct fuse_req, list);
681 if (req->in.h.unique == unique)
682 return req;
683 }
684 return NULL;
685}
686
687static int copy_out_args(struct fuse_copy_state *cs, struct fuse_out *out,
688 unsigned nbytes)
689{
690 unsigned reqsize = sizeof(struct fuse_out_header);
691
692 if (out->h.error)
693 return nbytes != reqsize ? -EINVAL : 0;
694
695 reqsize += len_args(out->numargs, out->args);
696
697 if (reqsize < nbytes || (reqsize > nbytes && !out->argvar))
698 return -EINVAL;
699 else if (reqsize > nbytes) {
700 struct fuse_arg *lastarg = &out->args[out->numargs-1];
701 unsigned diffsize = reqsize - nbytes;
702 if (diffsize > lastarg->size)
703 return -EINVAL;
704 lastarg->size -= diffsize;
705 }
706 return fuse_copy_args(cs, out->numargs, out->argpages, out->args,
707 out->page_zeroing);
708}
709
710/*
711 * Write a single reply to a request. First the header is copied from
712 * the write buffer. The request is then searched on the processing
713 * list by the unique ID found in the header. If found, then remove
714 * it from the list and copy the rest of the buffer to the request.
715 * The request is finished by calling request_end()
716 */
717static ssize_t fuse_dev_writev(struct file *file, const struct iovec *iov,
718 unsigned long nr_segs, loff_t *off)
719{
720 int err;
721 unsigned nbytes = iov_length(iov, nr_segs);
722 struct fuse_req *req;
723 struct fuse_out_header oh;
724 struct fuse_copy_state cs;
725 struct fuse_conn *fc = fuse_get_conn(file);
726 if (!fc)
727 return -ENODEV;
728
729 fuse_copy_init(&cs, 0, NULL, iov, nr_segs);
730 if (nbytes < sizeof(struct fuse_out_header))
731 return -EINVAL;
732
733 err = fuse_copy_one(&cs, &oh, sizeof(oh));
734 if (err)
735 goto err_finish;
736 err = -EINVAL;
737 if (!oh.unique || oh.error <= -1000 || oh.error > 0 ||
738 oh.len != nbytes)
739 goto err_finish;
740
741 spin_lock(&fuse_lock);
742 req = request_find(fc, oh.unique);
743 err = -EINVAL;
744 if (!req)
745 goto err_unlock;
746
747 list_del_init(&req->list);
748 if (req->interrupted) {
749 request_end(fc, req);
750 fuse_copy_finish(&cs);
751 return -ENOENT;
752 }
753 req->out.h = oh;
754 req->locked = 1;
755 cs.req = req;
756 spin_unlock(&fuse_lock);
757
758 err = copy_out_args(&cs, &req->out, nbytes);
759 fuse_copy_finish(&cs);
760
761 spin_lock(&fuse_lock);
762 req->locked = 0;
763 if (!err) {
764 if (req->interrupted)
765 err = -ENOENT;
766 } else if (!req->interrupted)
767 req->out.h.error = -EIO;
768 request_end(fc, req);
769
770 return err ? err : nbytes;
771
772 err_unlock:
773 spin_unlock(&fuse_lock);
774 err_finish:
775 fuse_copy_finish(&cs);
776 return err;
777}
778
779static ssize_t fuse_dev_write(struct file *file, const char __user *buf,
780 size_t nbytes, loff_t *off)
781{
782 struct iovec iov;
783 iov.iov_len = nbytes;
784 iov.iov_base = (char __user *) buf;
785 return fuse_dev_writev(file, &iov, 1, off);
786}
787
788static unsigned fuse_dev_poll(struct file *file, poll_table *wait)
789{
790 struct fuse_conn *fc = fuse_get_conn(file);
791 unsigned mask = POLLOUT | POLLWRNORM;
792
793 if (!fc)
794 return -ENODEV;
795
796 poll_wait(file, &fc->waitq, wait);
797
798 spin_lock(&fuse_lock);
799 if (!list_empty(&fc->pending))
800 mask |= POLLIN | POLLRDNORM;
801 spin_unlock(&fuse_lock);
802
803 return mask;
804}
805
806/* Abort all requests on the given list (pending or processing) */
807static void end_requests(struct fuse_conn *fc, struct list_head *head)
808{
809 while (!list_empty(head)) {
810 struct fuse_req *req;
811 req = list_entry(head->next, struct fuse_req, list);
812 list_del_init(&req->list);
813 req->out.h.error = -ECONNABORTED;
814 request_end(fc, req);
815 spin_lock(&fuse_lock);
816 }
817}
818
819static int fuse_dev_release(struct inode *inode, struct file *file)
820{
821 struct fuse_conn *fc;
822
823 spin_lock(&fuse_lock);
824 fc = file->private_data;
825 if (fc) {
826 fc->connected = 0;
827 end_requests(fc, &fc->pending);
828 end_requests(fc, &fc->processing);
829 fuse_release_conn(fc);
830 }
831 spin_unlock(&fuse_lock);
832 return 0;
833}
834
835struct file_operations fuse_dev_operations = {
836 .owner = THIS_MODULE,
837 .llseek = no_llseek,
838 .read = fuse_dev_read,
839 .readv = fuse_dev_readv,
840 .write = fuse_dev_write,
841 .writev = fuse_dev_writev,
842 .poll = fuse_dev_poll,
843 .release = fuse_dev_release,
844};
845
846static struct miscdevice fuse_miscdevice = {
847 .minor = FUSE_MINOR,
848 .name = "fuse",
849 .fops = &fuse_dev_operations,
850};
851
852int __init fuse_dev_init(void)
853{
854 int err = -ENOMEM;
855 fuse_req_cachep = kmem_cache_create("fuse_request",
856 sizeof(struct fuse_req),
857 0, 0, NULL, NULL);
858 if (!fuse_req_cachep)
859 goto out;
860
861 err = misc_register(&fuse_miscdevice);
862 if (err)
863 goto out_cache_clean;
864
865 return 0;
866
867 out_cache_clean:
868 kmem_cache_destroy(fuse_req_cachep);
869 out:
870 return err;
871}
872
873void fuse_dev_cleanup(void)
874{
875 misc_deregister(&fuse_miscdevice);
876 kmem_cache_destroy(fuse_req_cachep);
877}
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
new file mode 100644
index 0000000000..e79e49b3ee
--- /dev/null
+++ b/fs/fuse/dir.c
@@ -0,0 +1,982 @@
1/*
2 FUSE: Filesystem in Userspace
3 Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.hu>
4
5 This program can be distributed under the terms of the GNU GPL.
6 See the file COPYING.
7*/
8
9#include "fuse_i.h"
10
11#include <linux/pagemap.h>
12#include <linux/file.h>
13#include <linux/gfp.h>
14#include <linux/sched.h>
15#include <linux/namei.h>
16
17static inline unsigned long time_to_jiffies(unsigned long sec,
18 unsigned long nsec)
19{
20 struct timespec ts = {sec, nsec};
21 return jiffies + timespec_to_jiffies(&ts);
22}
23
24static void fuse_lookup_init(struct fuse_req *req, struct inode *dir,
25 struct dentry *entry,
26 struct fuse_entry_out *outarg)
27{
28 req->in.h.opcode = FUSE_LOOKUP;
29 req->in.h.nodeid = get_node_id(dir);
30 req->inode = dir;
31 req->in.numargs = 1;
32 req->in.args[0].size = entry->d_name.len + 1;
33 req->in.args[0].value = entry->d_name.name;
34 req->out.numargs = 1;
35 req->out.args[0].size = sizeof(struct fuse_entry_out);
36 req->out.args[0].value = outarg;
37}
38
39static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
40{
41 if (!entry->d_inode || is_bad_inode(entry->d_inode))
42 return 0;
43 else if (time_after(jiffies, entry->d_time)) {
44 int err;
45 struct fuse_entry_out outarg;
46 struct inode *inode = entry->d_inode;
47 struct fuse_inode *fi = get_fuse_inode(inode);
48 struct fuse_conn *fc = get_fuse_conn(inode);
49 struct fuse_req *req = fuse_get_request(fc);
50 if (!req)
51 return 0;
52
53 fuse_lookup_init(req, entry->d_parent->d_inode, entry, &outarg);
54 request_send(fc, req);
55 err = req->out.h.error;
56 if (!err) {
57 if (outarg.nodeid != get_node_id(inode)) {
58 fuse_send_forget(fc, req, outarg.nodeid, 1);
59 return 0;
60 }
61 fi->nlookup ++;
62 }
63 fuse_put_request(fc, req);
64 if (err || (outarg.attr.mode ^ inode->i_mode) & S_IFMT)
65 return 0;
66
67 fuse_change_attributes(inode, &outarg.attr);
68 entry->d_time = time_to_jiffies(outarg.entry_valid,
69 outarg.entry_valid_nsec);
70 fi->i_time = time_to_jiffies(outarg.attr_valid,
71 outarg.attr_valid_nsec);
72 }
73 return 1;
74}
75
76static struct dentry_operations fuse_dentry_operations = {
77 .d_revalidate = fuse_dentry_revalidate,
78};
79
80static int fuse_lookup_iget(struct inode *dir, struct dentry *entry,
81 struct inode **inodep)
82{
83 int err;
84 struct fuse_entry_out outarg;
85 struct inode *inode = NULL;
86 struct fuse_conn *fc = get_fuse_conn(dir);
87 struct fuse_req *req;
88
89 if (entry->d_name.len > FUSE_NAME_MAX)
90 return -ENAMETOOLONG;
91
92 req = fuse_get_request(fc);
93 if (!req)
94 return -EINTR;
95
96 fuse_lookup_init(req, dir, entry, &outarg);
97 request_send(fc, req);
98 err = req->out.h.error;
99 if (!err) {
100 inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
101 &outarg.attr);
102 if (!inode) {
103 fuse_send_forget(fc, req, outarg.nodeid, 1);
104 return -ENOMEM;
105 }
106 }
107 fuse_put_request(fc, req);
108 if (err && err != -ENOENT)
109 return err;
110
111 if (inode) {
112 struct fuse_inode *fi = get_fuse_inode(inode);
113 entry->d_time = time_to_jiffies(outarg.entry_valid,
114 outarg.entry_valid_nsec);
115 fi->i_time = time_to_jiffies(outarg.attr_valid,
116 outarg.attr_valid_nsec);
117 }
118
119 entry->d_op = &fuse_dentry_operations;
120 *inodep = inode;
121 return 0;
122}
123
124void fuse_invalidate_attr(struct inode *inode)
125{
126 get_fuse_inode(inode)->i_time = jiffies - 1;
127}
128
129static void fuse_invalidate_entry(struct dentry *entry)
130{
131 d_invalidate(entry);
132 entry->d_time = jiffies - 1;
133}
134
135static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req,
136 struct inode *dir, struct dentry *entry,
137 int mode)
138{
139 struct fuse_entry_out outarg;
140 struct inode *inode;
141 struct fuse_inode *fi;
142 int err;
143
144 req->in.h.nodeid = get_node_id(dir);
145 req->inode = dir;
146 req->out.numargs = 1;
147 req->out.args[0].size = sizeof(outarg);
148 req->out.args[0].value = &outarg;
149 request_send(fc, req);
150 err = req->out.h.error;
151 if (err) {
152 fuse_put_request(fc, req);
153 return err;
154 }
155 inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
156 &outarg.attr);
157 if (!inode) {
158 fuse_send_forget(fc, req, outarg.nodeid, 1);
159 return -ENOMEM;
160 }
161 fuse_put_request(fc, req);
162
163 /* Don't allow userspace to do really stupid things... */
164 if ((inode->i_mode ^ mode) & S_IFMT) {
165 iput(inode);
166 return -EIO;
167 }
168
169 entry->d_time = time_to_jiffies(outarg.entry_valid,
170 outarg.entry_valid_nsec);
171
172 fi = get_fuse_inode(inode);
173 fi->i_time = time_to_jiffies(outarg.attr_valid,
174 outarg.attr_valid_nsec);
175
176 d_instantiate(entry, inode);
177 fuse_invalidate_attr(dir);
178 return 0;
179}
180
181static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
182 dev_t rdev)
183{
184 struct fuse_mknod_in inarg;
185 struct fuse_conn *fc = get_fuse_conn(dir);
186 struct fuse_req *req = fuse_get_request(fc);
187 if (!req)
188 return -EINTR;
189
190 memset(&inarg, 0, sizeof(inarg));
191 inarg.mode = mode;
192 inarg.rdev = new_encode_dev(rdev);
193 req->in.h.opcode = FUSE_MKNOD;
194 req->in.numargs = 2;
195 req->in.args[0].size = sizeof(inarg);
196 req->in.args[0].value = &inarg;
197 req->in.args[1].size = entry->d_name.len + 1;
198 req->in.args[1].value = entry->d_name.name;
199 return create_new_entry(fc, req, dir, entry, mode);
200}
201
202static int fuse_create(struct inode *dir, struct dentry *entry, int mode,
203 struct nameidata *nd)
204{
205 return fuse_mknod(dir, entry, mode, 0);
206}
207
208static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
209{
210 struct fuse_mkdir_in inarg;
211 struct fuse_conn *fc = get_fuse_conn(dir);
212 struct fuse_req *req = fuse_get_request(fc);
213 if (!req)
214 return -EINTR;
215
216 memset(&inarg, 0, sizeof(inarg));
217 inarg.mode = mode;
218 req->in.h.opcode = FUSE_MKDIR;
219 req->in.numargs = 2;
220 req->in.args[0].size = sizeof(inarg);
221 req->in.args[0].value = &inarg;
222 req->in.args[1].size = entry->d_name.len + 1;
223 req->in.args[1].value = entry->d_name.name;
224 return create_new_entry(fc, req, dir, entry, S_IFDIR);
225}
226
227static int fuse_symlink(struct inode *dir, struct dentry *entry,
228 const char *link)
229{
230 struct fuse_conn *fc = get_fuse_conn(dir);
231 unsigned len = strlen(link) + 1;
232 struct fuse_req *req;
233
234 if (len > FUSE_SYMLINK_MAX)
235 return -ENAMETOOLONG;
236
237 req = fuse_get_request(fc);
238 if (!req)
239 return -EINTR;
240
241 req->in.h.opcode = FUSE_SYMLINK;
242 req->in.numargs = 2;
243 req->in.args[0].size = entry->d_name.len + 1;
244 req->in.args[0].value = entry->d_name.name;
245 req->in.args[1].size = len;
246 req->in.args[1].value = link;
247 return create_new_entry(fc, req, dir, entry, S_IFLNK);
248}
249
250static int fuse_unlink(struct inode *dir, struct dentry *entry)
251{
252 int err;
253 struct fuse_conn *fc = get_fuse_conn(dir);
254 struct fuse_req *req = fuse_get_request(fc);
255 if (!req)
256 return -EINTR;
257
258 req->in.h.opcode = FUSE_UNLINK;
259 req->in.h.nodeid = get_node_id(dir);
260 req->inode = dir;
261 req->in.numargs = 1;
262 req->in.args[0].size = entry->d_name.len + 1;
263 req->in.args[0].value = entry->d_name.name;
264 request_send(fc, req);
265 err = req->out.h.error;
266 fuse_put_request(fc, req);
267 if (!err) {
268 struct inode *inode = entry->d_inode;
269
270 /* Set nlink to zero so the inode can be cleared, if
271 the inode does have more links this will be
272 discovered at the next lookup/getattr */
273 inode->i_nlink = 0;
274 fuse_invalidate_attr(inode);
275 fuse_invalidate_attr(dir);
276 } else if (err == -EINTR)
277 fuse_invalidate_entry(entry);
278 return err;
279}
280
281static int fuse_rmdir(struct inode *dir, struct dentry *entry)
282{
283 int err;
284 struct fuse_conn *fc = get_fuse_conn(dir);
285 struct fuse_req *req = fuse_get_request(fc);
286 if (!req)
287 return -EINTR;
288
289 req->in.h.opcode = FUSE_RMDIR;
290 req->in.h.nodeid = get_node_id(dir);
291 req->inode = dir;
292 req->in.numargs = 1;
293 req->in.args[0].size = entry->d_name.len + 1;
294 req->in.args[0].value = entry->d_name.name;
295 request_send(fc, req);
296 err = req->out.h.error;
297 fuse_put_request(fc, req);
298 if (!err) {
299 entry->d_inode->i_nlink = 0;
300 fuse_invalidate_attr(dir);
301 } else if (err == -EINTR)
302 fuse_invalidate_entry(entry);
303 return err;
304}
305
306static int fuse_rename(struct inode *olddir, struct dentry *oldent,
307 struct inode *newdir, struct dentry *newent)
308{
309 int err;
310 struct fuse_rename_in inarg;
311 struct fuse_conn *fc = get_fuse_conn(olddir);
312 struct fuse_req *req = fuse_get_request(fc);
313 if (!req)
314 return -EINTR;
315
316 memset(&inarg, 0, sizeof(inarg));
317 inarg.newdir = get_node_id(newdir);
318 req->in.h.opcode = FUSE_RENAME;
319 req->in.h.nodeid = get_node_id(olddir);
320 req->inode = olddir;
321 req->inode2 = newdir;
322 req->in.numargs = 3;
323 req->in.args[0].size = sizeof(inarg);
324 req->in.args[0].value = &inarg;
325 req->in.args[1].size = oldent->d_name.len + 1;
326 req->in.args[1].value = oldent->d_name.name;
327 req->in.args[2].size = newent->d_name.len + 1;
328 req->in.args[2].value = newent->d_name.name;
329 request_send(fc, req);
330 err = req->out.h.error;
331 fuse_put_request(fc, req);
332 if (!err) {
333 fuse_invalidate_attr(olddir);
334 if (olddir != newdir)
335 fuse_invalidate_attr(newdir);
336 } else if (err == -EINTR) {
337 /* If request was interrupted, DEITY only knows if the
338 rename actually took place. If the invalidation
339 fails (e.g. some process has CWD under the renamed
340 directory), then there can be inconsistency between
341 the dcache and the real filesystem. Tough luck. */
342 fuse_invalidate_entry(oldent);
343 if (newent->d_inode)
344 fuse_invalidate_entry(newent);
345 }
346
347 return err;
348}
349
350static int fuse_link(struct dentry *entry, struct inode *newdir,
351 struct dentry *newent)
352{
353 int err;
354 struct fuse_link_in inarg;
355 struct inode *inode = entry->d_inode;
356 struct fuse_conn *fc = get_fuse_conn(inode);
357 struct fuse_req *req = fuse_get_request(fc);
358 if (!req)
359 return -EINTR;
360
361 memset(&inarg, 0, sizeof(inarg));
362 inarg.oldnodeid = get_node_id(inode);
363 req->in.h.opcode = FUSE_LINK;
364 req->inode2 = inode;
365 req->in.numargs = 2;
366 req->in.args[0].size = sizeof(inarg);
367 req->in.args[0].value = &inarg;
368 req->in.args[1].size = newent->d_name.len + 1;
369 req->in.args[1].value = newent->d_name.name;
370 err = create_new_entry(fc, req, newdir, newent, inode->i_mode);
371 /* Contrary to "normal" filesystems it can happen that link
372 makes two "logical" inodes point to the same "physical"
373 inode. We invalidate the attributes of the old one, so it
374 will reflect changes in the backing inode (link count,
375 etc.)
376 */
377 if (!err || err == -EINTR)
378 fuse_invalidate_attr(inode);
379 return err;
380}
381
382int fuse_do_getattr(struct inode *inode)
383{
384 int err;
385 struct fuse_attr_out arg;
386 struct fuse_conn *fc = get_fuse_conn(inode);
387 struct fuse_req *req = fuse_get_request(fc);
388 if (!req)
389 return -EINTR;
390
391 req->in.h.opcode = FUSE_GETATTR;
392 req->in.h.nodeid = get_node_id(inode);
393 req->inode = inode;
394 req->out.numargs = 1;
395 req->out.args[0].size = sizeof(arg);
396 req->out.args[0].value = &arg;
397 request_send(fc, req);
398 err = req->out.h.error;
399 fuse_put_request(fc, req);
400 if (!err) {
401 if ((inode->i_mode ^ arg.attr.mode) & S_IFMT) {
402 make_bad_inode(inode);
403 err = -EIO;
404 } else {
405 struct fuse_inode *fi = get_fuse_inode(inode);
406 fuse_change_attributes(inode, &arg.attr);
407 fi->i_time = time_to_jiffies(arg.attr_valid,
408 arg.attr_valid_nsec);
409 }
410 }
411 return err;
412}
413
414/*
415 * Calling into a user-controlled filesystem gives the filesystem
416 * daemon ptrace-like capabilities over the requester process. This
417 * means, that the filesystem daemon is able to record the exact
418 * filesystem operations performed, and can also control the behavior
419 * of the requester process in otherwise impossible ways. For example
420 * it can delay the operation for arbitrary length of time allowing
421 * DoS against the requester.
422 *
423 * For this reason only those processes can call into the filesystem,
424 * for which the owner of the mount has ptrace privilege. This
425 * excludes processes started by other users, suid or sgid processes.
426 */
427static int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task)
428{
429 if (fc->flags & FUSE_ALLOW_OTHER)
430 return 1;
431
432 if (task->euid == fc->user_id &&
433 task->suid == fc->user_id &&
434 task->uid == fc->user_id &&
435 task->egid == fc->group_id &&
436 task->sgid == fc->group_id &&
437 task->gid == fc->group_id)
438 return 1;
439
440 return 0;
441}
442
443static int fuse_revalidate(struct dentry *entry)
444{
445 struct inode *inode = entry->d_inode;
446 struct fuse_inode *fi = get_fuse_inode(inode);
447 struct fuse_conn *fc = get_fuse_conn(inode);
448
449 if (!fuse_allow_task(fc, current))
450 return -EACCES;
451 if (get_node_id(inode) != FUSE_ROOT_ID &&
452 time_before_eq(jiffies, fi->i_time))
453 return 0;
454
455 return fuse_do_getattr(inode);
456}
457
458static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
459{
460 struct fuse_conn *fc = get_fuse_conn(inode);
461
462 if (!fuse_allow_task(fc, current))
463 return -EACCES;
464 else if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
465 int err = generic_permission(inode, mask, NULL);
466
467 /* If permission is denied, try to refresh file
468 attributes. This is also needed, because the root
469 node will at first have no permissions */
470 if (err == -EACCES) {
471 err = fuse_do_getattr(inode);
472 if (!err)
473 err = generic_permission(inode, mask, NULL);
474 }
475
476 /* FIXME: Need some mechanism to revoke permissions:
477 currently if the filesystem suddenly changes the
478 file mode, we will not be informed about it, and
479 continue to allow access to the file/directory.
480
481 This is actually not so grave, since the user can
482 simply keep access to the file/directory anyway by
483 keeping it open... */
484
485 return err;
486 } else {
487 int mode = inode->i_mode;
488 if ((mask & MAY_WRITE) && IS_RDONLY(inode) &&
489 (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
490 return -EROFS;
491 if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO))
492 return -EACCES;
493 return 0;
494 }
495}
496
497static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
498 void *dstbuf, filldir_t filldir)
499{
500 while (nbytes >= FUSE_NAME_OFFSET) {
501 struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
502 size_t reclen = FUSE_DIRENT_SIZE(dirent);
503 int over;
504 if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX)
505 return -EIO;
506 if (reclen > nbytes)
507 break;
508
509 over = filldir(dstbuf, dirent->name, dirent->namelen,
510 file->f_pos, dirent->ino, dirent->type);
511 if (over)
512 break;
513
514 buf += reclen;
515 nbytes -= reclen;
516 file->f_pos = dirent->off;
517 }
518
519 return 0;
520}
521
522static inline size_t fuse_send_readdir(struct fuse_req *req, struct file *file,
523 struct inode *inode, loff_t pos,
524 size_t count)
525{
526 return fuse_send_read_common(req, file, inode, pos, count, 1);
527}
528
529static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
530{
531 int err;
532 size_t nbytes;
533 struct page *page;
534 struct inode *inode = file->f_dentry->d_inode;
535 struct fuse_conn *fc = get_fuse_conn(inode);
536 struct fuse_req *req = fuse_get_request(fc);
537 if (!req)
538 return -EINTR;
539
540 page = alloc_page(GFP_KERNEL);
541 if (!page) {
542 fuse_put_request(fc, req);
543 return -ENOMEM;
544 }
545 req->num_pages = 1;
546 req->pages[0] = page;
547 nbytes = fuse_send_readdir(req, file, inode, file->f_pos, PAGE_SIZE);
548 err = req->out.h.error;
549 fuse_put_request(fc, req);
550 if (!err)
551 err = parse_dirfile(page_address(page), nbytes, file, dstbuf,
552 filldir);
553
554 __free_page(page);
555 fuse_invalidate_attr(inode); /* atime changed */
556 return err;
557}
558
559static char *read_link(struct dentry *dentry)
560{
561 struct inode *inode = dentry->d_inode;
562 struct fuse_conn *fc = get_fuse_conn(inode);
563 struct fuse_req *req = fuse_get_request(fc);
564 char *link;
565
566 if (!req)
567 return ERR_PTR(-EINTR);
568
569 link = (char *) __get_free_page(GFP_KERNEL);
570 if (!link) {
571 link = ERR_PTR(-ENOMEM);
572 goto out;
573 }
574 req->in.h.opcode = FUSE_READLINK;
575 req->in.h.nodeid = get_node_id(inode);
576 req->inode = inode;
577 req->out.argvar = 1;
578 req->out.numargs = 1;
579 req->out.args[0].size = PAGE_SIZE - 1;
580 req->out.args[0].value = link;
581 request_send(fc, req);
582 if (req->out.h.error) {
583 free_page((unsigned long) link);
584 link = ERR_PTR(req->out.h.error);
585 } else
586 link[req->out.args[0].size] = '\0';
587 out:
588 fuse_put_request(fc, req);
589 fuse_invalidate_attr(inode); /* atime changed */
590 return link;
591}
592
593static void free_link(char *link)
594{
595 if (!IS_ERR(link))
596 free_page((unsigned long) link);
597}
598
599static void *fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
600{
601 nd_set_link(nd, read_link(dentry));
602 return NULL;
603}
604
605static void fuse_put_link(struct dentry *dentry, struct nameidata *nd, void *c)
606{
607 free_link(nd_get_link(nd));
608}
609
610static int fuse_dir_open(struct inode *inode, struct file *file)
611{
612 return fuse_open_common(inode, file, 1);
613}
614
615static int fuse_dir_release(struct inode *inode, struct file *file)
616{
617 return fuse_release_common(inode, file, 1);
618}
619
620static int fuse_dir_fsync(struct file *file, struct dentry *de, int datasync)
621{
622 /* nfsd can call this with no file */
623 return file ? fuse_fsync_common(file, de, datasync, 1) : 0;
624}
625
626static unsigned iattr_to_fattr(struct iattr *iattr, struct fuse_attr *fattr)
627{
628 unsigned ivalid = iattr->ia_valid;
629 unsigned fvalid = 0;
630
631 memset(fattr, 0, sizeof(*fattr));
632
633 if (ivalid & ATTR_MODE)
634 fvalid |= FATTR_MODE, fattr->mode = iattr->ia_mode;
635 if (ivalid & ATTR_UID)
636 fvalid |= FATTR_UID, fattr->uid = iattr->ia_uid;
637 if (ivalid & ATTR_GID)
638 fvalid |= FATTR_GID, fattr->gid = iattr->ia_gid;
639 if (ivalid & ATTR_SIZE)
640 fvalid |= FATTR_SIZE, fattr->size = iattr->ia_size;
641 /* You can only _set_ these together (they may change by themselves) */
642 if ((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) {
643 fvalid |= FATTR_ATIME | FATTR_MTIME;
644 fattr->atime = iattr->ia_atime.tv_sec;
645 fattr->mtime = iattr->ia_mtime.tv_sec;
646 }
647
648 return fvalid;
649}
650
651static int fuse_setattr(struct dentry *entry, struct iattr *attr)
652{
653 struct inode *inode = entry->d_inode;
654 struct fuse_conn *fc = get_fuse_conn(inode);
655 struct fuse_inode *fi = get_fuse_inode(inode);
656 struct fuse_req *req;
657 struct fuse_setattr_in inarg;
658 struct fuse_attr_out outarg;
659 int err;
660 int is_truncate = 0;
661
662 if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
663 err = inode_change_ok(inode, attr);
664 if (err)
665 return err;
666 }
667
668 if (attr->ia_valid & ATTR_SIZE) {
669 unsigned long limit;
670 is_truncate = 1;
671 limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
672 if (limit != RLIM_INFINITY && attr->ia_size > (loff_t) limit) {
673 send_sig(SIGXFSZ, current, 0);
674 return -EFBIG;
675 }
676 }
677
678 req = fuse_get_request(fc);
679 if (!req)
680 return -EINTR;
681
682 memset(&inarg, 0, sizeof(inarg));
683 inarg.valid = iattr_to_fattr(attr, &inarg.attr);
684 req->in.h.opcode = FUSE_SETATTR;
685 req->in.h.nodeid = get_node_id(inode);
686 req->inode = inode;
687 req->in.numargs = 1;
688 req->in.args[0].size = sizeof(inarg);
689 req->in.args[0].value = &inarg;
690 req->out.numargs = 1;
691 req->out.args[0].size = sizeof(outarg);
692 req->out.args[0].value = &outarg;
693 request_send(fc, req);
694 err = req->out.h.error;
695 fuse_put_request(fc, req);
696 if (!err) {
697 if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
698 make_bad_inode(inode);
699 err = -EIO;
700 } else {
701 if (is_truncate) {
702 loff_t origsize = i_size_read(inode);
703 i_size_write(inode, outarg.attr.size);
704 if (origsize > outarg.attr.size)
705 vmtruncate(inode, outarg.attr.size);
706 }
707 fuse_change_attributes(inode, &outarg.attr);
708 fi->i_time = time_to_jiffies(outarg.attr_valid,
709 outarg.attr_valid_nsec);
710 }
711 } else if (err == -EINTR)
712 fuse_invalidate_attr(inode);
713
714 return err;
715}
716
717static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
718 struct kstat *stat)
719{
720 struct inode *inode = entry->d_inode;
721 int err = fuse_revalidate(entry);
722 if (!err)
723 generic_fillattr(inode, stat);
724
725 return err;
726}
727
728static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
729 struct nameidata *nd)
730{
731 struct inode *inode;
732 int err = fuse_lookup_iget(dir, entry, &inode);
733 if (err)
734 return ERR_PTR(err);
735 if (inode && S_ISDIR(inode->i_mode)) {
736 /* Don't allow creating an alias to a directory */
737 struct dentry *alias = d_find_alias(inode);
738 if (alias && !(alias->d_flags & DCACHE_DISCONNECTED)) {
739 dput(alias);
740 iput(inode);
741 return ERR_PTR(-EIO);
742 }
743 }
744 return d_splice_alias(inode, entry);
745}
746
747static int fuse_setxattr(struct dentry *entry, const char *name,
748 const void *value, size_t size, int flags)
749{
750 struct inode *inode = entry->d_inode;
751 struct fuse_conn *fc = get_fuse_conn(inode);
752 struct fuse_req *req;
753 struct fuse_setxattr_in inarg;
754 int err;
755
756 if (size > FUSE_XATTR_SIZE_MAX)
757 return -E2BIG;
758
759 if (fc->no_setxattr)
760 return -EOPNOTSUPP;
761
762 req = fuse_get_request(fc);
763 if (!req)
764 return -EINTR;
765
766 memset(&inarg, 0, sizeof(inarg));
767 inarg.size = size;
768 inarg.flags = flags;
769 req->in.h.opcode = FUSE_SETXATTR;
770 req->in.h.nodeid = get_node_id(inode);
771 req->inode = inode;
772 req->in.numargs = 3;
773 req->in.args[0].size = sizeof(inarg);
774 req->in.args[0].value = &inarg;
775 req->in.args[1].size = strlen(name) + 1;
776 req->in.args[1].value = name;
777 req->in.args[2].size = size;
778 req->in.args[2].value = value;
779 request_send(fc, req);
780 err = req->out.h.error;
781 fuse_put_request(fc, req);
782 if (err == -ENOSYS) {
783 fc->no_setxattr = 1;
784 err = -EOPNOTSUPP;
785 }
786 return err;
787}
788
789static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
790 void *value, size_t size)
791{
792 struct inode *inode = entry->d_inode;
793 struct fuse_conn *fc = get_fuse_conn(inode);
794 struct fuse_req *req;
795 struct fuse_getxattr_in inarg;
796 struct fuse_getxattr_out outarg;
797 ssize_t ret;
798
799 if (fc->no_getxattr)
800 return -EOPNOTSUPP;
801
802 req = fuse_get_request(fc);
803 if (!req)
804 return -EINTR;
805
806 memset(&inarg, 0, sizeof(inarg));
807 inarg.size = size;
808 req->in.h.opcode = FUSE_GETXATTR;
809 req->in.h.nodeid = get_node_id(inode);
810 req->inode = inode;
811 req->in.numargs = 2;
812 req->in.args[0].size = sizeof(inarg);
813 req->in.args[0].value = &inarg;
814 req->in.args[1].size = strlen(name) + 1;
815 req->in.args[1].value = name;
816 /* This is really two different operations rolled into one */
817 req->out.numargs = 1;
818 if (size) {
819 req->out.argvar = 1;
820 req->out.args[0].size = size;
821 req->out.args[0].value = value;
822 } else {
823 req->out.args[0].size = sizeof(outarg);
824 req->out.args[0].value = &outarg;
825 }
826 request_send(fc, req);
827 ret = req->out.h.error;
828 if (!ret)
829 ret = size ? req->out.args[0].size : outarg.size;
830 else {
831 if (ret == -ENOSYS) {
832 fc->no_getxattr = 1;
833 ret = -EOPNOTSUPP;
834 }
835 }
836 fuse_put_request(fc, req);
837 return ret;
838}
839
840static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
841{
842 struct inode *inode = entry->d_inode;
843 struct fuse_conn *fc = get_fuse_conn(inode);
844 struct fuse_req *req;
845 struct fuse_getxattr_in inarg;
846 struct fuse_getxattr_out outarg;
847 ssize_t ret;
848
849 if (fc->no_listxattr)
850 return -EOPNOTSUPP;
851
852 req = fuse_get_request(fc);
853 if (!req)
854 return -EINTR;
855
856 memset(&inarg, 0, sizeof(inarg));
857 inarg.size = size;
858 req->in.h.opcode = FUSE_LISTXATTR;
859 req->in.h.nodeid = get_node_id(inode);
860 req->inode = inode;
861 req->in.numargs = 1;
862 req->in.args[0].size = sizeof(inarg);
863 req->in.args[0].value = &inarg;
864 /* This is really two different operations rolled into one */
865 req->out.numargs = 1;
866 if (size) {
867 req->out.argvar = 1;
868 req->out.args[0].size = size;
869 req->out.args[0].value = list;
870 } else {
871 req->out.args[0].size = sizeof(outarg);
872 req->out.args[0].value = &outarg;
873 }
874 request_send(fc, req);
875 ret = req->out.h.error;
876 if (!ret)
877 ret = size ? req->out.args[0].size : outarg.size;
878 else {
879 if (ret == -ENOSYS) {
880 fc->no_listxattr = 1;
881 ret = -EOPNOTSUPP;
882 }
883 }
884 fuse_put_request(fc, req);
885 return ret;
886}
887
888static int fuse_removexattr(struct dentry *entry, const char *name)
889{
890 struct inode *inode = entry->d_inode;
891 struct fuse_conn *fc = get_fuse_conn(inode);
892 struct fuse_req *req;
893 int err;
894
895 if (fc->no_removexattr)
896 return -EOPNOTSUPP;
897
898 req = fuse_get_request(fc);
899 if (!req)
900 return -EINTR;
901
902 req->in.h.opcode = FUSE_REMOVEXATTR;
903 req->in.h.nodeid = get_node_id(inode);
904 req->inode = inode;
905 req->in.numargs = 1;
906 req->in.args[0].size = strlen(name) + 1;
907 req->in.args[0].value = name;
908 request_send(fc, req);
909 err = req->out.h.error;
910 fuse_put_request(fc, req);
911 if (err == -ENOSYS) {
912 fc->no_removexattr = 1;
913 err = -EOPNOTSUPP;
914 }
915 return err;
916}
917
918static struct inode_operations fuse_dir_inode_operations = {
919 .lookup = fuse_lookup,
920 .mkdir = fuse_mkdir,
921 .symlink = fuse_symlink,
922 .unlink = fuse_unlink,
923 .rmdir = fuse_rmdir,
924 .rename = fuse_rename,
925 .link = fuse_link,
926 .setattr = fuse_setattr,
927 .create = fuse_create,
928 .mknod = fuse_mknod,
929 .permission = fuse_permission,
930 .getattr = fuse_getattr,
931 .setxattr = fuse_setxattr,
932 .getxattr = fuse_getxattr,
933 .listxattr = fuse_listxattr,
934 .removexattr = fuse_removexattr,
935};
936
937static struct file_operations fuse_dir_operations = {
938 .llseek = generic_file_llseek,
939 .read = generic_read_dir,
940 .readdir = fuse_readdir,
941 .open = fuse_dir_open,
942 .release = fuse_dir_release,
943 .fsync = fuse_dir_fsync,
944};
945
946static struct inode_operations fuse_common_inode_operations = {
947 .setattr = fuse_setattr,
948 .permission = fuse_permission,
949 .getattr = fuse_getattr,
950 .setxattr = fuse_setxattr,
951 .getxattr = fuse_getxattr,
952 .listxattr = fuse_listxattr,
953 .removexattr = fuse_removexattr,
954};
955
956static struct inode_operations fuse_symlink_inode_operations = {
957 .setattr = fuse_setattr,
958 .follow_link = fuse_follow_link,
959 .put_link = fuse_put_link,
960 .readlink = generic_readlink,
961 .getattr = fuse_getattr,
962 .setxattr = fuse_setxattr,
963 .getxattr = fuse_getxattr,
964 .listxattr = fuse_listxattr,
965 .removexattr = fuse_removexattr,
966};
967
968void fuse_init_common(struct inode *inode)
969{
970 inode->i_op = &fuse_common_inode_operations;
971}
972
973void fuse_init_dir(struct inode *inode)
974{
975 inode->i_op = &fuse_dir_inode_operations;
976 inode->i_fop = &fuse_dir_operations;
977}
978
979void fuse_init_symlink(struct inode *inode)
980{
981 inode->i_op = &fuse_symlink_inode_operations;
982}
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
new file mode 100644
index 0000000000..6454022b05
--- /dev/null
+++ b/fs/fuse/file.c
@@ -0,0 +1,555 @@
1/*
2 FUSE: Filesystem in Userspace
3 Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.hu>
4
5 This program can be distributed under the terms of the GNU GPL.
6 See the file COPYING.
7*/
8
9#include "fuse_i.h"
10
11#include <linux/pagemap.h>
12#include <linux/slab.h>
13#include <linux/kernel.h>
14
15static struct file_operations fuse_direct_io_file_operations;
16
17int fuse_open_common(struct inode *inode, struct file *file, int isdir)
18{
19 struct fuse_conn *fc = get_fuse_conn(inode);
20 struct fuse_req *req;
21 struct fuse_open_in inarg;
22 struct fuse_open_out outarg;
23 struct fuse_file *ff;
24 int err;
25
26 err = generic_file_open(inode, file);
27 if (err)
28 return err;
29
30 /* If opening the root node, no lookup has been performed on
31 it, so the attributes must be refreshed */
32 if (get_node_id(inode) == FUSE_ROOT_ID) {
33 int err = fuse_do_getattr(inode);
34 if (err)
35 return err;
36 }
37
38 req = fuse_get_request(fc);
39 if (!req)
40 return -EINTR;
41
42 err = -ENOMEM;
43 ff = kmalloc(sizeof(struct fuse_file), GFP_KERNEL);
44 if (!ff)
45 goto out_put_request;
46
47 ff->release_req = fuse_request_alloc();
48 if (!ff->release_req) {
49 kfree(ff);
50 goto out_put_request;
51 }
52
53 memset(&inarg, 0, sizeof(inarg));
54 inarg.flags = file->f_flags & ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
55 req->in.h.opcode = isdir ? FUSE_OPENDIR : FUSE_OPEN;
56 req->in.h.nodeid = get_node_id(inode);
57 req->inode = inode;
58 req->in.numargs = 1;
59 req->in.args[0].size = sizeof(inarg);
60 req->in.args[0].value = &inarg;
61 req->out.numargs = 1;
62 req->out.args[0].size = sizeof(outarg);
63 req->out.args[0].value = &outarg;
64 request_send(fc, req);
65 err = req->out.h.error;
66 if (err) {
67 fuse_request_free(ff->release_req);
68 kfree(ff);
69 } else {
70 if (!isdir && (outarg.open_flags & FOPEN_DIRECT_IO))
71 file->f_op = &fuse_direct_io_file_operations;
72 if (!(outarg.open_flags & FOPEN_KEEP_CACHE))
73 invalidate_inode_pages(inode->i_mapping);
74 ff->fh = outarg.fh;
75 file->private_data = ff;
76 }
77
78 out_put_request:
79 fuse_put_request(fc, req);
80 return err;
81}
82
83int fuse_release_common(struct inode *inode, struct file *file, int isdir)
84{
85 struct fuse_conn *fc = get_fuse_conn(inode);
86 struct fuse_file *ff = file->private_data;
87 struct fuse_req *req = ff->release_req;
88 struct fuse_release_in *inarg = &req->misc.release_in;
89
90 inarg->fh = ff->fh;
91 inarg->flags = file->f_flags & ~O_EXCL;
92 req->in.h.opcode = isdir ? FUSE_RELEASEDIR : FUSE_RELEASE;
93 req->in.h.nodeid = get_node_id(inode);
94 req->inode = inode;
95 req->in.numargs = 1;
96 req->in.args[0].size = sizeof(struct fuse_release_in);
97 req->in.args[0].value = inarg;
98 request_send_background(fc, req);
99 kfree(ff);
100
101 /* Return value is ignored by VFS */
102 return 0;
103}
104
105static int fuse_open(struct inode *inode, struct file *file)
106{
107 return fuse_open_common(inode, file, 0);
108}
109
110static int fuse_release(struct inode *inode, struct file *file)
111{
112 return fuse_release_common(inode, file, 0);
113}
114
115static int fuse_flush(struct file *file)
116{
117 struct inode *inode = file->f_dentry->d_inode;
118 struct fuse_conn *fc = get_fuse_conn(inode);
119 struct fuse_file *ff = file->private_data;
120 struct fuse_req *req;
121 struct fuse_flush_in inarg;
122 int err;
123
124 if (fc->no_flush)
125 return 0;
126
127 req = fuse_get_request(fc);
128 if (!req)
129 return -EINTR;
130
131 memset(&inarg, 0, sizeof(inarg));
132 inarg.fh = ff->fh;
133 req->in.h.opcode = FUSE_FLUSH;
134 req->in.h.nodeid = get_node_id(inode);
135 req->inode = inode;
136 req->file = file;
137 req->in.numargs = 1;
138 req->in.args[0].size = sizeof(inarg);
139 req->in.args[0].value = &inarg;
140 request_send(fc, req);
141 err = req->out.h.error;
142 fuse_put_request(fc, req);
143 if (err == -ENOSYS) {
144 fc->no_flush = 1;
145 err = 0;
146 }
147 return err;
148}
149
150int fuse_fsync_common(struct file *file, struct dentry *de, int datasync,
151 int isdir)
152{
153 struct inode *inode = de->d_inode;
154 struct fuse_conn *fc = get_fuse_conn(inode);
155 struct fuse_file *ff = file->private_data;
156 struct fuse_req *req;
157 struct fuse_fsync_in inarg;
158 int err;
159
160 if ((!isdir && fc->no_fsync) || (isdir && fc->no_fsyncdir))
161 return 0;
162
163 req = fuse_get_request(fc);
164 if (!req)
165 return -EINTR;
166
167 memset(&inarg, 0, sizeof(inarg));
168 inarg.fh = ff->fh;
169 inarg.fsync_flags = datasync ? 1 : 0;
170 req->in.h.opcode = isdir ? FUSE_FSYNCDIR : FUSE_FSYNC;
171 req->in.h.nodeid = get_node_id(inode);
172 req->inode = inode;
173 req->file = file;
174 req->in.numargs = 1;
175 req->in.args[0].size = sizeof(inarg);
176 req->in.args[0].value = &inarg;
177 request_send(fc, req);
178 err = req->out.h.error;
179 fuse_put_request(fc, req);
180 if (err == -ENOSYS) {
181 if (isdir)
182 fc->no_fsyncdir = 1;
183 else
184 fc->no_fsync = 1;
185 err = 0;
186 }
187 return err;
188}
189
190static int fuse_fsync(struct file *file, struct dentry *de, int datasync)
191{
192 return fuse_fsync_common(file, de, datasync, 0);
193}
194
195size_t fuse_send_read_common(struct fuse_req *req, struct file *file,
196 struct inode *inode, loff_t pos, size_t count,
197 int isdir)
198{
199 struct fuse_conn *fc = get_fuse_conn(inode);
200 struct fuse_file *ff = file->private_data;
201 struct fuse_read_in inarg;
202
203 memset(&inarg, 0, sizeof(struct fuse_read_in));
204 inarg.fh = ff->fh;
205 inarg.offset = pos;
206 inarg.size = count;
207 req->in.h.opcode = isdir ? FUSE_READDIR : FUSE_READ;
208 req->in.h.nodeid = get_node_id(inode);
209 req->inode = inode;
210 req->file = file;
211 req->in.numargs = 1;
212 req->in.args[0].size = sizeof(struct fuse_read_in);
213 req->in.args[0].value = &inarg;
214 req->out.argpages = 1;
215 req->out.argvar = 1;
216 req->out.numargs = 1;
217 req->out.args[0].size = count;
218 request_send(fc, req);
219 return req->out.args[0].size;
220}
221
222static inline size_t fuse_send_read(struct fuse_req *req, struct file *file,
223 struct inode *inode, loff_t pos,
224 size_t count)
225{
226 return fuse_send_read_common(req, file, inode, pos, count, 0);
227}
228
229static int fuse_readpage(struct file *file, struct page *page)
230{
231 struct inode *inode = page->mapping->host;
232 struct fuse_conn *fc = get_fuse_conn(inode);
233 loff_t pos = (loff_t) page->index << PAGE_CACHE_SHIFT;
234 struct fuse_req *req = fuse_get_request(fc);
235 int err = -EINTR;
236 if (!req)
237 goto out;
238
239 req->out.page_zeroing = 1;
240 req->num_pages = 1;
241 req->pages[0] = page;
242 fuse_send_read(req, file, inode, pos, PAGE_CACHE_SIZE);
243 err = req->out.h.error;
244 fuse_put_request(fc, req);
245 if (!err)
246 SetPageUptodate(page);
247 fuse_invalidate_attr(inode); /* atime changed */
248 out:
249 unlock_page(page);
250 return err;
251}
252
253static int fuse_send_readpages(struct fuse_req *req, struct file *file,
254 struct inode *inode)
255{
256 loff_t pos = (loff_t) req->pages[0]->index << PAGE_CACHE_SHIFT;
257 size_t count = req->num_pages << PAGE_CACHE_SHIFT;
258 unsigned i;
259 req->out.page_zeroing = 1;
260 fuse_send_read(req, file, inode, pos, count);
261 for (i = 0; i < req->num_pages; i++) {
262 struct page *page = req->pages[i];
263 if (!req->out.h.error)
264 SetPageUptodate(page);
265 unlock_page(page);
266 }
267 return req->out.h.error;
268}
269
270struct fuse_readpages_data {
271 struct fuse_req *req;
272 struct file *file;
273 struct inode *inode;
274};
275
276static int fuse_readpages_fill(void *_data, struct page *page)
277{
278 struct fuse_readpages_data *data = _data;
279 struct fuse_req *req = data->req;
280 struct inode *inode = data->inode;
281 struct fuse_conn *fc = get_fuse_conn(inode);
282
283 if (req->num_pages &&
284 (req->num_pages == FUSE_MAX_PAGES_PER_REQ ||
285 (req->num_pages + 1) * PAGE_CACHE_SIZE > fc->max_read ||
286 req->pages[req->num_pages - 1]->index + 1 != page->index)) {
287 int err = fuse_send_readpages(req, data->file, inode);
288 if (err) {
289 unlock_page(page);
290 return err;
291 }
292 fuse_reset_request(req);
293 }
294 req->pages[req->num_pages] = page;
295 req->num_pages ++;
296 return 0;
297}
298
299static int fuse_readpages(struct file *file, struct address_space *mapping,
300 struct list_head *pages, unsigned nr_pages)
301{
302 struct inode *inode = mapping->host;
303 struct fuse_conn *fc = get_fuse_conn(inode);
304 struct fuse_readpages_data data;
305 int err;
306 data.file = file;
307 data.inode = inode;
308 data.req = fuse_get_request(fc);
309 if (!data.req)
310 return -EINTR;
311
312 err = read_cache_pages(mapping, pages, fuse_readpages_fill, &data);
313 if (!err && data.req->num_pages)
314 err = fuse_send_readpages(data.req, file, inode);
315 fuse_put_request(fc, data.req);
316 fuse_invalidate_attr(inode); /* atime changed */
317 return err;
318}
319
320static size_t fuse_send_write(struct fuse_req *req, struct file *file,
321 struct inode *inode, loff_t pos, size_t count)
322{
323 struct fuse_conn *fc = get_fuse_conn(inode);
324 struct fuse_file *ff = file->private_data;
325 struct fuse_write_in inarg;
326 struct fuse_write_out outarg;
327
328 memset(&inarg, 0, sizeof(struct fuse_write_in));
329 inarg.fh = ff->fh;
330 inarg.offset = pos;
331 inarg.size = count;
332 req->in.h.opcode = FUSE_WRITE;
333 req->in.h.nodeid = get_node_id(inode);
334 req->inode = inode;
335 req->file = file;
336 req->in.argpages = 1;
337 req->in.numargs = 2;
338 req->in.args[0].size = sizeof(struct fuse_write_in);
339 req->in.args[0].value = &inarg;
340 req->in.args[1].size = count;
341 req->out.numargs = 1;
342 req->out.args[0].size = sizeof(struct fuse_write_out);
343 req->out.args[0].value = &outarg;
344 request_send(fc, req);
345 return outarg.size;
346}
347
348static int fuse_prepare_write(struct file *file, struct page *page,
349 unsigned offset, unsigned to)
350{
351 /* No op */
352 return 0;
353}
354
355static int fuse_commit_write(struct file *file, struct page *page,
356 unsigned offset, unsigned to)
357{
358 int err;
359 size_t nres;
360 unsigned count = to - offset;
361 struct inode *inode = page->mapping->host;
362 struct fuse_conn *fc = get_fuse_conn(inode);
363 loff_t pos = ((loff_t) page->index << PAGE_CACHE_SHIFT) + offset;
364 struct fuse_req *req = fuse_get_request(fc);
365 if (!req)
366 return -EINTR;
367
368 req->num_pages = 1;
369 req->pages[0] = page;
370 req->page_offset = offset;
371 nres = fuse_send_write(req, file, inode, pos, count);
372 err = req->out.h.error;
373 fuse_put_request(fc, req);
374 if (!err && nres != count)
375 err = -EIO;
376 if (!err) {
377 pos += count;
378 if (pos > i_size_read(inode))
379 i_size_write(inode, pos);
380
381 if (offset == 0 && to == PAGE_CACHE_SIZE) {
382 clear_page_dirty(page);
383 SetPageUptodate(page);
384 }
385 }
386 fuse_invalidate_attr(inode);
387 return err;
388}
389
390static void fuse_release_user_pages(struct fuse_req *req, int write)
391{
392 unsigned i;
393
394 for (i = 0; i < req->num_pages; i++) {
395 struct page *page = req->pages[i];
396 if (write)
397 set_page_dirty_lock(page);
398 put_page(page);
399 }
400}
401
402static int fuse_get_user_pages(struct fuse_req *req, const char __user *buf,
403 unsigned nbytes, int write)
404{
405 unsigned long user_addr = (unsigned long) buf;
406 unsigned offset = user_addr & ~PAGE_MASK;
407 int npages;
408
409 /* This doesn't work with nfsd */
410 if (!current->mm)
411 return -EPERM;
412
413 nbytes = min(nbytes, (unsigned) FUSE_MAX_PAGES_PER_REQ << PAGE_SHIFT);
414 npages = (nbytes + offset + PAGE_SIZE - 1) >> PAGE_SHIFT;
415 npages = min(npages, FUSE_MAX_PAGES_PER_REQ);
416 down_read(&current->mm->mmap_sem);
417 npages = get_user_pages(current, current->mm, user_addr, npages, write,
418 0, req->pages, NULL);
419 up_read(&current->mm->mmap_sem);
420 if (npages < 0)
421 return npages;
422
423 req->num_pages = npages;
424 req->page_offset = offset;
425 return 0;
426}
427
428static ssize_t fuse_direct_io(struct file *file, const char __user *buf,
429 size_t count, loff_t *ppos, int write)
430{
431 struct inode *inode = file->f_dentry->d_inode;
432 struct fuse_conn *fc = get_fuse_conn(inode);
433 size_t nmax = write ? fc->max_write : fc->max_read;
434 loff_t pos = *ppos;
435 ssize_t res = 0;
436 struct fuse_req *req = fuse_get_request(fc);
437 if (!req)
438 return -EINTR;
439
440 while (count) {
441 size_t tmp;
442 size_t nres;
443 size_t nbytes = min(count, nmax);
444 int err = fuse_get_user_pages(req, buf, nbytes, !write);
445 if (err) {
446 res = err;
447 break;
448 }
449 tmp = (req->num_pages << PAGE_SHIFT) - req->page_offset;
450 nbytes = min(nbytes, tmp);
451 if (write)
452 nres = fuse_send_write(req, file, inode, pos, nbytes);
453 else
454 nres = fuse_send_read(req, file, inode, pos, nbytes);
455 fuse_release_user_pages(req, !write);
456 if (req->out.h.error) {
457 if (!res)
458 res = req->out.h.error;
459 break;
460 } else if (nres > nbytes) {
461 res = -EIO;
462 break;
463 }
464 count -= nres;
465 res += nres;
466 pos += nres;
467 buf += nres;
468 if (nres != nbytes)
469 break;
470 if (count)
471 fuse_reset_request(req);
472 }
473 fuse_put_request(fc, req);
474 if (res > 0) {
475 if (write && pos > i_size_read(inode))
476 i_size_write(inode, pos);
477 *ppos = pos;
478 }
479 fuse_invalidate_attr(inode);
480
481 return res;
482}
483
484static ssize_t fuse_direct_read(struct file *file, char __user *buf,
485 size_t count, loff_t *ppos)
486{
487 return fuse_direct_io(file, buf, count, ppos, 0);
488}
489
490static ssize_t fuse_direct_write(struct file *file, const char __user *buf,
491 size_t count, loff_t *ppos)
492{
493 struct inode *inode = file->f_dentry->d_inode;
494 ssize_t res;
495 /* Don't allow parallel writes to the same file */
496 down(&inode->i_sem);
497 res = fuse_direct_io(file, buf, count, ppos, 1);
498 up(&inode->i_sem);
499 return res;
500}
501
502static int fuse_file_mmap(struct file *file, struct vm_area_struct *vma)
503{
504 if ((vma->vm_flags & VM_SHARED)) {
505 if ((vma->vm_flags & VM_WRITE))
506 return -ENODEV;
507 else
508 vma->vm_flags &= ~VM_MAYWRITE;
509 }
510 return generic_file_mmap(file, vma);
511}
512
513static int fuse_set_page_dirty(struct page *page)
514{
515 printk("fuse_set_page_dirty: should not happen\n");
516 dump_stack();
517 return 0;
518}
519
520static struct file_operations fuse_file_operations = {
521 .llseek = generic_file_llseek,
522 .read = generic_file_read,
523 .write = generic_file_write,
524 .mmap = fuse_file_mmap,
525 .open = fuse_open,
526 .flush = fuse_flush,
527 .release = fuse_release,
528 .fsync = fuse_fsync,
529 .sendfile = generic_file_sendfile,
530};
531
532static struct file_operations fuse_direct_io_file_operations = {
533 .llseek = generic_file_llseek,
534 .read = fuse_direct_read,
535 .write = fuse_direct_write,
536 .open = fuse_open,
537 .flush = fuse_flush,
538 .release = fuse_release,
539 .fsync = fuse_fsync,
540 /* no mmap and sendfile */
541};
542
543static struct address_space_operations fuse_file_aops = {
544 .readpage = fuse_readpage,
545 .prepare_write = fuse_prepare_write,
546 .commit_write = fuse_commit_write,
547 .readpages = fuse_readpages,
548 .set_page_dirty = fuse_set_page_dirty,
549};
550
551void fuse_init_file_inode(struct inode *inode)
552{
553 inode->i_fop = &fuse_file_operations;
554 inode->i_data.a_ops = &fuse_file_aops;
555}
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
new file mode 100644
index 0000000000..24d761518d
--- /dev/null
+++ b/fs/fuse/fuse_i.h
@@ -0,0 +1,451 @@
1/*
2 FUSE: Filesystem in Userspace
3 Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.hu>
4
5 This program can be distributed under the terms of the GNU GPL.
6 See the file COPYING.
7*/
8
9#include <linux/fuse.h>
10#include <linux/fs.h>
11#include <linux/wait.h>
12#include <linux/list.h>
13#include <linux/spinlock.h>
14#include <linux/mm.h>
15#include <linux/backing-dev.h>
16#include <asm/semaphore.h>
17
18/** Max number of pages that can be used in a single read request */
19#define FUSE_MAX_PAGES_PER_REQ 32
20
21/** If more requests are outstanding, then the operation will block */
22#define FUSE_MAX_OUTSTANDING 10
23
24/** If the FUSE_DEFAULT_PERMISSIONS flag is given, the filesystem
25 module will check permissions based on the file mode. Otherwise no
26 permission checking is done in the kernel */
27#define FUSE_DEFAULT_PERMISSIONS (1 << 0)
28
29/** If the FUSE_ALLOW_OTHER flag is given, then not only the user
30 doing the mount will be allowed to access the filesystem */
31#define FUSE_ALLOW_OTHER (1 << 1)
32
33
34/** FUSE inode */
35struct fuse_inode {
36 /** Inode data */
37 struct inode inode;
38
39 /** Unique ID, which identifies the inode between userspace
40 * and kernel */
41 u64 nodeid;
42
43 /** Number of lookups on this inode */
44 u64 nlookup;
45
46 /** The request used for sending the FORGET message */
47 struct fuse_req *forget_req;
48
49 /** Time in jiffies until the file attributes are valid */
50 unsigned long i_time;
51};
52
53/** FUSE specific file data */
54struct fuse_file {
55 /** Request reserved for flush and release */
56 struct fuse_req *release_req;
57
58 /** File handle used by userspace */
59 u64 fh;
60};
61
62/** One input argument of a request */
63struct fuse_in_arg {
64 unsigned size;
65 const void *value;
66};
67
68/** The request input */
69struct fuse_in {
70 /** The request header */
71 struct fuse_in_header h;
72
73 /** True if the data for the last argument is in req->pages */
74 unsigned argpages:1;
75
76 /** Number of arguments */
77 unsigned numargs;
78
79 /** Array of arguments */
80 struct fuse_in_arg args[3];
81};
82
83/** One output argument of a request */
84struct fuse_arg {
85 unsigned size;
86 void *value;
87};
88
89/** The request output */
90struct fuse_out {
91 /** Header returned from userspace */
92 struct fuse_out_header h;
93
94 /** Last argument is variable length (can be shorter than
95 arg->size) */
96 unsigned argvar:1;
97
98 /** Last argument is a list of pages to copy data to */
99 unsigned argpages:1;
100
101 /** Zero partially or not copied pages */
102 unsigned page_zeroing:1;
103
104 /** Number or arguments */
105 unsigned numargs;
106
107 /** Array of arguments */
108 struct fuse_arg args[3];
109};
110
111struct fuse_req;
112struct fuse_conn;
113
114/**
115 * A request to the client
116 */
117struct fuse_req {
118 /** This can be on either unused_list, pending or processing
119 lists in fuse_conn */
120 struct list_head list;
121
122 /** Entry on the background list */
123 struct list_head bg_entry;
124
125 /** refcount */
126 atomic_t count;
127
128 /** True if the request has reply */
129 unsigned isreply:1;
130
131 /** The request is preallocated */
132 unsigned preallocated:1;
133
134 /** The request was interrupted */
135 unsigned interrupted:1;
136
137 /** Request is sent in the background */
138 unsigned background:1;
139
140 /** Data is being copied to/from the request */
141 unsigned locked:1;
142
143 /** Request has been sent to userspace */
144 unsigned sent:1;
145
146 /** The request is finished */
147 unsigned finished:1;
148
149 /** The request input */
150 struct fuse_in in;
151
152 /** The request output */
153 struct fuse_out out;
154
155 /** Used to wake up the task waiting for completion of request*/
156 wait_queue_head_t waitq;
157
158 /** Data for asynchronous requests */
159 union {
160 struct fuse_forget_in forget_in;
161 struct fuse_release_in release_in;
162 struct fuse_init_in_out init_in_out;
163 } misc;
164
165 /** page vector */
166 struct page *pages[FUSE_MAX_PAGES_PER_REQ];
167
168 /** number of pages in vector */
169 unsigned num_pages;
170
171 /** offset of data on first page */
172 unsigned page_offset;
173
174 /** Inode used in the request */
175 struct inode *inode;
176
177 /** Second inode used in the request (or NULL) */
178 struct inode *inode2;
179
180 /** File used in the request (or NULL) */
181 struct file *file;
182};
183
184/**
185 * A Fuse connection.
186 *
187 * This structure is created, when the filesystem is mounted, and is
188 * destroyed, when the client device is closed and the filesystem is
189 * unmounted.
190 */
191struct fuse_conn {
192 /** Reference count */
193 int count;
194
195 /** The user id for this mount */
196 uid_t user_id;
197
198 /** The group id for this mount */
199 gid_t group_id;
200
201 /** The fuse mount flags for this mount */
202 unsigned flags;
203
204 /** Maximum read size */
205 unsigned max_read;
206
207 /** Maximum write size */
208 unsigned max_write;
209
210 /** Readers of the connection are waiting on this */
211 wait_queue_head_t waitq;
212
213 /** The list of pending requests */
214 struct list_head pending;
215
216 /** The list of requests being processed */
217 struct list_head processing;
218
219 /** Requests put in the background (RELEASE or any other
220 interrupted request) */
221 struct list_head background;
222
223 /** Controls the maximum number of outstanding requests */
224 struct semaphore outstanding_sem;
225
226 /** This counts the number of outstanding requests if
227 outstanding_sem would go negative */
228 unsigned outstanding_debt;
229
230 /** RW semaphore for exclusion with fuse_put_super() */
231 struct rw_semaphore sbput_sem;
232
233 /** The list of unused requests */
234 struct list_head unused_list;
235
236 /** The next unique request id */
237 u64 reqctr;
238
239 /** Mount is active */
240 unsigned mounted : 1;
241
242 /** Connection established */
243 unsigned connected : 1;
244
245 /** Connection failed (version mismatch) */
246 unsigned conn_error : 1;
247
248 /** Is fsync not implemented by fs? */
249 unsigned no_fsync : 1;
250
251 /** Is fsyncdir not implemented by fs? */
252 unsigned no_fsyncdir : 1;
253
254 /** Is flush not implemented by fs? */
255 unsigned no_flush : 1;
256
257 /** Is setxattr not implemented by fs? */
258 unsigned no_setxattr : 1;
259
260 /** Is getxattr not implemented by fs? */
261 unsigned no_getxattr : 1;
262
263 /** Is listxattr not implemented by fs? */
264 unsigned no_listxattr : 1;
265
266 /** Is removexattr not implemented by fs? */
267 unsigned no_removexattr : 1;
268
269 /** Backing dev info */
270 struct backing_dev_info bdi;
271};
272
273static inline struct fuse_conn **get_fuse_conn_super_p(struct super_block *sb)
274{
275 return (struct fuse_conn **) &sb->s_fs_info;
276}
277
278static inline struct fuse_conn *get_fuse_conn_super(struct super_block *sb)
279{
280 return *get_fuse_conn_super_p(sb);
281}
282
283static inline struct fuse_conn *get_fuse_conn(struct inode *inode)
284{
285 return get_fuse_conn_super(inode->i_sb);
286}
287
288static inline struct fuse_inode *get_fuse_inode(struct inode *inode)
289{
290 return container_of(inode, struct fuse_inode, inode);
291}
292
293static inline u64 get_node_id(struct inode *inode)
294{
295 return get_fuse_inode(inode)->nodeid;
296}
297
298/** Device operations */
299extern struct file_operations fuse_dev_operations;
300
301/**
302 * This is the single global spinlock which protects FUSE's structures
303 *
304 * The following data is protected by this lock:
305 *
306 * - the private_data field of the device file
307 * - the s_fs_info field of the super block
308 * - unused_list, pending, processing lists in fuse_conn
309 * - background list in fuse_conn
310 * - the unique request ID counter reqctr in fuse_conn
311 * - the sb (super_block) field in fuse_conn
312 * - the file (device file) field in fuse_conn
313 */
314extern spinlock_t fuse_lock;
315
316/**
317 * Get a filled in inode
318 */
319struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
320 int generation, struct fuse_attr *attr);
321
322/**
323 * Send FORGET command
324 */
325void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req,
326 unsigned long nodeid, u64 nlookup);
327
328/**
329 * Send READ or READDIR request
330 */
331size_t fuse_send_read_common(struct fuse_req *req, struct file *file,
332 struct inode *inode, loff_t pos, size_t count,
333 int isdir);
334
335/**
336 * Send OPEN or OPENDIR request
337 */
338int fuse_open_common(struct inode *inode, struct file *file, int isdir);
339
340/**
341 * Send RELEASE or RELEASEDIR request
342 */
343int fuse_release_common(struct inode *inode, struct file *file, int isdir);
344
345/**
346 * Send FSYNC or FSYNCDIR request
347 */
348int fuse_fsync_common(struct file *file, struct dentry *de, int datasync,
349 int isdir);
350
351/**
352 * Initialise file operations on a regular file
353 */
354void fuse_init_file_inode(struct inode *inode);
355
356/**
357 * Initialise inode operations on regular files and special files
358 */
359void fuse_init_common(struct inode *inode);
360
361/**
362 * Initialise inode and file operations on a directory
363 */
364void fuse_init_dir(struct inode *inode);
365
366/**
367 * Initialise inode operations on a symlink
368 */
369void fuse_init_symlink(struct inode *inode);
370
371/**
372 * Change attributes of an inode
373 */
374void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr);
375
376/**
377 * Check if the connection can be released, and if yes, then free the
378 * connection structure
379 */
380void fuse_release_conn(struct fuse_conn *fc);
381
382/**
383 * Initialize the client device
384 */
385int fuse_dev_init(void);
386
387/**
388 * Cleanup the client device
389 */
390void fuse_dev_cleanup(void);
391
392/**
393 * Allocate a request
394 */
395struct fuse_req *fuse_request_alloc(void);
396
397/**
398 * Free a request
399 */
400void fuse_request_free(struct fuse_req *req);
401
402/**
403 * Reinitialize a request, the preallocated flag is left unmodified
404 */
405void fuse_reset_request(struct fuse_req *req);
406
407/**
408 * Reserve a preallocated request
409 */
410struct fuse_req *fuse_get_request(struct fuse_conn *fc);
411
412/**
413 * Decrement reference count of a request. If count goes to zero put
414 * on unused list (preallocated) or free reqest (not preallocated).
415 */
416void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req);
417
418/**
419 * Send a request (synchronous)
420 */
421void request_send(struct fuse_conn *fc, struct fuse_req *req);
422
423/**
424 * Send a request with no reply
425 */
426void request_send_noreply(struct fuse_conn *fc, struct fuse_req *req);
427
428/**
429 * Send a request in the background
430 */
431void request_send_background(struct fuse_conn *fc, struct fuse_req *req);
432
433/**
434 * Release inodes and file assiciated with background request
435 */
436void fuse_release_background(struct fuse_req *req);
437
438/**
439 * Get the attributes of a file
440 */
441int fuse_do_getattr(struct inode *inode);
442
443/**
444 * Invalidate inode attributes
445 */
446void fuse_invalidate_attr(struct inode *inode);
447
448/**
449 * Send the INIT message
450 */
451void fuse_send_init(struct fuse_conn *fc);
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
new file mode 100644
index 0000000000..e69a546844
--- /dev/null
+++ b/fs/fuse/inode.c
@@ -0,0 +1,591 @@
1/*
2 FUSE: Filesystem in Userspace
3 Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.hu>
4
5 This program can be distributed under the terms of the GNU GPL.
6 See the file COPYING.
7*/
8
9#include "fuse_i.h"
10
11#include <linux/pagemap.h>
12#include <linux/slab.h>
13#include <linux/file.h>
14#include <linux/mount.h>
15#include <linux/seq_file.h>
16#include <linux/init.h>
17#include <linux/module.h>
18#include <linux/parser.h>
19#include <linux/statfs.h>
20
21MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>");
22MODULE_DESCRIPTION("Filesystem in Userspace");
23MODULE_LICENSE("GPL");
24
25spinlock_t fuse_lock;
26static kmem_cache_t *fuse_inode_cachep;
27
28#define FUSE_SUPER_MAGIC 0x65735546
29
30struct fuse_mount_data {
31 int fd;
32 unsigned rootmode;
33 unsigned user_id;
34 unsigned group_id;
35 unsigned fd_present : 1;
36 unsigned rootmode_present : 1;
37 unsigned user_id_present : 1;
38 unsigned group_id_present : 1;
39 unsigned flags;
40 unsigned max_read;
41};
42
43static struct inode *fuse_alloc_inode(struct super_block *sb)
44{
45 struct inode *inode;
46 struct fuse_inode *fi;
47
48 inode = kmem_cache_alloc(fuse_inode_cachep, SLAB_KERNEL);
49 if (!inode)
50 return NULL;
51
52 fi = get_fuse_inode(inode);
53 fi->i_time = jiffies - 1;
54 fi->nodeid = 0;
55 fi->nlookup = 0;
56 fi->forget_req = fuse_request_alloc();
57 if (!fi->forget_req) {
58 kmem_cache_free(fuse_inode_cachep, inode);
59 return NULL;
60 }
61
62 return inode;
63}
64
65static void fuse_destroy_inode(struct inode *inode)
66{
67 struct fuse_inode *fi = get_fuse_inode(inode);
68 if (fi->forget_req)
69 fuse_request_free(fi->forget_req);
70 kmem_cache_free(fuse_inode_cachep, inode);
71}
72
73static void fuse_read_inode(struct inode *inode)
74{
75 /* No op */
76}
77
78void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req,
79 unsigned long nodeid, u64 nlookup)
80{
81 struct fuse_forget_in *inarg = &req->misc.forget_in;
82 inarg->nlookup = nlookup;
83 req->in.h.opcode = FUSE_FORGET;
84 req->in.h.nodeid = nodeid;
85 req->in.numargs = 1;
86 req->in.args[0].size = sizeof(struct fuse_forget_in);
87 req->in.args[0].value = inarg;
88 request_send_noreply(fc, req);
89}
90
91static void fuse_clear_inode(struct inode *inode)
92{
93 if (inode->i_sb->s_flags & MS_ACTIVE) {
94 struct fuse_conn *fc = get_fuse_conn(inode);
95 struct fuse_inode *fi = get_fuse_inode(inode);
96 fuse_send_forget(fc, fi->forget_req, fi->nodeid, fi->nlookup);
97 fi->forget_req = NULL;
98 }
99}
100
101void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr)
102{
103 if (S_ISREG(inode->i_mode) && i_size_read(inode) != attr->size)
104 invalidate_inode_pages(inode->i_mapping);
105
106 inode->i_ino = attr->ino;
107 inode->i_mode = (inode->i_mode & S_IFMT) + (attr->mode & 07777);
108 inode->i_nlink = attr->nlink;
109 inode->i_uid = attr->uid;
110 inode->i_gid = attr->gid;
111 i_size_write(inode, attr->size);
112 inode->i_blksize = PAGE_CACHE_SIZE;
113 inode->i_blocks = attr->blocks;
114 inode->i_atime.tv_sec = attr->atime;
115 inode->i_atime.tv_nsec = attr->atimensec;
116 inode->i_mtime.tv_sec = attr->mtime;
117 inode->i_mtime.tv_nsec = attr->mtimensec;
118 inode->i_ctime.tv_sec = attr->ctime;
119 inode->i_ctime.tv_nsec = attr->ctimensec;
120}
121
122static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr)
123{
124 inode->i_mode = attr->mode & S_IFMT;
125 i_size_write(inode, attr->size);
126 if (S_ISREG(inode->i_mode)) {
127 fuse_init_common(inode);
128 fuse_init_file_inode(inode);
129 } else if (S_ISDIR(inode->i_mode))
130 fuse_init_dir(inode);
131 else if (S_ISLNK(inode->i_mode))
132 fuse_init_symlink(inode);
133 else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) ||
134 S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
135 fuse_init_common(inode);
136 init_special_inode(inode, inode->i_mode,
137 new_decode_dev(attr->rdev));
138 } else {
139 /* Don't let user create weird files */
140 inode->i_mode = S_IFREG;
141 fuse_init_common(inode);
142 fuse_init_file_inode(inode);
143 }
144}
145
146static int fuse_inode_eq(struct inode *inode, void *_nodeidp)
147{
148 unsigned long nodeid = *(unsigned long *) _nodeidp;
149 if (get_node_id(inode) == nodeid)
150 return 1;
151 else
152 return 0;
153}
154
155static int fuse_inode_set(struct inode *inode, void *_nodeidp)
156{
157 unsigned long nodeid = *(unsigned long *) _nodeidp;
158 get_fuse_inode(inode)->nodeid = nodeid;
159 return 0;
160}
161
162struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
163 int generation, struct fuse_attr *attr)
164{
165 struct inode *inode;
166 struct fuse_inode *fi;
167 struct fuse_conn *fc = get_fuse_conn_super(sb);
168 int retried = 0;
169
170 retry:
171 inode = iget5_locked(sb, nodeid, fuse_inode_eq, fuse_inode_set, &nodeid);
172 if (!inode)
173 return NULL;
174
175 if ((inode->i_state & I_NEW)) {
176 inode->i_flags |= S_NOATIME|S_NOCMTIME;
177 inode->i_generation = generation;
178 inode->i_data.backing_dev_info = &fc->bdi;
179 fuse_init_inode(inode, attr);
180 unlock_new_inode(inode);
181 } else if ((inode->i_mode ^ attr->mode) & S_IFMT) {
182 BUG_ON(retried);
183 /* Inode has changed type, any I/O on the old should fail */
184 make_bad_inode(inode);
185 iput(inode);
186 retried = 1;
187 goto retry;
188 }
189
190 fi = get_fuse_inode(inode);
191 fi->nlookup ++;
192 fuse_change_attributes(inode, attr);
193 return inode;
194}
195
196static void fuse_put_super(struct super_block *sb)
197{
198 struct fuse_conn *fc = get_fuse_conn_super(sb);
199
200 down_write(&fc->sbput_sem);
201 while (!list_empty(&fc->background))
202 fuse_release_background(list_entry(fc->background.next,
203 struct fuse_req, bg_entry));
204
205 spin_lock(&fuse_lock);
206 fc->mounted = 0;
207 fc->user_id = 0;
208 fc->group_id = 0;
209 fc->flags = 0;
210 /* Flush all readers on this fs */
211 wake_up_all(&fc->waitq);
212 up_write(&fc->sbput_sem);
213 fuse_release_conn(fc);
214 spin_unlock(&fuse_lock);
215}
216
217static void convert_fuse_statfs(struct kstatfs *stbuf, struct fuse_kstatfs *attr)
218{
219 stbuf->f_type = FUSE_SUPER_MAGIC;
220 stbuf->f_bsize = attr->bsize;
221 stbuf->f_blocks = attr->blocks;
222 stbuf->f_bfree = attr->bfree;
223 stbuf->f_bavail = attr->bavail;
224 stbuf->f_files = attr->files;
225 stbuf->f_ffree = attr->ffree;
226 stbuf->f_namelen = attr->namelen;
227 /* fsid is left zero */
228}
229
230static int fuse_statfs(struct super_block *sb, struct kstatfs *buf)
231{
232 struct fuse_conn *fc = get_fuse_conn_super(sb);
233 struct fuse_req *req;
234 struct fuse_statfs_out outarg;
235 int err;
236
237 req = fuse_get_request(fc);
238 if (!req)
239 return -EINTR;
240
241 req->in.numargs = 0;
242 req->in.h.opcode = FUSE_STATFS;
243 req->out.numargs = 1;
244 req->out.args[0].size = sizeof(outarg);
245 req->out.args[0].value = &outarg;
246 request_send(fc, req);
247 err = req->out.h.error;
248 if (!err)
249 convert_fuse_statfs(buf, &outarg.st);
250 fuse_put_request(fc, req);
251 return err;
252}
253
254enum {
255 OPT_FD,
256 OPT_ROOTMODE,
257 OPT_USER_ID,
258 OPT_GROUP_ID,
259 OPT_DEFAULT_PERMISSIONS,
260 OPT_ALLOW_OTHER,
261 OPT_MAX_READ,
262 OPT_ERR
263};
264
265static match_table_t tokens = {
266 {OPT_FD, "fd=%u"},
267 {OPT_ROOTMODE, "rootmode=%o"},
268 {OPT_USER_ID, "user_id=%u"},
269 {OPT_GROUP_ID, "group_id=%u"},
270 {OPT_DEFAULT_PERMISSIONS, "default_permissions"},
271 {OPT_ALLOW_OTHER, "allow_other"},
272 {OPT_MAX_READ, "max_read=%u"},
273 {OPT_ERR, NULL}
274};
275
276static int parse_fuse_opt(char *opt, struct fuse_mount_data *d)
277{
278 char *p;
279 memset(d, 0, sizeof(struct fuse_mount_data));
280 d->max_read = ~0;
281
282 while ((p = strsep(&opt, ",")) != NULL) {
283 int token;
284 int value;
285 substring_t args[MAX_OPT_ARGS];
286 if (!*p)
287 continue;
288
289 token = match_token(p, tokens, args);
290 switch (token) {
291 case OPT_FD:
292 if (match_int(&args[0], &value))
293 return 0;
294 d->fd = value;
295 d->fd_present = 1;
296 break;
297
298 case OPT_ROOTMODE:
299 if (match_octal(&args[0], &value))
300 return 0;
301 d->rootmode = value;
302 d->rootmode_present = 1;
303 break;
304
305 case OPT_USER_ID:
306 if (match_int(&args[0], &value))
307 return 0;
308 d->user_id = value;
309 d->user_id_present = 1;
310 break;
311
312 case OPT_GROUP_ID:
313 if (match_int(&args[0], &value))
314 return 0;
315 d->group_id = value;
316 d->group_id_present = 1;
317 break;
318
319 case OPT_DEFAULT_PERMISSIONS:
320 d->flags |= FUSE_DEFAULT_PERMISSIONS;
321 break;
322
323 case OPT_ALLOW_OTHER:
324 d->flags |= FUSE_ALLOW_OTHER;
325 break;
326
327 case OPT_MAX_READ:
328 if (match_int(&args[0], &value))
329 return 0;
330 d->max_read = value;
331 break;
332
333 default:
334 return 0;
335 }
336 }
337
338 if (!d->fd_present || !d->rootmode_present ||
339 !d->user_id_present || !d->group_id_present)
340 return 0;
341
342 return 1;
343}
344
345static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt)
346{
347 struct fuse_conn *fc = get_fuse_conn_super(mnt->mnt_sb);
348
349 seq_printf(m, ",user_id=%u", fc->user_id);
350 seq_printf(m, ",group_id=%u", fc->group_id);
351 if (fc->flags & FUSE_DEFAULT_PERMISSIONS)
352 seq_puts(m, ",default_permissions");
353 if (fc->flags & FUSE_ALLOW_OTHER)
354 seq_puts(m, ",allow_other");
355 if (fc->max_read != ~0)
356 seq_printf(m, ",max_read=%u", fc->max_read);
357 return 0;
358}
359
360static void free_conn(struct fuse_conn *fc)
361{
362 while (!list_empty(&fc->unused_list)) {
363 struct fuse_req *req;
364 req = list_entry(fc->unused_list.next, struct fuse_req, list);
365 list_del(&req->list);
366 fuse_request_free(req);
367 }
368 kfree(fc);
369}
370
371/* Must be called with the fuse lock held */
372void fuse_release_conn(struct fuse_conn *fc)
373{
374 fc->count--;
375 if (!fc->count)
376 free_conn(fc);
377}
378
379static struct fuse_conn *new_conn(void)
380{
381 struct fuse_conn *fc;
382
383 fc = kmalloc(sizeof(*fc), GFP_KERNEL);
384 if (fc != NULL) {
385 int i;
386 memset(fc, 0, sizeof(*fc));
387 init_waitqueue_head(&fc->waitq);
388 INIT_LIST_HEAD(&fc->pending);
389 INIT_LIST_HEAD(&fc->processing);
390 INIT_LIST_HEAD(&fc->unused_list);
391 INIT_LIST_HEAD(&fc->background);
392 sema_init(&fc->outstanding_sem, 0);
393 init_rwsem(&fc->sbput_sem);
394 for (i = 0; i < FUSE_MAX_OUTSTANDING; i++) {
395 struct fuse_req *req = fuse_request_alloc();
396 if (!req) {
397 free_conn(fc);
398 return NULL;
399 }
400 list_add(&req->list, &fc->unused_list);
401 }
402 fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
403 fc->bdi.unplug_io_fn = default_unplug_io_fn;
404 fc->reqctr = 0;
405 }
406 return fc;
407}
408
409static struct fuse_conn *get_conn(struct file *file, struct super_block *sb)
410{
411 struct fuse_conn *fc;
412
413 if (file->f_op != &fuse_dev_operations)
414 return ERR_PTR(-EINVAL);
415 fc = new_conn();
416 if (fc == NULL)
417 return ERR_PTR(-ENOMEM);
418 spin_lock(&fuse_lock);
419 if (file->private_data) {
420 free_conn(fc);
421 fc = ERR_PTR(-EINVAL);
422 } else {
423 file->private_data = fc;
424 *get_fuse_conn_super_p(sb) = fc;
425 fc->mounted = 1;
426 fc->connected = 1;
427 fc->count = 2;
428 }
429 spin_unlock(&fuse_lock);
430 return fc;
431}
432
433static struct inode *get_root_inode(struct super_block *sb, unsigned mode)
434{
435 struct fuse_attr attr;
436 memset(&attr, 0, sizeof(attr));
437
438 attr.mode = mode;
439 attr.ino = FUSE_ROOT_ID;
440 return fuse_iget(sb, 1, 0, &attr);
441}
442
443static struct super_operations fuse_super_operations = {
444 .alloc_inode = fuse_alloc_inode,
445 .destroy_inode = fuse_destroy_inode,
446 .read_inode = fuse_read_inode,
447 .clear_inode = fuse_clear_inode,
448 .put_super = fuse_put_super,
449 .statfs = fuse_statfs,
450 .show_options = fuse_show_options,
451};
452
453static int fuse_fill_super(struct super_block *sb, void *data, int silent)
454{
455 struct fuse_conn *fc;
456 struct inode *root;
457 struct fuse_mount_data d;
458 struct file *file;
459 int err;
460
461 if (!parse_fuse_opt((char *) data, &d))
462 return -EINVAL;
463
464 sb->s_blocksize = PAGE_CACHE_SIZE;
465 sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
466 sb->s_magic = FUSE_SUPER_MAGIC;
467 sb->s_op = &fuse_super_operations;
468 sb->s_maxbytes = MAX_LFS_FILESIZE;
469
470 file = fget(d.fd);
471 if (!file)
472 return -EINVAL;
473
474 fc = get_conn(file, sb);
475 fput(file);
476 if (IS_ERR(fc))
477 return PTR_ERR(fc);
478
479 fc->flags = d.flags;
480 fc->user_id = d.user_id;
481 fc->group_id = d.group_id;
482 fc->max_read = d.max_read;
483 if (fc->max_read / PAGE_CACHE_SIZE < fc->bdi.ra_pages)
484 fc->bdi.ra_pages = fc->max_read / PAGE_CACHE_SIZE;
485 fc->max_write = FUSE_MAX_IN / 2;
486
487 err = -ENOMEM;
488 root = get_root_inode(sb, d.rootmode);
489 if (root == NULL)
490 goto err;
491
492 sb->s_root = d_alloc_root(root);
493 if (!sb->s_root) {
494 iput(root);
495 goto err;
496 }
497 fuse_send_init(fc);
498 return 0;
499
500 err:
501 spin_lock(&fuse_lock);
502 fuse_release_conn(fc);
503 spin_unlock(&fuse_lock);
504 return err;
505}
506
507static struct super_block *fuse_get_sb(struct file_system_type *fs_type,
508 int flags, const char *dev_name,
509 void *raw_data)
510{
511 return get_sb_nodev(fs_type, flags, raw_data, fuse_fill_super);
512}
513
514static struct file_system_type fuse_fs_type = {
515 .owner = THIS_MODULE,
516 .name = "fuse",
517 .get_sb = fuse_get_sb,
518 .kill_sb = kill_anon_super,
519};
520
521static void fuse_inode_init_once(void *foo, kmem_cache_t *cachep,
522 unsigned long flags)
523{
524 struct inode * inode = foo;
525
526 if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
527 SLAB_CTOR_CONSTRUCTOR)
528 inode_init_once(inode);
529}
530
531static int __init fuse_fs_init(void)
532{
533 int err;
534
535 err = register_filesystem(&fuse_fs_type);
536 if (err)
537 printk("fuse: failed to register filesystem\n");
538 else {
539 fuse_inode_cachep = kmem_cache_create("fuse_inode",
540 sizeof(struct fuse_inode),
541 0, SLAB_HWCACHE_ALIGN,
542 fuse_inode_init_once, NULL);
543 if (!fuse_inode_cachep) {
544 unregister_filesystem(&fuse_fs_type);
545 err = -ENOMEM;
546 }
547 }
548
549 return err;
550}
551
552static void fuse_fs_cleanup(void)
553{
554 unregister_filesystem(&fuse_fs_type);
555 kmem_cache_destroy(fuse_inode_cachep);
556}
557
558static int __init fuse_init(void)
559{
560 int res;
561
562 printk("fuse init (API version %i.%i)\n",
563 FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
564
565 spin_lock_init(&fuse_lock);
566 res = fuse_fs_init();
567 if (res)
568 goto err;
569
570 res = fuse_dev_init();
571 if (res)
572 goto err_fs_cleanup;
573
574 return 0;
575
576 err_fs_cleanup:
577 fuse_fs_cleanup();
578 err:
579 return res;
580}
581
582static void __exit fuse_exit(void)
583{
584 printk(KERN_DEBUG "fuse exit\n");
585
586 fuse_fs_cleanup();
587 fuse_dev_cleanup();
588}
589
590module_init(fuse_init);
591module_exit(fuse_exit);
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c
index b2d18200a0..59c5062cd6 100644
--- a/fs/hostfs/hostfs_kern.c
+++ b/fs/hostfs/hostfs_kern.c
@@ -284,6 +284,7 @@ static struct inode *hostfs_alloc_inode(struct super_block *sb)
284 284
285static void hostfs_delete_inode(struct inode *inode) 285static void hostfs_delete_inode(struct inode *inode)
286{ 286{
287 truncate_inode_pages(&inode->i_data, 0);
287 if(HOSTFS_I(inode)->fd != -1) { 288 if(HOSTFS_I(inode)->fd != -1) {
288 close_file(&HOSTFS_I(inode)->fd); 289 close_file(&HOSTFS_I(inode)->fd);
289 HOSTFS_I(inode)->fd = -1; 290 HOSTFS_I(inode)->fd = -1;
diff --git a/fs/hpfs/inode.c b/fs/hpfs/inode.c
index 38b1741fa5..e3d17e9ea6 100644
--- a/fs/hpfs/inode.c
+++ b/fs/hpfs/inode.c
@@ -284,6 +284,7 @@ void hpfs_write_if_changed(struct inode *inode)
284 284
285void hpfs_delete_inode(struct inode *inode) 285void hpfs_delete_inode(struct inode *inode)
286{ 286{
287 truncate_inode_pages(&inode->i_data, 0);
287 lock_kernel(); 288 lock_kernel();
288 hpfs_remove_fnode(inode->i_sb, inode->i_ino); 289 hpfs_remove_fnode(inode->i_sb, inode->i_ino);
289 unlock_kernel(); 290 unlock_kernel();
diff --git a/fs/inode.c b/fs/inode.c
index 71df1b1e8f..f80a79ff15 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -1034,19 +1034,21 @@ void generic_delete_inode(struct inode *inode)
1034 inodes_stat.nr_inodes--; 1034 inodes_stat.nr_inodes--;
1035 spin_unlock(&inode_lock); 1035 spin_unlock(&inode_lock);
1036 1036
1037 if (inode->i_data.nrpages)
1038 truncate_inode_pages(&inode->i_data, 0);
1039
1040 security_inode_delete(inode); 1037 security_inode_delete(inode);
1041 1038
1042 if (op->delete_inode) { 1039 if (op->delete_inode) {
1043 void (*delete)(struct inode *) = op->delete_inode; 1040 void (*delete)(struct inode *) = op->delete_inode;
1044 if (!is_bad_inode(inode)) 1041 if (!is_bad_inode(inode))
1045 DQUOT_INIT(inode); 1042 DQUOT_INIT(inode);
1046 /* s_op->delete_inode internally recalls clear_inode() */ 1043 /* Filesystems implementing their own
1044 * s_op->delete_inode are required to call
1045 * truncate_inode_pages and clear_inode()
1046 * internally */
1047 delete(inode); 1047 delete(inode);
1048 } else 1048 } else {
1049 truncate_inode_pages(&inode->i_data, 0);
1049 clear_inode(inode); 1050 clear_inode(inode);
1051 }
1050 spin_lock(&inode_lock); 1052 spin_lock(&inode_lock);
1051 hlist_del_init(&inode->i_hash); 1053 hlist_del_init(&inode->i_hash);
1052 spin_unlock(&inode_lock); 1054 spin_unlock(&inode_lock);
diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c
index c6ec66fd87..49bbc2be3d 100644
--- a/fs/jbd/transaction.c
+++ b/fs/jbd/transaction.c
@@ -1340,8 +1340,7 @@ int journal_stop(handle_t *handle)
1340 if (handle->h_sync) { 1340 if (handle->h_sync) {
1341 do { 1341 do {
1342 old_handle_count = transaction->t_handle_count; 1342 old_handle_count = transaction->t_handle_count;
1343 set_current_state(TASK_UNINTERRUPTIBLE); 1343 schedule_timeout_uninterruptible(1);
1344 schedule_timeout(1);
1345 } while (old_handle_count != transaction->t_handle_count); 1344 } while (old_handle_count != transaction->t_handle_count);
1346 } 1345 }
1347 1346
diff --git a/fs/jffs/inode-v23.c b/fs/jffs/inode-v23.c
index 777b90057b..3dcc6d2162 100644
--- a/fs/jffs/inode-v23.c
+++ b/fs/jffs/inode-v23.c
@@ -1744,6 +1744,7 @@ jffs_delete_inode(struct inode *inode)
1744 D3(printk("jffs_delete_inode(): inode->i_ino == %lu\n", 1744 D3(printk("jffs_delete_inode(): inode->i_ino == %lu\n",
1745 inode->i_ino)); 1745 inode->i_ino));
1746 1746
1747 truncate_inode_pages(&inode->i_data, 0);
1747 lock_kernel(); 1748 lock_kernel();
1748 inode->i_size = 0; 1749 inode->i_size = 0;
1749 inode->i_blocks = 0; 1750 inode->i_blocks = 0;
diff --git a/fs/jffs/intrep.c b/fs/jffs/intrep.c
index 456d7e6e29..27f199e94c 100644
--- a/fs/jffs/intrep.c
+++ b/fs/jffs/intrep.c
@@ -1701,12 +1701,10 @@ jffs_find_file(struct jffs_control *c, __u32 ino)
1701{ 1701{
1702 struct jffs_file *f; 1702 struct jffs_file *f;
1703 int i = ino % c->hash_len; 1703 int i = ino % c->hash_len;
1704 struct list_head *tmp;
1705 1704
1706 D3(printk("jffs_find_file(): ino: %u\n", ino)); 1705 D3(printk("jffs_find_file(): ino: %u\n", ino));
1707 1706
1708 for (tmp = c->hash[i].next; tmp != &c->hash[i]; tmp = tmp->next) { 1707 list_for_each_entry(f, &c->hash[i], hash) {
1709 f = list_entry(tmp, struct jffs_file, hash);
1710 if (ino != f->ino) 1708 if (ino != f->ino)
1711 continue; 1709 continue;
1712 D3(printk("jffs_find_file(): Found file with ino " 1710 D3(printk("jffs_find_file(): Found file with ino "
@@ -2102,13 +2100,12 @@ jffs_foreach_file(struct jffs_control *c, int (*func)(struct jffs_file *))
2102 int result = 0; 2100 int result = 0;
2103 2101
2104 for (pos = 0; pos < c->hash_len; pos++) { 2102 for (pos = 0; pos < c->hash_len; pos++) {
2105 struct list_head *p, *next; 2103 struct jffs_file *f, *next;
2106 for (p = c->hash[pos].next; p != &c->hash[pos]; p = next) { 2104
2107 /* We need a reference to the next file in the 2105 /* We must do _safe, because 'func' might remove the
2108 list because `func' might remove the current 2106 current file 'f' from the list. */
2109 file `f'. */ 2107 list_for_each_entry_safe(f, next, &c->hash[pos], hash) {
2110 next = p->next; 2108 r = func(f);
2111 r = func(list_entry(p, struct jffs_file, hash));
2112 if (r < 0) 2109 if (r < 0)
2113 return r; 2110 return r;
2114 result += r; 2111 result += r;
@@ -2613,9 +2610,8 @@ jffs_print_hash_table(struct jffs_control *c)
2613 2610
2614 printk("JFFS: Dumping the file system's hash table...\n"); 2611 printk("JFFS: Dumping the file system's hash table...\n");
2615 for (i = 0; i < c->hash_len; i++) { 2612 for (i = 0; i < c->hash_len; i++) {
2616 struct list_head *p; 2613 struct jffs_file *f;
2617 for (p = c->hash[i].next; p != &c->hash[i]; p = p->next) { 2614 list_for_each_entry(f, &c->hash[i], hash) {
2618 struct jffs_file *f=list_entry(p,struct jffs_file,hash);
2619 printk("*** c->hash[%u]: \"%s\" " 2615 printk("*** c->hash[%u]: \"%s\" "
2620 "(ino: %u, pino: %u)\n", 2616 "(ino: %u, pino: %u)\n",
2621 i, (f->name ? f->name : ""), 2617 i, (f->name ? f->name : ""),
diff --git a/fs/jfs/acl.c b/fs/jfs/acl.c
index e892dab40c..461e4934ca 100644
--- a/fs/jfs/acl.c
+++ b/fs/jfs/acl.c
@@ -23,6 +23,7 @@
23#include <linux/quotaops.h> 23#include <linux/quotaops.h>
24#include <linux/posix_acl_xattr.h> 24#include <linux/posix_acl_xattr.h>
25#include "jfs_incore.h" 25#include "jfs_incore.h"
26#include "jfs_txnmgr.h"
26#include "jfs_xattr.h" 27#include "jfs_xattr.h"
27#include "jfs_acl.h" 28#include "jfs_acl.h"
28 29
@@ -75,7 +76,8 @@ static struct posix_acl *jfs_get_acl(struct inode *inode, int type)
75 return acl; 76 return acl;
76} 77}
77 78
78static int jfs_set_acl(struct inode *inode, int type, struct posix_acl *acl) 79static int jfs_set_acl(tid_t tid, struct inode *inode, int type,
80 struct posix_acl *acl)
79{ 81{
80 char *ea_name; 82 char *ea_name;
81 struct jfs_inode_info *ji = JFS_IP(inode); 83 struct jfs_inode_info *ji = JFS_IP(inode);
@@ -110,7 +112,7 @@ static int jfs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
110 if (rc < 0) 112 if (rc < 0)
111 goto out; 113 goto out;
112 } 114 }
113 rc = __jfs_setxattr(inode, ea_name, value, size, 0); 115 rc = __jfs_setxattr(tid, inode, ea_name, value, size, 0);
114out: 116out:
115 kfree(value); 117 kfree(value);
116 118
@@ -143,7 +145,7 @@ int jfs_permission(struct inode *inode, int mask, struct nameidata *nd)
143 return generic_permission(inode, mask, jfs_check_acl); 145 return generic_permission(inode, mask, jfs_check_acl);
144} 146}
145 147
146int jfs_init_acl(struct inode *inode, struct inode *dir) 148int jfs_init_acl(tid_t tid, struct inode *inode, struct inode *dir)
147{ 149{
148 struct posix_acl *acl = NULL; 150 struct posix_acl *acl = NULL;
149 struct posix_acl *clone; 151 struct posix_acl *clone;
@@ -159,7 +161,7 @@ int jfs_init_acl(struct inode *inode, struct inode *dir)
159 161
160 if (acl) { 162 if (acl) {
161 if (S_ISDIR(inode->i_mode)) { 163 if (S_ISDIR(inode->i_mode)) {
162 rc = jfs_set_acl(inode, ACL_TYPE_DEFAULT, acl); 164 rc = jfs_set_acl(tid, inode, ACL_TYPE_DEFAULT, acl);
163 if (rc) 165 if (rc)
164 goto cleanup; 166 goto cleanup;
165 } 167 }
@@ -173,7 +175,8 @@ int jfs_init_acl(struct inode *inode, struct inode *dir)
173 if (rc >= 0) { 175 if (rc >= 0) {
174 inode->i_mode = mode; 176 inode->i_mode = mode;
175 if (rc > 0) 177 if (rc > 0)
176 rc = jfs_set_acl(inode, ACL_TYPE_ACCESS, clone); 178 rc = jfs_set_acl(tid, inode, ACL_TYPE_ACCESS,
179 clone);
177 } 180 }
178 posix_acl_release(clone); 181 posix_acl_release(clone);
179cleanup: 182cleanup:
@@ -202,8 +205,15 @@ static int jfs_acl_chmod(struct inode *inode)
202 return -ENOMEM; 205 return -ENOMEM;
203 206
204 rc = posix_acl_chmod_masq(clone, inode->i_mode); 207 rc = posix_acl_chmod_masq(clone, inode->i_mode);
205 if (!rc) 208 if (!rc) {
206 rc = jfs_set_acl(inode, ACL_TYPE_ACCESS, clone); 209 tid_t tid = txBegin(inode->i_sb, 0);
210 down(&JFS_IP(inode)->commit_sem);
211 rc = jfs_set_acl(tid, inode, ACL_TYPE_ACCESS, clone);
212 if (!rc)
213 rc = txCommit(tid, 1, &inode, 0);
214 txEnd(tid);
215 up(&JFS_IP(inode)->commit_sem);
216 }
207 217
208 posix_acl_release(clone); 218 posix_acl_release(clone);
209 return rc; 219 return rc;
diff --git a/fs/jfs/inode.c b/fs/jfs/inode.c
index 767c7ecb42..0ec62d5310 100644
--- a/fs/jfs/inode.c
+++ b/fs/jfs/inode.c
@@ -128,21 +128,23 @@ void jfs_delete_inode(struct inode *inode)
128{ 128{
129 jfs_info("In jfs_delete_inode, inode = 0x%p", inode); 129 jfs_info("In jfs_delete_inode, inode = 0x%p", inode);
130 130
131 if (is_bad_inode(inode) || 131 if (!is_bad_inode(inode) &&
132 (JFS_IP(inode)->fileset != cpu_to_le32(FILESYSTEM_I))) 132 (JFS_IP(inode)->fileset == cpu_to_le32(FILESYSTEM_I))) {
133 return;
134 133
135 if (test_cflag(COMMIT_Freewmap, inode)) 134 truncate_inode_pages(&inode->i_data, 0);
136 jfs_free_zero_link(inode);
137 135
138 diFree(inode); 136 if (test_cflag(COMMIT_Freewmap, inode))
137 jfs_free_zero_link(inode);
139 138
140 /* 139 diFree(inode);
141 * Free the inode from the quota allocation. 140
142 */ 141 /*
143 DQUOT_INIT(inode); 142 * Free the inode from the quota allocation.
144 DQUOT_FREE_INODE(inode); 143 */
145 DQUOT_DROP(inode); 144 DQUOT_INIT(inode);
145 DQUOT_FREE_INODE(inode);
146 DQUOT_DROP(inode);
147 }
146 148
147 clear_inode(inode); 149 clear_inode(inode);
148} 150}
diff --git a/fs/jfs/jfs_acl.h b/fs/jfs/jfs_acl.h
index a3acd3eec0..a76293767c 100644
--- a/fs/jfs/jfs_acl.h
+++ b/fs/jfs/jfs_acl.h
@@ -21,8 +21,16 @@
21#ifdef CONFIG_JFS_POSIX_ACL 21#ifdef CONFIG_JFS_POSIX_ACL
22 22
23int jfs_permission(struct inode *, int, struct nameidata *); 23int jfs_permission(struct inode *, int, struct nameidata *);
24int jfs_init_acl(struct inode *, struct inode *); 24int jfs_init_acl(tid_t, struct inode *, struct inode *);
25int jfs_setattr(struct dentry *, struct iattr *); 25int jfs_setattr(struct dentry *, struct iattr *);
26 26
27#endif /* CONFIG_JFS_POSIX_ACL */ 27#else
28
29static inline int jfs_init_acl(tid_t tid, struct inode *inode,
30 struct inode *dir)
31{
32 return 0;
33}
34
35#endif
28#endif /* _H_JFS_ACL */ 36#endif /* _H_JFS_ACL */
diff --git a/fs/jfs/jfs_xattr.h b/fs/jfs/jfs_xattr.h
index a1052f3f0b..25e9990bcc 100644
--- a/fs/jfs/jfs_xattr.h
+++ b/fs/jfs/jfs_xattr.h
@@ -52,8 +52,8 @@ struct jfs_ea_list {
52#define END_EALIST(ealist) \ 52#define END_EALIST(ealist) \
53 ((struct jfs_ea *) (((char *) (ealist)) + EALIST_SIZE(ealist))) 53 ((struct jfs_ea *) (((char *) (ealist)) + EALIST_SIZE(ealist)))
54 54
55extern int __jfs_setxattr(struct inode *, const char *, const void *, size_t, 55extern int __jfs_setxattr(tid_t, struct inode *, const char *, const void *,
56 int); 56 size_t, int);
57extern int jfs_setxattr(struct dentry *, const char *, const void *, size_t, 57extern int jfs_setxattr(struct dentry *, const char *, const void *, size_t,
58 int); 58 int);
59extern ssize_t __jfs_getxattr(struct inode *, const char *, void *, size_t); 59extern ssize_t __jfs_getxattr(struct inode *, const char *, void *, size_t);
@@ -61,4 +61,14 @@ extern ssize_t jfs_getxattr(struct dentry *, const char *, void *, size_t);
61extern ssize_t jfs_listxattr(struct dentry *, char *, size_t); 61extern ssize_t jfs_listxattr(struct dentry *, char *, size_t);
62extern int jfs_removexattr(struct dentry *, const char *); 62extern int jfs_removexattr(struct dentry *, const char *);
63 63
64#ifdef CONFIG_JFS_SECURITY
65extern int jfs_init_security(tid_t, struct inode *, struct inode *);
66#else
67static inline int jfs_init_security(tid_t tid, struct inode *inode,
68 struct inode *dir)
69{
70 return 0;
71}
72#endif
73
64#endif /* H_JFS_XATTR */ 74#endif /* H_JFS_XATTR */
diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c
index 49ccde3937..1abe7343f9 100644
--- a/fs/jfs/namei.c
+++ b/fs/jfs/namei.c
@@ -39,6 +39,24 @@ struct dentry_operations jfs_ci_dentry_operations;
39static s64 commitZeroLink(tid_t, struct inode *); 39static s64 commitZeroLink(tid_t, struct inode *);
40 40
41/* 41/*
42 * NAME: free_ea_wmap(inode)
43 *
44 * FUNCTION: free uncommitted extended attributes from working map
45 *
46 */
47static inline void free_ea_wmap(struct inode *inode)
48{
49 dxd_t *ea = &JFS_IP(inode)->ea;
50
51 if (ea->flag & DXD_EXTENT) {
52 /* free EA pages from cache */
53 invalidate_dxd_metapages(inode, *ea);
54 dbFree(inode, addressDXD(ea), lengthDXD(ea));
55 }
56 ea->flag = 0;
57}
58
59/*
42 * NAME: jfs_create(dip, dentry, mode) 60 * NAME: jfs_create(dip, dentry, mode)
43 * 61 *
44 * FUNCTION: create a regular file in the parent directory <dip> 62 * FUNCTION: create a regular file in the parent directory <dip>
@@ -89,8 +107,19 @@ static int jfs_create(struct inode *dip, struct dentry *dentry, int mode,
89 down(&JFS_IP(dip)->commit_sem); 107 down(&JFS_IP(dip)->commit_sem);
90 down(&JFS_IP(ip)->commit_sem); 108 down(&JFS_IP(ip)->commit_sem);
91 109
110 rc = jfs_init_acl(tid, ip, dip);
111 if (rc)
112 goto out3;
113
114 rc = jfs_init_security(tid, ip, dip);
115 if (rc) {
116 txAbort(tid, 0);
117 goto out3;
118 }
119
92 if ((rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE))) { 120 if ((rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE))) {
93 jfs_err("jfs_create: dtSearch returned %d", rc); 121 jfs_err("jfs_create: dtSearch returned %d", rc);
122 txAbort(tid, 0);
94 goto out3; 123 goto out3;
95 } 124 }
96 125
@@ -139,6 +168,7 @@ static int jfs_create(struct inode *dip, struct dentry *dentry, int mode,
139 up(&JFS_IP(dip)->commit_sem); 168 up(&JFS_IP(dip)->commit_sem);
140 up(&JFS_IP(ip)->commit_sem); 169 up(&JFS_IP(ip)->commit_sem);
141 if (rc) { 170 if (rc) {
171 free_ea_wmap(ip);
142 ip->i_nlink = 0; 172 ip->i_nlink = 0;
143 iput(ip); 173 iput(ip);
144 } else 174 } else
@@ -147,11 +177,6 @@ static int jfs_create(struct inode *dip, struct dentry *dentry, int mode,
147 out2: 177 out2:
148 free_UCSname(&dname); 178 free_UCSname(&dname);
149 179
150#ifdef CONFIG_JFS_POSIX_ACL
151 if (rc == 0)
152 jfs_init_acl(ip, dip);
153#endif
154
155 out1: 180 out1:
156 181
157 jfs_info("jfs_create: rc:%d", rc); 182 jfs_info("jfs_create: rc:%d", rc);
@@ -216,8 +241,19 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode)
216 down(&JFS_IP(dip)->commit_sem); 241 down(&JFS_IP(dip)->commit_sem);
217 down(&JFS_IP(ip)->commit_sem); 242 down(&JFS_IP(ip)->commit_sem);
218 243
244 rc = jfs_init_acl(tid, ip, dip);
245 if (rc)
246 goto out3;
247
248 rc = jfs_init_security(tid, ip, dip);
249 if (rc) {
250 txAbort(tid, 0);
251 goto out3;
252 }
253
219 if ((rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE))) { 254 if ((rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE))) {
220 jfs_err("jfs_mkdir: dtSearch returned %d", rc); 255 jfs_err("jfs_mkdir: dtSearch returned %d", rc);
256 txAbort(tid, 0);
221 goto out3; 257 goto out3;
222 } 258 }
223 259
@@ -267,6 +303,7 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode)
267 up(&JFS_IP(dip)->commit_sem); 303 up(&JFS_IP(dip)->commit_sem);
268 up(&JFS_IP(ip)->commit_sem); 304 up(&JFS_IP(ip)->commit_sem);
269 if (rc) { 305 if (rc) {
306 free_ea_wmap(ip);
270 ip->i_nlink = 0; 307 ip->i_nlink = 0;
271 iput(ip); 308 iput(ip);
272 } else 309 } else
@@ -275,10 +312,6 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode)
275 out2: 312 out2:
276 free_UCSname(&dname); 313 free_UCSname(&dname);
277 314
278#ifdef CONFIG_JFS_POSIX_ACL
279 if (rc == 0)
280 jfs_init_acl(ip, dip);
281#endif
282 315
283 out1: 316 out1:
284 317
@@ -885,6 +918,10 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
885 down(&JFS_IP(dip)->commit_sem); 918 down(&JFS_IP(dip)->commit_sem);
886 down(&JFS_IP(ip)->commit_sem); 919 down(&JFS_IP(ip)->commit_sem);
887 920
921 rc = jfs_init_security(tid, ip, dip);
922 if (rc)
923 goto out3;
924
888 tblk = tid_to_tblock(tid); 925 tblk = tid_to_tblock(tid);
889 tblk->xflag |= COMMIT_CREATE; 926 tblk->xflag |= COMMIT_CREATE;
890 tblk->ino = ip->i_ino; 927 tblk->ino = ip->i_ino;
@@ -1000,6 +1037,7 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
1000 up(&JFS_IP(dip)->commit_sem); 1037 up(&JFS_IP(dip)->commit_sem);
1001 up(&JFS_IP(ip)->commit_sem); 1038 up(&JFS_IP(ip)->commit_sem);
1002 if (rc) { 1039 if (rc) {
1040 free_ea_wmap(ip);
1003 ip->i_nlink = 0; 1041 ip->i_nlink = 0;
1004 iput(ip); 1042 iput(ip);
1005 } else 1043 } else
@@ -1008,11 +1046,6 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
1008 out2: 1046 out2:
1009 free_UCSname(&dname); 1047 free_UCSname(&dname);
1010 1048
1011#ifdef CONFIG_JFS_POSIX_ACL
1012 if (rc == 0)
1013 jfs_init_acl(ip, dip);
1014#endif
1015
1016 out1: 1049 out1:
1017 jfs_info("jfs_symlink: rc:%d", rc); 1050 jfs_info("jfs_symlink: rc:%d", rc);
1018 return rc; 1051 return rc;
@@ -1328,8 +1361,20 @@ static int jfs_mknod(struct inode *dir, struct dentry *dentry,
1328 down(&JFS_IP(dir)->commit_sem); 1361 down(&JFS_IP(dir)->commit_sem);
1329 down(&JFS_IP(ip)->commit_sem); 1362 down(&JFS_IP(ip)->commit_sem);
1330 1363
1331 if ((rc = dtSearch(dir, &dname, &ino, &btstack, JFS_CREATE))) 1364 rc = jfs_init_acl(tid, ip, dir);
1365 if (rc)
1366 goto out3;
1367
1368 rc = jfs_init_security(tid, ip, dir);
1369 if (rc) {
1370 txAbort(tid, 0);
1332 goto out3; 1371 goto out3;
1372 }
1373
1374 if ((rc = dtSearch(dir, &dname, &ino, &btstack, JFS_CREATE))) {
1375 txAbort(tid, 0);
1376 goto out3;
1377 }
1333 1378
1334 tblk = tid_to_tblock(tid); 1379 tblk = tid_to_tblock(tid);
1335 tblk->xflag |= COMMIT_CREATE; 1380 tblk->xflag |= COMMIT_CREATE;
@@ -1337,8 +1382,10 @@ static int jfs_mknod(struct inode *dir, struct dentry *dentry,
1337 tblk->u.ixpxd = JFS_IP(ip)->ixpxd; 1382 tblk->u.ixpxd = JFS_IP(ip)->ixpxd;
1338 1383
1339 ino = ip->i_ino; 1384 ino = ip->i_ino;
1340 if ((rc = dtInsert(tid, dir, &dname, &ino, &btstack))) 1385 if ((rc = dtInsert(tid, dir, &dname, &ino, &btstack))) {
1386 txAbort(tid, 0);
1341 goto out3; 1387 goto out3;
1388 }
1342 1389
1343 ip->i_op = &jfs_file_inode_operations; 1390 ip->i_op = &jfs_file_inode_operations;
1344 jfs_ip->dev = new_encode_dev(rdev); 1391 jfs_ip->dev = new_encode_dev(rdev);
@@ -1360,6 +1407,7 @@ static int jfs_mknod(struct inode *dir, struct dentry *dentry,
1360 up(&JFS_IP(ip)->commit_sem); 1407 up(&JFS_IP(ip)->commit_sem);
1361 up(&JFS_IP(dir)->commit_sem); 1408 up(&JFS_IP(dir)->commit_sem);
1362 if (rc) { 1409 if (rc) {
1410 free_ea_wmap(ip);
1363 ip->i_nlink = 0; 1411 ip->i_nlink = 0;
1364 iput(ip); 1412 iput(ip);
1365 } else 1413 } else
@@ -1368,11 +1416,6 @@ static int jfs_mknod(struct inode *dir, struct dentry *dentry,
1368 out1: 1416 out1:
1369 free_UCSname(&dname); 1417 free_UCSname(&dname);
1370 1418
1371#ifdef CONFIG_JFS_POSIX_ACL
1372 if (rc == 0)
1373 jfs_init_acl(ip, dir);
1374#endif
1375
1376 out: 1419 out:
1377 jfs_info("jfs_mknod: returning %d", rc); 1420 jfs_info("jfs_mknod: returning %d", rc);
1378 return rc; 1421 return rc;
diff --git a/fs/jfs/xattr.c b/fs/jfs/xattr.c
index 554ec739e4..23aa5066b5 100644
--- a/fs/jfs/xattr.c
+++ b/fs/jfs/xattr.c
@@ -21,6 +21,7 @@
21#include <linux/xattr.h> 21#include <linux/xattr.h>
22#include <linux/posix_acl_xattr.h> 22#include <linux/posix_acl_xattr.h>
23#include <linux/quotaops.h> 23#include <linux/quotaops.h>
24#include <linux/security.h>
24#include "jfs_incore.h" 25#include "jfs_incore.h"
25#include "jfs_superblock.h" 26#include "jfs_superblock.h"
26#include "jfs_dmap.h" 27#include "jfs_dmap.h"
@@ -633,12 +634,12 @@ static void ea_release(struct inode *inode, struct ea_buffer *ea_buf)
633 } 634 }
634} 635}
635 636
636static int ea_put(struct inode *inode, struct ea_buffer *ea_buf, int new_size) 637static int ea_put(tid_t tid, struct inode *inode, struct ea_buffer *ea_buf,
638 int new_size)
637{ 639{
638 struct jfs_inode_info *ji = JFS_IP(inode); 640 struct jfs_inode_info *ji = JFS_IP(inode);
639 unsigned long old_blocks, new_blocks; 641 unsigned long old_blocks, new_blocks;
640 int rc = 0; 642 int rc = 0;
641 tid_t tid;
642 643
643 if (new_size == 0) { 644 if (new_size == 0) {
644 ea_release(inode, ea_buf); 645 ea_release(inode, ea_buf);
@@ -664,9 +665,6 @@ static int ea_put(struct inode *inode, struct ea_buffer *ea_buf, int new_size)
664 if (rc) 665 if (rc)
665 return rc; 666 return rc;
666 667
667 tid = txBegin(inode->i_sb, 0);
668 down(&ji->commit_sem);
669
670 old_blocks = new_blocks = 0; 668 old_blocks = new_blocks = 0;
671 669
672 if (ji->ea.flag & DXD_EXTENT) { 670 if (ji->ea.flag & DXD_EXTENT) {
@@ -695,11 +693,8 @@ static int ea_put(struct inode *inode, struct ea_buffer *ea_buf, int new_size)
695 DQUOT_FREE_BLOCK(inode, old_blocks); 693 DQUOT_FREE_BLOCK(inode, old_blocks);
696 694
697 inode->i_ctime = CURRENT_TIME; 695 inode->i_ctime = CURRENT_TIME;
698 rc = txCommit(tid, 1, &inode, 0);
699 txEnd(tid);
700 up(&ji->commit_sem);
701 696
702 return rc; 697 return 0;
703} 698}
704 699
705/* 700/*
@@ -810,8 +805,8 @@ static int can_set_xattr(struct inode *inode, const char *name,
810 return permission(inode, MAY_WRITE, NULL); 805 return permission(inode, MAY_WRITE, NULL);
811} 806}
812 807
813int __jfs_setxattr(struct inode *inode, const char *name, const void *value, 808int __jfs_setxattr(tid_t tid, struct inode *inode, const char *name,
814 size_t value_len, int flags) 809 const void *value, size_t value_len, int flags)
815{ 810{
816 struct jfs_ea_list *ealist; 811 struct jfs_ea_list *ealist;
817 struct jfs_ea *ea, *old_ea = NULL, *next_ea = NULL; 812 struct jfs_ea *ea, *old_ea = NULL, *next_ea = NULL;
@@ -825,9 +820,6 @@ int __jfs_setxattr(struct inode *inode, const char *name, const void *value,
825 int rc; 820 int rc;
826 int length; 821 int length;
827 822
828 if ((rc = can_set_xattr(inode, name, value, value_len)))
829 return rc;
830
831 if (strncmp(name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN) == 0) { 823 if (strncmp(name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN) == 0) {
832 os2name = kmalloc(namelen - XATTR_OS2_PREFIX_LEN + 1, 824 os2name = kmalloc(namelen - XATTR_OS2_PREFIX_LEN + 1,
833 GFP_KERNEL); 825 GFP_KERNEL);
@@ -939,7 +931,7 @@ int __jfs_setxattr(struct inode *inode, const char *name, const void *value,
939 931
940 ealist->size = cpu_to_le32(new_size); 932 ealist->size = cpu_to_le32(new_size);
941 933
942 rc = ea_put(inode, &ea_buf, new_size); 934 rc = ea_put(tid, inode, &ea_buf, new_size);
943 935
944 goto out; 936 goto out;
945 release: 937 release:
@@ -955,12 +947,29 @@ int __jfs_setxattr(struct inode *inode, const char *name, const void *value,
955int jfs_setxattr(struct dentry *dentry, const char *name, const void *value, 947int jfs_setxattr(struct dentry *dentry, const char *name, const void *value,
956 size_t value_len, int flags) 948 size_t value_len, int flags)
957{ 949{
950 struct inode *inode = dentry->d_inode;
951 struct jfs_inode_info *ji = JFS_IP(inode);
952 int rc;
953 tid_t tid;
954
955 if ((rc = can_set_xattr(inode, name, value, value_len)))
956 return rc;
957
958 if (value == NULL) { /* empty EA, do not remove */ 958 if (value == NULL) { /* empty EA, do not remove */
959 value = ""; 959 value = "";
960 value_len = 0; 960 value_len = 0;
961 } 961 }
962 962
963 return __jfs_setxattr(dentry->d_inode, name, value, value_len, flags); 963 tid = txBegin(inode->i_sb, 0);
964 down(&ji->commit_sem);
965 rc = __jfs_setxattr(tid, dentry->d_inode, name, value, value_len,
966 flags);
967 if (!rc)
968 rc = txCommit(tid, 1, &inode, 0);
969 txEnd(tid);
970 up(&ji->commit_sem);
971
972 return rc;
964} 973}
965 974
966static int can_get_xattr(struct inode *inode, const char *name) 975static int can_get_xattr(struct inode *inode, const char *name)
@@ -1122,5 +1131,56 @@ ssize_t jfs_listxattr(struct dentry * dentry, char *data, size_t buf_size)
1122 1131
1123int jfs_removexattr(struct dentry *dentry, const char *name) 1132int jfs_removexattr(struct dentry *dentry, const char *name)
1124{ 1133{
1125 return __jfs_setxattr(dentry->d_inode, name, NULL, 0, XATTR_REPLACE); 1134 struct inode *inode = dentry->d_inode;
1135 struct jfs_inode_info *ji = JFS_IP(inode);
1136 int rc;
1137 tid_t tid;
1138
1139 if ((rc = can_set_xattr(inode, name, NULL, 0)))
1140 return rc;
1141
1142 tid = txBegin(inode->i_sb, 0);
1143 down(&ji->commit_sem);
1144 rc = __jfs_setxattr(tid, dentry->d_inode, name, NULL, 0, XATTR_REPLACE);
1145 if (!rc)
1146 rc = txCommit(tid, 1, &inode, 0);
1147 txEnd(tid);
1148 up(&ji->commit_sem);
1149
1150 return rc;
1151}
1152
1153#ifdef CONFIG_JFS_SECURITY
1154int jfs_init_security(tid_t tid, struct inode *inode, struct inode *dir)
1155{
1156 int rc;
1157 size_t len;
1158 void *value;
1159 char *suffix;
1160 char *name;
1161
1162 rc = security_inode_init_security(inode, dir, &suffix, &value, &len);
1163 if (rc) {
1164 if (rc == -EOPNOTSUPP)
1165 return 0;
1166 return rc;
1167 }
1168 name = kmalloc(XATTR_SECURITY_PREFIX_LEN + 1 + strlen(suffix),
1169 GFP_NOFS);
1170 if (!name) {
1171 rc = -ENOMEM;
1172 goto kmalloc_failed;
1173 }
1174 strcpy(name, XATTR_SECURITY_PREFIX);
1175 strcpy(name + XATTR_SECURITY_PREFIX_LEN, suffix);
1176
1177 rc = __jfs_setxattr(tid, inode, name, value, len, 0);
1178
1179 kfree(name);
1180kmalloc_failed:
1181 kfree(suffix);
1182 kfree(value);
1183
1184 return rc;
1126} 1185}
1186#endif
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c
index 14b3ce87fa..87332f3014 100644
--- a/fs/lockd/clntproc.c
+++ b/fs/lockd/clntproc.c
@@ -299,8 +299,7 @@ nlmclnt_alloc_call(void)
299 return call; 299 return call;
300 } 300 }
301 printk("nlmclnt_alloc_call: failed, waiting for memory\n"); 301 printk("nlmclnt_alloc_call: failed, waiting for memory\n");
302 current->state = TASK_INTERRUPTIBLE; 302 schedule_timeout_interruptible(5*HZ);
303 schedule_timeout(5*HZ);
304 } 303 }
305 return NULL; 304 return NULL;
306} 305}
diff --git a/fs/locks.c b/fs/locks.c
index 11956b6179..c2c09b4798 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -2198,21 +2198,23 @@ void steal_locks(fl_owner_t from)
2198{ 2198{
2199 struct files_struct *files = current->files; 2199 struct files_struct *files = current->files;
2200 int i, j; 2200 int i, j;
2201 struct fdtable *fdt;
2201 2202
2202 if (from == files) 2203 if (from == files)
2203 return; 2204 return;
2204 2205
2205 lock_kernel(); 2206 lock_kernel();
2206 j = 0; 2207 j = 0;
2208 fdt = files_fdtable(files);
2207 for (;;) { 2209 for (;;) {
2208 unsigned long set; 2210 unsigned long set;
2209 i = j * __NFDBITS; 2211 i = j * __NFDBITS;
2210 if (i >= files->max_fdset || i >= files->max_fds) 2212 if (i >= fdt->max_fdset || i >= fdt->max_fds)
2211 break; 2213 break;
2212 set = files->open_fds->fds_bits[j++]; 2214 set = fdt->open_fds->fds_bits[j++];
2213 while (set) { 2215 while (set) {
2214 if (set & 1) { 2216 if (set & 1) {
2215 struct file *file = files->fd[i]; 2217 struct file *file = fdt->fd[i];
2216 if (file) 2218 if (file)
2217 __steal_locks(file, from); 2219 __steal_locks(file, from);
2218 } 2220 }
diff --git a/fs/minix/inode.c b/fs/minix/inode.c
index 3f18c21198..790cc0d0e9 100644
--- a/fs/minix/inode.c
+++ b/fs/minix/inode.c
@@ -24,6 +24,7 @@ static int minix_remount (struct super_block * sb, int * flags, char * data);
24 24
25static void minix_delete_inode(struct inode *inode) 25static void minix_delete_inode(struct inode *inode)
26{ 26{
27 truncate_inode_pages(&inode->i_data, 0);
27 inode->i_size = 0; 28 inode->i_size = 0;
28 minix_truncate(inode); 29 minix_truncate(inode);
29 minix_free_inode(inode); 30 minix_free_inode(inode);
diff --git a/fs/namei.c b/fs/namei.c
index 145e852c4b..21d85f1ac8 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1316,10 +1316,8 @@ int vfs_create(struct inode *dir, struct dentry *dentry, int mode,
1316 return error; 1316 return error;
1317 DQUOT_INIT(dir); 1317 DQUOT_INIT(dir);
1318 error = dir->i_op->create(dir, dentry, mode, nd); 1318 error = dir->i_op->create(dir, dentry, mode, nd);
1319 if (!error) { 1319 if (!error)
1320 fsnotify_create(dir, dentry->d_name.name); 1320 fsnotify_create(dir, dentry->d_name.name);
1321 security_inode_post_create(dir, dentry, mode);
1322 }
1323 return error; 1321 return error;
1324} 1322}
1325 1323
@@ -1635,10 +1633,8 @@ int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
1635 1633
1636 DQUOT_INIT(dir); 1634 DQUOT_INIT(dir);
1637 error = dir->i_op->mknod(dir, dentry, mode, dev); 1635 error = dir->i_op->mknod(dir, dentry, mode, dev);
1638 if (!error) { 1636 if (!error)
1639 fsnotify_create(dir, dentry->d_name.name); 1637 fsnotify_create(dir, dentry->d_name.name);
1640 security_inode_post_mknod(dir, dentry, mode, dev);
1641 }
1642 return error; 1638 return error;
1643} 1639}
1644 1640
@@ -1708,10 +1704,8 @@ int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
1708 1704
1709 DQUOT_INIT(dir); 1705 DQUOT_INIT(dir);
1710 error = dir->i_op->mkdir(dir, dentry, mode); 1706 error = dir->i_op->mkdir(dir, dentry, mode);
1711 if (!error) { 1707 if (!error)
1712 fsnotify_mkdir(dir, dentry->d_name.name); 1708 fsnotify_mkdir(dir, dentry->d_name.name);
1713 security_inode_post_mkdir(dir,dentry, mode);
1714 }
1715 return error; 1709 return error;
1716} 1710}
1717 1711
@@ -1947,10 +1941,8 @@ int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname, i
1947 1941
1948 DQUOT_INIT(dir); 1942 DQUOT_INIT(dir);
1949 error = dir->i_op->symlink(dir, dentry, oldname); 1943 error = dir->i_op->symlink(dir, dentry, oldname);
1950 if (!error) { 1944 if (!error)
1951 fsnotify_create(dir, dentry->d_name.name); 1945 fsnotify_create(dir, dentry->d_name.name);
1952 security_inode_post_symlink(dir, dentry, oldname);
1953 }
1954 return error; 1946 return error;
1955} 1947}
1956 1948
@@ -2020,10 +2012,8 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de
2020 DQUOT_INIT(dir); 2012 DQUOT_INIT(dir);
2021 error = dir->i_op->link(old_dentry, dir, new_dentry); 2013 error = dir->i_op->link(old_dentry, dir, new_dentry);
2022 up(&old_dentry->d_inode->i_sem); 2014 up(&old_dentry->d_inode->i_sem);
2023 if (!error) { 2015 if (!error)
2024 fsnotify_create(dir, new_dentry->d_name.name); 2016 fsnotify_create(dir, new_dentry->d_name.name);
2025 security_inode_post_link(old_dentry, dir, new_dentry);
2026 }
2027 return error; 2017 return error;
2028} 2018}
2029 2019
@@ -2142,11 +2132,8 @@ static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
2142 d_rehash(new_dentry); 2132 d_rehash(new_dentry);
2143 dput(new_dentry); 2133 dput(new_dentry);
2144 } 2134 }
2145 if (!error) { 2135 if (!error)
2146 d_move(old_dentry,new_dentry); 2136 d_move(old_dentry,new_dentry);
2147 security_inode_post_rename(old_dir, old_dentry,
2148 new_dir, new_dentry);
2149 }
2150 return error; 2137 return error;
2151} 2138}
2152 2139
@@ -2172,7 +2159,6 @@ static int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry,
2172 /* The following d_move() should become unconditional */ 2159 /* The following d_move() should become unconditional */
2173 if (!(old_dir->i_sb->s_type->fs_flags & FS_ODD_RENAME)) 2160 if (!(old_dir->i_sb->s_type->fs_flags & FS_ODD_RENAME))
2174 d_move(old_dentry, new_dentry); 2161 d_move(old_dentry, new_dentry);
2175 security_inode_post_rename(old_dir, old_dentry, new_dir, new_dentry);
2176 } 2162 }
2177 if (target) 2163 if (target)
2178 up(&target->i_sem); 2164 up(&target->i_sem);
diff --git a/fs/namespace.c b/fs/namespace.c
index 34156260c9..2fa9fdf7d6 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -537,7 +537,6 @@ lives_below_in_same_fs(struct dentry *d, struct dentry *dentry)
537static struct vfsmount *copy_tree(struct vfsmount *mnt, struct dentry *dentry) 537static struct vfsmount *copy_tree(struct vfsmount *mnt, struct dentry *dentry)
538{ 538{
539 struct vfsmount *res, *p, *q, *r, *s; 539 struct vfsmount *res, *p, *q, *r, *s;
540 struct list_head *h;
541 struct nameidata nd; 540 struct nameidata nd;
542 541
543 res = q = clone_mnt(mnt, dentry); 542 res = q = clone_mnt(mnt, dentry);
@@ -546,8 +545,7 @@ static struct vfsmount *copy_tree(struct vfsmount *mnt, struct dentry *dentry)
546 q->mnt_mountpoint = mnt->mnt_mountpoint; 545 q->mnt_mountpoint = mnt->mnt_mountpoint;
547 546
548 p = mnt; 547 p = mnt;
549 for (h = mnt->mnt_mounts.next; h != &mnt->mnt_mounts; h = h->next) { 548 list_for_each_entry(r, &mnt->mnt_mounts, mnt_child) {
550 r = list_entry(h, struct vfsmount, mnt_child);
551 if (!lives_below_in_same_fs(r->mnt_mountpoint, dentry)) 549 if (!lives_below_in_same_fs(r->mnt_mountpoint, dentry))
552 continue; 550 continue;
553 551
diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c
index 44795d2f4b..8c8839203c 100644
--- a/fs/ncpfs/inode.c
+++ b/fs/ncpfs/inode.c
@@ -286,6 +286,8 @@ ncp_iget(struct super_block *sb, struct ncp_entry_info *info)
286static void 286static void
287ncp_delete_inode(struct inode *inode) 287ncp_delete_inode(struct inode *inode)
288{ 288{
289 truncate_inode_pages(&inode->i_data, 0);
290
289 if (S_ISDIR(inode->i_mode)) { 291 if (S_ISDIR(inode->i_mode)) {
290 DDPRINTK("ncp_delete_inode: put directory %ld\n", inode->i_ino); 292 DDPRINTK("ncp_delete_inode: put directory %ld\n", inode->i_ino);
291 } 293 }
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 541b418327..6922469d6f 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -146,6 +146,8 @@ nfs_delete_inode(struct inode * inode)
146{ 146{
147 dprintk("NFS: delete_inode(%s/%ld)\n", inode->i_sb->s_id, inode->i_ino); 147 dprintk("NFS: delete_inode(%s/%ld)\n", inode->i_sb->s_id, inode->i_ino);
148 148
149 truncate_inode_pages(&inode->i_data, 0);
150
149 nfs_wb_all(inode); 151 nfs_wb_all(inode);
150 /* 152 /*
151 * The following should never happen... 153 * The following should never happen...
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
index 2681485cf2..edc9551404 100644
--- a/fs/nfs/nfs3proc.c
+++ b/fs/nfs/nfs3proc.c
@@ -34,8 +34,7 @@ nfs3_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)
34 res = rpc_call_sync(clnt, msg, flags); 34 res = rpc_call_sync(clnt, msg, flags);
35 if (res != -EJUKEBOX) 35 if (res != -EJUKEBOX)
36 break; 36 break;
37 set_current_state(TASK_INTERRUPTIBLE); 37 schedule_timeout_interruptible(NFS_JUKEBOX_RETRY_TIME);
38 schedule_timeout(NFS_JUKEBOX_RETRY_TIME);
39 res = -ERESTARTSYS; 38 res = -ERESTARTSYS;
40 } while (!signalled()); 39 } while (!signalled());
41 rpc_clnt_sigunmask(clnt, &oldset); 40 rpc_clnt_sigunmask(clnt, &oldset);
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 0c5a308e49..9701ca8c94 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -2418,14 +2418,11 @@ static int nfs4_delay(struct rpc_clnt *clnt, long *timeout)
2418 *timeout = NFS4_POLL_RETRY_MAX; 2418 *timeout = NFS4_POLL_RETRY_MAX;
2419 rpc_clnt_sigmask(clnt, &oldset); 2419 rpc_clnt_sigmask(clnt, &oldset);
2420 if (clnt->cl_intr) { 2420 if (clnt->cl_intr) {
2421 set_current_state(TASK_INTERRUPTIBLE); 2421 schedule_timeout_interruptible(*timeout);
2422 schedule_timeout(*timeout);
2423 if (signalled()) 2422 if (signalled())
2424 res = -ERESTARTSYS; 2423 res = -ERESTARTSYS;
2425 } else { 2424 } else
2426 set_current_state(TASK_UNINTERRUPTIBLE); 2425 schedule_timeout_uninterruptible(*timeout);
2427 schedule_timeout(*timeout);
2428 }
2429 rpc_clnt_sigunmask(clnt, &oldset); 2426 rpc_clnt_sigunmask(clnt, &oldset);
2430 *timeout <<= 1; 2427 *timeout <<= 1;
2431 return res; 2428 return res;
@@ -2578,8 +2575,7 @@ int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4
2578static unsigned long 2575static unsigned long
2579nfs4_set_lock_task_retry(unsigned long timeout) 2576nfs4_set_lock_task_retry(unsigned long timeout)
2580{ 2577{
2581 current->state = TASK_INTERRUPTIBLE; 2578 schedule_timeout_interruptible(timeout);
2582 schedule_timeout(timeout);
2583 timeout <<= 1; 2579 timeout <<= 1;
2584 if (timeout > NFS4_LOCK_MAXTIMEOUT) 2580 if (timeout > NFS4_LOCK_MAXTIMEOUT)
2585 return NFS4_LOCK_MAXTIMEOUT; 2581 return NFS4_LOCK_MAXTIMEOUT;
diff --git a/fs/ntfs/aops.c b/fs/ntfs/aops.c
index 545236414d..b6cc8cf246 100644
--- a/fs/ntfs/aops.c
+++ b/fs/ntfs/aops.c
@@ -27,6 +27,7 @@
27#include <linux/swap.h> 27#include <linux/swap.h>
28#include <linux/buffer_head.h> 28#include <linux/buffer_head.h>
29#include <linux/writeback.h> 29#include <linux/writeback.h>
30#include <linux/bit_spinlock.h>
30 31
31#include "aops.h" 32#include "aops.h"
32#include "attrib.h" 33#include "attrib.h"
diff --git a/fs/open.c b/fs/open.c
index 4ee2dcc31c..2fac58c519 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -24,6 +24,7 @@
24#include <linux/personality.h> 24#include <linux/personality.h>
25#include <linux/pagemap.h> 25#include <linux/pagemap.h>
26#include <linux/syscalls.h> 26#include <linux/syscalls.h>
27#include <linux/rcupdate.h>
27 28
28#include <asm/unistd.h> 29#include <asm/unistd.h>
29 30
@@ -842,14 +843,16 @@ int get_unused_fd(void)
842{ 843{
843 struct files_struct * files = current->files; 844 struct files_struct * files = current->files;
844 int fd, error; 845 int fd, error;
846 struct fdtable *fdt;
845 847
846 error = -EMFILE; 848 error = -EMFILE;
847 spin_lock(&files->file_lock); 849 spin_lock(&files->file_lock);
848 850
849repeat: 851repeat:
850 fd = find_next_zero_bit(files->open_fds->fds_bits, 852 fdt = files_fdtable(files);
851 files->max_fdset, 853 fd = find_next_zero_bit(fdt->open_fds->fds_bits,
852 files->next_fd); 854 fdt->max_fdset,
855 fdt->next_fd);
853 856
854 /* 857 /*
855 * N.B. For clone tasks sharing a files structure, this test 858 * N.B. For clone tasks sharing a files structure, this test
@@ -872,14 +875,14 @@ repeat:
872 goto repeat; 875 goto repeat;
873 } 876 }
874 877
875 FD_SET(fd, files->open_fds); 878 FD_SET(fd, fdt->open_fds);
876 FD_CLR(fd, files->close_on_exec); 879 FD_CLR(fd, fdt->close_on_exec);
877 files->next_fd = fd + 1; 880 fdt->next_fd = fd + 1;
878#if 1 881#if 1
879 /* Sanity check */ 882 /* Sanity check */
880 if (files->fd[fd] != NULL) { 883 if (fdt->fd[fd] != NULL) {
881 printk(KERN_WARNING "get_unused_fd: slot %d not NULL!\n", fd); 884 printk(KERN_WARNING "get_unused_fd: slot %d not NULL!\n", fd);
882 files->fd[fd] = NULL; 885 fdt->fd[fd] = NULL;
883 } 886 }
884#endif 887#endif
885 error = fd; 888 error = fd;
@@ -893,9 +896,10 @@ EXPORT_SYMBOL(get_unused_fd);
893 896
894static inline void __put_unused_fd(struct files_struct *files, unsigned int fd) 897static inline void __put_unused_fd(struct files_struct *files, unsigned int fd)
895{ 898{
896 __FD_CLR(fd, files->open_fds); 899 struct fdtable *fdt = files_fdtable(files);
897 if (fd < files->next_fd) 900 __FD_CLR(fd, fdt->open_fds);
898 files->next_fd = fd; 901 if (fd < fdt->next_fd)
902 fdt->next_fd = fd;
899} 903}
900 904
901void fastcall put_unused_fd(unsigned int fd) 905void fastcall put_unused_fd(unsigned int fd)
@@ -924,10 +928,11 @@ EXPORT_SYMBOL(put_unused_fd);
924void fastcall fd_install(unsigned int fd, struct file * file) 928void fastcall fd_install(unsigned int fd, struct file * file)
925{ 929{
926 struct files_struct *files = current->files; 930 struct files_struct *files = current->files;
931 struct fdtable *fdt;
927 spin_lock(&files->file_lock); 932 spin_lock(&files->file_lock);
928 if (unlikely(files->fd[fd] != NULL)) 933 fdt = files_fdtable(files);
929 BUG(); 934 BUG_ON(fdt->fd[fd] != NULL);
930 files->fd[fd] = file; 935 rcu_assign_pointer(fdt->fd[fd], file);
931 spin_unlock(&files->file_lock); 936 spin_unlock(&files->file_lock);
932} 937}
933 938
@@ -1010,15 +1015,17 @@ asmlinkage long sys_close(unsigned int fd)
1010{ 1015{
1011 struct file * filp; 1016 struct file * filp;
1012 struct files_struct *files = current->files; 1017 struct files_struct *files = current->files;
1018 struct fdtable *fdt;
1013 1019
1014 spin_lock(&files->file_lock); 1020 spin_lock(&files->file_lock);
1015 if (fd >= files->max_fds) 1021 fdt = files_fdtable(files);
1022 if (fd >= fdt->max_fds)
1016 goto out_unlock; 1023 goto out_unlock;
1017 filp = files->fd[fd]; 1024 filp = fdt->fd[fd];
1018 if (!filp) 1025 if (!filp)
1019 goto out_unlock; 1026 goto out_unlock;
1020 files->fd[fd] = NULL; 1027 rcu_assign_pointer(fdt->fd[fd], NULL);
1021 FD_CLR(fd, files->close_on_exec); 1028 FD_CLR(fd, fdt->close_on_exec);
1022 __put_unused_fd(files, fd); 1029 __put_unused_fd(files, fd);
1023 spin_unlock(&files->file_lock); 1030 spin_unlock(&files->file_lock);
1024 return filp_close(filp, files); 1031 return filp_close(filp, files);
diff --git a/fs/pipe.c b/fs/pipe.c
index 2c7a23dde2..66aa0b938d 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -39,7 +39,11 @@ void pipe_wait(struct inode * inode)
39{ 39{
40 DEFINE_WAIT(wait); 40 DEFINE_WAIT(wait);
41 41
42 prepare_to_wait(PIPE_WAIT(*inode), &wait, TASK_INTERRUPTIBLE); 42 /*
43 * Pipes are system-local resources, so sleeping on them
44 * is considered a noninteractive wait:
45 */
46 prepare_to_wait(PIPE_WAIT(*inode), &wait, TASK_INTERRUPTIBLE|TASK_NONINTERACTIVE);
43 up(PIPE_SEM(*inode)); 47 up(PIPE_SEM(*inode));
44 schedule(); 48 schedule();
45 finish_wait(PIPE_WAIT(*inode), &wait); 49 finish_wait(PIPE_WAIT(*inode), &wait);
diff --git a/fs/proc/array.c b/fs/proc/array.c
index 37668fe998..d88d518d30 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -159,6 +159,7 @@ static inline char * task_state(struct task_struct *p, char *buffer)
159{ 159{
160 struct group_info *group_info; 160 struct group_info *group_info;
161 int g; 161 int g;
162 struct fdtable *fdt = NULL;
162 163
163 read_lock(&tasklist_lock); 164 read_lock(&tasklist_lock);
164 buffer += sprintf(buffer, 165 buffer += sprintf(buffer,
@@ -179,10 +180,12 @@ static inline char * task_state(struct task_struct *p, char *buffer)
179 p->gid, p->egid, p->sgid, p->fsgid); 180 p->gid, p->egid, p->sgid, p->fsgid);
180 read_unlock(&tasklist_lock); 181 read_unlock(&tasklist_lock);
181 task_lock(p); 182 task_lock(p);
183 if (p->files)
184 fdt = files_fdtable(p->files);
182 buffer += sprintf(buffer, 185 buffer += sprintf(buffer,
183 "FDSize:\t%d\n" 186 "FDSize:\t%d\n"
184 "Groups:\t", 187 "Groups:\t",
185 p->files ? p->files->max_fds : 0); 188 fdt ? fdt->max_fds : 0);
186 189
187 group_info = p->group_info; 190 group_info = p->group_info;
188 get_group_info(group_info); 191 get_group_info(group_info);
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 84751f3f52..23db452ab4 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -62,6 +62,7 @@
62#include <linux/namespace.h> 62#include <linux/namespace.h>
63#include <linux/mm.h> 63#include <linux/mm.h>
64#include <linux/smp_lock.h> 64#include <linux/smp_lock.h>
65#include <linux/rcupdate.h>
65#include <linux/kallsyms.h> 66#include <linux/kallsyms.h>
66#include <linux/mount.h> 67#include <linux/mount.h>
67#include <linux/security.h> 68#include <linux/security.h>
@@ -283,16 +284,16 @@ static int proc_fd_link(struct inode *inode, struct dentry **dentry, struct vfsm
283 284
284 files = get_files_struct(task); 285 files = get_files_struct(task);
285 if (files) { 286 if (files) {
286 spin_lock(&files->file_lock); 287 rcu_read_lock();
287 file = fcheck_files(files, fd); 288 file = fcheck_files(files, fd);
288 if (file) { 289 if (file) {
289 *mnt = mntget(file->f_vfsmnt); 290 *mnt = mntget(file->f_vfsmnt);
290 *dentry = dget(file->f_dentry); 291 *dentry = dget(file->f_dentry);
291 spin_unlock(&files->file_lock); 292 rcu_read_unlock();
292 put_files_struct(files); 293 put_files_struct(files);
293 return 0; 294 return 0;
294 } 295 }
295 spin_unlock(&files->file_lock); 296 rcu_read_unlock();
296 put_files_struct(files); 297 put_files_struct(files);
297 } 298 }
298 return -ENOENT; 299 return -ENOENT;
@@ -1039,6 +1040,7 @@ static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir)
1039 int retval; 1040 int retval;
1040 char buf[NUMBUF]; 1041 char buf[NUMBUF];
1041 struct files_struct * files; 1042 struct files_struct * files;
1043 struct fdtable *fdt;
1042 1044
1043 retval = -ENOENT; 1045 retval = -ENOENT;
1044 if (!pid_alive(p)) 1046 if (!pid_alive(p))
@@ -1061,15 +1063,16 @@ static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir)
1061 files = get_files_struct(p); 1063 files = get_files_struct(p);
1062 if (!files) 1064 if (!files)
1063 goto out; 1065 goto out;
1064 spin_lock(&files->file_lock); 1066 rcu_read_lock();
1067 fdt = files_fdtable(files);
1065 for (fd = filp->f_pos-2; 1068 for (fd = filp->f_pos-2;
1066 fd < files->max_fds; 1069 fd < fdt->max_fds;
1067 fd++, filp->f_pos++) { 1070 fd++, filp->f_pos++) {
1068 unsigned int i,j; 1071 unsigned int i,j;
1069 1072
1070 if (!fcheck_files(files, fd)) 1073 if (!fcheck_files(files, fd))
1071 continue; 1074 continue;
1072 spin_unlock(&files->file_lock); 1075 rcu_read_unlock();
1073 1076
1074 j = NUMBUF; 1077 j = NUMBUF;
1075 i = fd; 1078 i = fd;
@@ -1081,12 +1084,12 @@ static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir)
1081 1084
1082 ino = fake_ino(tid, PROC_TID_FD_DIR + fd); 1085 ino = fake_ino(tid, PROC_TID_FD_DIR + fd);
1083 if (filldir(dirent, buf+j, NUMBUF-j, fd+2, ino, DT_LNK) < 0) { 1086 if (filldir(dirent, buf+j, NUMBUF-j, fd+2, ino, DT_LNK) < 0) {
1084 spin_lock(&files->file_lock); 1087 rcu_read_lock();
1085 break; 1088 break;
1086 } 1089 }
1087 spin_lock(&files->file_lock); 1090 rcu_read_lock();
1088 } 1091 }
1089 spin_unlock(&files->file_lock); 1092 rcu_read_unlock();
1090 put_files_struct(files); 1093 put_files_struct(files);
1091 } 1094 }
1092out: 1095out:
@@ -1261,9 +1264,9 @@ static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd)
1261 1264
1262 files = get_files_struct(task); 1265 files = get_files_struct(task);
1263 if (files) { 1266 if (files) {
1264 spin_lock(&files->file_lock); 1267 rcu_read_lock();
1265 if (fcheck_files(files, fd)) { 1268 if (fcheck_files(files, fd)) {
1266 spin_unlock(&files->file_lock); 1269 rcu_read_unlock();
1267 put_files_struct(files); 1270 put_files_struct(files);
1268 if (task_dumpable(task)) { 1271 if (task_dumpable(task)) {
1269 inode->i_uid = task->euid; 1272 inode->i_uid = task->euid;
@@ -1275,7 +1278,7 @@ static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd)
1275 security_task_to_inode(task, inode); 1278 security_task_to_inode(task, inode);
1276 return 1; 1279 return 1;
1277 } 1280 }
1278 spin_unlock(&files->file_lock); 1281 rcu_read_unlock();
1279 put_files_struct(files); 1282 put_files_struct(files);
1280 } 1283 }
1281 d_drop(dentry); 1284 d_drop(dentry);
@@ -1367,7 +1370,7 @@ static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry,
1367 if (!files) 1370 if (!files)
1368 goto out_unlock; 1371 goto out_unlock;
1369 inode->i_mode = S_IFLNK; 1372 inode->i_mode = S_IFLNK;
1370 spin_lock(&files->file_lock); 1373 rcu_read_lock();
1371 file = fcheck_files(files, fd); 1374 file = fcheck_files(files, fd);
1372 if (!file) 1375 if (!file)
1373 goto out_unlock2; 1376 goto out_unlock2;
@@ -1375,7 +1378,7 @@ static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry,
1375 inode->i_mode |= S_IRUSR | S_IXUSR; 1378 inode->i_mode |= S_IRUSR | S_IXUSR;
1376 if (file->f_mode & 2) 1379 if (file->f_mode & 2)
1377 inode->i_mode |= S_IWUSR | S_IXUSR; 1380 inode->i_mode |= S_IWUSR | S_IXUSR;
1378 spin_unlock(&files->file_lock); 1381 rcu_read_unlock();
1379 put_files_struct(files); 1382 put_files_struct(files);
1380 inode->i_op = &proc_pid_link_inode_operations; 1383 inode->i_op = &proc_pid_link_inode_operations;
1381 inode->i_size = 64; 1384 inode->i_size = 64;
@@ -1385,7 +1388,7 @@ static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry,
1385 return NULL; 1388 return NULL;
1386 1389
1387out_unlock2: 1390out_unlock2:
1388 spin_unlock(&files->file_lock); 1391 rcu_read_unlock();
1389 put_files_struct(files); 1392 put_files_struct(files);
1390out_unlock: 1393out_unlock:
1391 iput(inode); 1394 iput(inode);
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index 133c286851..effa6c0c46 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -60,6 +60,8 @@ static void proc_delete_inode(struct inode *inode)
60 struct proc_dir_entry *de; 60 struct proc_dir_entry *de;
61 struct task_struct *tsk; 61 struct task_struct *tsk;
62 62
63 truncate_inode_pages(&inode->i_data, 0);
64
63 /* Let go of any associated process */ 65 /* Let go of any associated process */
64 tsk = PROC_I(inode)->task; 66 tsk = PROC_I(inode)->task;
65 if (tsk) 67 if (tsk)
diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c
index b79162a354..80f32911c0 100644
--- a/fs/qnx4/inode.c
+++ b/fs/qnx4/inode.c
@@ -63,6 +63,7 @@ int qnx4_sync_inode(struct inode *inode)
63static void qnx4_delete_inode(struct inode *inode) 63static void qnx4_delete_inode(struct inode *inode)
64{ 64{
65 QNX4DEBUG(("qnx4: deleting inode [%lu]\n", (unsigned long) inode->i_ino)); 65 QNX4DEBUG(("qnx4: deleting inode [%lu]\n", (unsigned long) inode->i_ino));
66 truncate_inode_pages(&inode->i_data, 0);
66 inode->i_size = 0; 67 inode->i_size = 0;
67 qnx4_truncate(inode); 68 qnx4_truncate(inode);
68 lock_kernel(); 69 lock_kernel();
diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c
index ff291c973a..1a8a1bf215 100644
--- a/fs/reiserfs/inode.c
+++ b/fs/reiserfs/inode.c
@@ -33,6 +33,8 @@ void reiserfs_delete_inode(struct inode *inode)
33 2 * REISERFS_QUOTA_INIT_BLOCKS(inode->i_sb); 33 2 * REISERFS_QUOTA_INIT_BLOCKS(inode->i_sb);
34 struct reiserfs_transaction_handle th; 34 struct reiserfs_transaction_handle th;
35 35
36 truncate_inode_pages(&inode->i_data, 0);
37
36 reiserfs_write_lock(inode->i_sb); 38 reiserfs_write_lock(inode->i_sb);
37 39
38 /* The = 0 happens when we abort creating a new inode for some reason like lack of space.. */ 40 /* The = 0 happens when we abort creating a new inode for some reason like lack of space.. */
diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c
index a8e29e9bbb..4b15761434 100644
--- a/fs/reiserfs/journal.c
+++ b/fs/reiserfs/journal.c
@@ -2868,8 +2868,7 @@ static void let_transaction_grow(struct super_block *sb, unsigned long trans_id)
2868 struct reiserfs_journal *journal = SB_JOURNAL(sb); 2868 struct reiserfs_journal *journal = SB_JOURNAL(sb);
2869 unsigned long bcount = journal->j_bcount; 2869 unsigned long bcount = journal->j_bcount;
2870 while (1) { 2870 while (1) {
2871 set_current_state(TASK_UNINTERRUPTIBLE); 2871 schedule_timeout_uninterruptible(1);
2872 schedule_timeout(1);
2873 journal->j_current_jl->j_state |= LIST_COMMIT_PENDING; 2872 journal->j_current_jl->j_state |= LIST_COMMIT_PENDING;
2874 while ((atomic_read(&journal->j_wcount) > 0 || 2873 while ((atomic_read(&journal->j_wcount) > 0 ||
2875 atomic_read(&journal->j_jlock)) && 2874 atomic_read(&journal->j_jlock)) &&
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c
index 6951c35755..44b02fc02e 100644
--- a/fs/reiserfs/super.c
+++ b/fs/reiserfs/super.c
@@ -1934,8 +1934,7 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
1934 if (SB_AP_BITMAP(s)) 1934 if (SB_AP_BITMAP(s))
1935 brelse(SB_AP_BITMAP(s)[j].bh); 1935 brelse(SB_AP_BITMAP(s)[j].bh);
1936 } 1936 }
1937 if (SB_AP_BITMAP(s)) 1937 vfree(SB_AP_BITMAP(s));
1938 vfree(SB_AP_BITMAP(s));
1939 } 1938 }
1940 if (SB_BUFFER_WITH_SB(s)) 1939 if (SB_BUFFER_WITH_SB(s))
1941 brelse(SB_BUFFER_WITH_SB(s)); 1940 brelse(SB_BUFFER_WITH_SB(s));
diff --git a/fs/select.c b/fs/select.c
index b80e7eb0ac..f10a10317d 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -22,6 +22,7 @@
22#include <linux/personality.h> /* for STICKY_TIMEOUTS */ 22#include <linux/personality.h> /* for STICKY_TIMEOUTS */
23#include <linux/file.h> 23#include <linux/file.h>
24#include <linux/fs.h> 24#include <linux/fs.h>
25#include <linux/rcupdate.h>
25 26
26#include <asm/uaccess.h> 27#include <asm/uaccess.h>
27 28
@@ -132,11 +133,13 @@ static int max_select_fd(unsigned long n, fd_set_bits *fds)
132 unsigned long *open_fds; 133 unsigned long *open_fds;
133 unsigned long set; 134 unsigned long set;
134 int max; 135 int max;
136 struct fdtable *fdt;
135 137
136 /* handle last in-complete long-word first */ 138 /* handle last in-complete long-word first */
137 set = ~(~0UL << (n & (__NFDBITS-1))); 139 set = ~(~0UL << (n & (__NFDBITS-1)));
138 n /= __NFDBITS; 140 n /= __NFDBITS;
139 open_fds = current->files->open_fds->fds_bits+n; 141 fdt = files_fdtable(current->files);
142 open_fds = fdt->open_fds->fds_bits+n;
140 max = 0; 143 max = 0;
141 if (set) { 144 if (set) {
142 set &= BITS(fds, n); 145 set &= BITS(fds, n);
@@ -183,9 +186,9 @@ int do_select(int n, fd_set_bits *fds, long *timeout)
183 int retval, i; 186 int retval, i;
184 long __timeout = *timeout; 187 long __timeout = *timeout;
185 188
186 spin_lock(&current->files->file_lock); 189 rcu_read_lock();
187 retval = max_select_fd(n, fds); 190 retval = max_select_fd(n, fds);
188 spin_unlock(&current->files->file_lock); 191 rcu_read_unlock();
189 192
190 if (retval < 0) 193 if (retval < 0)
191 return retval; 194 return retval;
@@ -299,6 +302,7 @@ sys_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp, s
299 char *bits; 302 char *bits;
300 long timeout; 303 long timeout;
301 int ret, size, max_fdset; 304 int ret, size, max_fdset;
305 struct fdtable *fdt;
302 306
303 timeout = MAX_SCHEDULE_TIMEOUT; 307 timeout = MAX_SCHEDULE_TIMEOUT;
304 if (tvp) { 308 if (tvp) {
@@ -326,7 +330,10 @@ sys_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp, s
326 goto out_nofds; 330 goto out_nofds;
327 331
328 /* max_fdset can increase, so grab it once to avoid race */ 332 /* max_fdset can increase, so grab it once to avoid race */
329 max_fdset = current->files->max_fdset; 333 rcu_read_lock();
334 fdt = files_fdtable(current->files);
335 max_fdset = fdt->max_fdset;
336 rcu_read_unlock();
330 if (n > max_fdset) 337 if (n > max_fdset)
331 n = max_fdset; 338 n = max_fdset;
332 339
@@ -464,9 +471,15 @@ asmlinkage long sys_poll(struct pollfd __user * ufds, unsigned int nfds, long ti
464 unsigned int i; 471 unsigned int i;
465 struct poll_list *head; 472 struct poll_list *head;
466 struct poll_list *walk; 473 struct poll_list *walk;
474 struct fdtable *fdt;
475 int max_fdset;
467 476
468 /* Do a sanity check on nfds ... */ 477 /* Do a sanity check on nfds ... */
469 if (nfds > current->files->max_fdset && nfds > OPEN_MAX) 478 rcu_read_lock();
479 fdt = files_fdtable(current->files);
480 max_fdset = fdt->max_fdset;
481 rcu_read_unlock();
482 if (nfds > max_fdset && nfds > OPEN_MAX)
470 return -EINVAL; 483 return -EINVAL;
471 484
472 if (timeout) { 485 if (timeout) {
diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c
index 4765aaac9f..10b994428f 100644
--- a/fs/smbfs/inode.c
+++ b/fs/smbfs/inode.c
@@ -331,6 +331,7 @@ static void
331smb_delete_inode(struct inode *ino) 331smb_delete_inode(struct inode *ino)
332{ 332{
333 DEBUG1("ino=%ld\n", ino->i_ino); 333 DEBUG1("ino=%ld\n", ino->i_ino);
334 truncate_inode_pages(&ino->i_data, 0);
334 lock_kernel(); 335 lock_kernel();
335 if (smb_close(ino)) 336 if (smb_close(ino))
336 PARANOIA("could not close inode %ld\n", ino->i_ino); 337 PARANOIA("could not close inode %ld\n", ino->i_ino);
diff --git a/fs/smbfs/proc.c b/fs/smbfs/proc.c
index 220babe91e..38ab558835 100644
--- a/fs/smbfs/proc.c
+++ b/fs/smbfs/proc.c
@@ -2397,8 +2397,7 @@ smb_proc_readdir_long(struct file *filp, void *dirent, filldir_t filldir,
2397 if (req->rq_rcls == ERRSRV && req->rq_err == ERRerror) { 2397 if (req->rq_rcls == ERRSRV && req->rq_err == ERRerror) {
2398 /* a damn Win95 bug - sometimes it clags if you 2398 /* a damn Win95 bug - sometimes it clags if you
2399 ask it too fast */ 2399 ask it too fast */
2400 current->state = TASK_INTERRUPTIBLE; 2400 schedule_timeout_interruptible(msecs_to_jiffies(200));
2401 schedule_timeout(HZ/5);
2402 continue; 2401 continue;
2403 } 2402 }
2404 2403
diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c
index 0530077d9d..fa33eceb00 100644
--- a/fs/sysv/inode.c
+++ b/fs/sysv/inode.c
@@ -292,6 +292,7 @@ int sysv_sync_inode(struct inode * inode)
292 292
293static void sysv_delete_inode(struct inode *inode) 293static void sysv_delete_inode(struct inode *inode)
294{ 294{
295 truncate_inode_pages(&inode->i_data, 0);
295 inode->i_size = 0; 296 inode->i_size = 0;
296 sysv_truncate(inode); 297 sysv_truncate(inode);
297 lock_kernel(); 298 lock_kernel();
diff --git a/fs/udf/inode.c b/fs/udf/inode.c
index 3d68de39fa..b83890beaa 100644
--- a/fs/udf/inode.c
+++ b/fs/udf/inode.c
@@ -87,6 +87,8 @@ static int udf_get_block(struct inode *, sector_t, struct buffer_head *, int);
87 */ 87 */
88void udf_delete_inode(struct inode * inode) 88void udf_delete_inode(struct inode * inode)
89{ 89{
90 truncate_inode_pages(&inode->i_data, 0);
91
90 if (is_bad_inode(inode)) 92 if (is_bad_inode(inode))
91 goto no_delete; 93 goto no_delete;
92 94
diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c
index 718627ca8b..55f4aa16e3 100644
--- a/fs/ufs/inode.c
+++ b/fs/ufs/inode.c
@@ -804,6 +804,7 @@ int ufs_sync_inode (struct inode *inode)
804 804
805void ufs_delete_inode (struct inode * inode) 805void ufs_delete_inode (struct inode * inode)
806{ 806{
807 truncate_inode_pages(&inode->i_data, 0);
807 /*UFS_I(inode)->i_dtime = CURRENT_TIME;*/ 808 /*UFS_I(inode)->i_dtime = CURRENT_TIME;*/
808 lock_kernel(); 809 lock_kernel();
809 mark_inode_dirty(inode); 810 mark_inode_dirty(inode);
diff --git a/fs/xfs/linux-2.6/time.h b/fs/xfs/linux-2.6/time.h
index 6c6fd0faa8..b0d2873ab2 100644
--- a/fs/xfs/linux-2.6/time.h
+++ b/fs/xfs/linux-2.6/time.h
@@ -39,8 +39,7 @@ typedef struct timespec timespec_t;
39 39
40static inline void delay(long ticks) 40static inline void delay(long ticks)
41{ 41{
42 set_current_state(TASK_UNINTERRUPTIBLE); 42 schedule_timeout_uninterruptible(ticks);
43 schedule_timeout(ticks);
44} 43}
45 44
46static inline void nanotime(struct timespec *tvp) 45static inline void nanotime(struct timespec *tvp)
diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c
index 655bf4a78a..e82cf72ac5 100644
--- a/fs/xfs/linux-2.6/xfs_buf.c
+++ b/fs/xfs/linux-2.6/xfs_buf.c
@@ -1780,10 +1780,10 @@ xfsbufd(
1780 xfsbufd_force_sleep = 0; 1780 xfsbufd_force_sleep = 0;
1781 } 1781 }
1782 1782
1783 set_current_state(TASK_INTERRUPTIBLE); 1783 schedule_timeout_interruptible
1784 schedule_timeout((xfs_buf_timer_centisecs * HZ) / 100); 1784 (xfs_buf_timer_centisecs * msecs_to_jiffies(10));
1785 1785
1786 age = (xfs_buf_age_centisecs * HZ) / 100; 1786 age = xfs_buf_age_centisecs * msecs_to_jiffies(10);
1787 spin_lock(&pbd_delwrite_lock); 1787 spin_lock(&pbd_delwrite_lock);
1788 list_for_each_entry_safe(pb, n, &pbd_delwrite_queue, pb_list) { 1788 list_for_each_entry_safe(pb, n, &pbd_delwrite_queue, pb_list) {
1789 PB_TRACE(pb, "walkq1", (long)pagebuf_ispin(pb)); 1789 PB_TRACE(pb, "walkq1", (long)pagebuf_ispin(pb));
diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c
index 0da87bfc99..2302454d8d 100644
--- a/fs/xfs/linux-2.6/xfs_super.c
+++ b/fs/xfs/linux-2.6/xfs_super.c
@@ -467,7 +467,7 @@ xfs_flush_inode(
467 467
468 igrab(inode); 468 igrab(inode);
469 xfs_syncd_queue_work(vfs, inode, xfs_flush_inode_work); 469 xfs_syncd_queue_work(vfs, inode, xfs_flush_inode_work);
470 delay(HZ/2); 470 delay(msecs_to_jiffies(500));
471} 471}
472 472
473/* 473/*
@@ -492,7 +492,7 @@ xfs_flush_device(
492 492
493 igrab(inode); 493 igrab(inode);
494 xfs_syncd_queue_work(vfs, inode, xfs_flush_device_work); 494 xfs_syncd_queue_work(vfs, inode, xfs_flush_device_work);
495 delay(HZ/2); 495 delay(msecs_to_jiffies(500));
496 xfs_log_force(ip->i_mount, (xfs_lsn_t)0, XFS_LOG_FORCE|XFS_LOG_SYNC); 496 xfs_log_force(ip->i_mount, (xfs_lsn_t)0, XFS_LOG_FORCE|XFS_LOG_SYNC);
497} 497}
498 498
@@ -520,10 +520,9 @@ xfssyncd(
520 struct vfs_sync_work *work, *n; 520 struct vfs_sync_work *work, *n;
521 LIST_HEAD (tmp); 521 LIST_HEAD (tmp);
522 522
523 timeleft = (xfs_syncd_centisecs * HZ) / 100; 523 timeleft = xfs_syncd_centisecs * msecs_to_jiffies(10);
524 for (;;) { 524 for (;;) {
525 set_current_state(TASK_INTERRUPTIBLE); 525 timeleft = schedule_timeout_interruptible(timeleft);
526 timeleft = schedule_timeout(timeleft);
527 /* swsusp */ 526 /* swsusp */
528 try_to_freeze(); 527 try_to_freeze();
529 if (kthread_should_stop()) 528 if (kthread_should_stop())
@@ -537,7 +536,8 @@ xfssyncd(
537 */ 536 */
538 if (!timeleft || list_empty(&vfsp->vfs_sync_list)) { 537 if (!timeleft || list_empty(&vfsp->vfs_sync_list)) {
539 if (!timeleft) 538 if (!timeleft)
540 timeleft = (xfs_syncd_centisecs * HZ) / 100; 539 timeleft = xfs_syncd_centisecs *
540 msecs_to_jiffies(10);
541 INIT_LIST_HEAD(&vfsp->vfs_sync_work.w_list); 541 INIT_LIST_HEAD(&vfsp->vfs_sync_work.w_list);
542 list_add_tail(&vfsp->vfs_sync_work.w_list, 542 list_add_tail(&vfsp->vfs_sync_work.w_list,
543 &vfsp->vfs_sync_list); 543 &vfsp->vfs_sync_list);
diff --git a/fs/xfs/support/ktrace.c b/fs/xfs/support/ktrace.c
index 3dae14c8c5..fa8394f943 100644
--- a/fs/xfs/support/ktrace.c
+++ b/fs/xfs/support/ktrace.c
@@ -170,7 +170,7 @@ ktrace_enter(
170 void *val14, 170 void *val14,
171 void *val15) 171 void *val15)
172{ 172{
173 static lock_t wrap_lock = SPIN_LOCK_UNLOCKED; 173 static DEFINE_SPINLOCK(wrap_lock);
174 unsigned long flags; 174 unsigned long flags;
175 int index; 175 int index;
176 ktrace_entry_t *ktep; 176 ktrace_entry_t *ktep;