aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/filesystems/9p.txt22
-rw-r--r--drivers/mmc/core/mmc.c3
-rw-r--r--drivers/mmc/host/at91_mci.c4
-rw-r--r--drivers/net/wireless/Kconfig6
-rw-r--r--drivers/net/wireless/libertas/Makefile2
-rw-r--r--drivers/net/wireless/libertas/defs.h2
-rw-r--r--drivers/net/wireless/libertas/if_sdio.c1079
-rw-r--r--drivers/net/wireless/libertas/if_sdio.h45
-rw-r--r--fs/9p/fid.c157
-rw-r--r--fs/9p/v9fs.c189
-rw-r--r--fs/9p/v9fs.h38
-rw-r--r--fs/9p/vfs_file.c6
-rw-r--r--fs/9p/vfs_inode.c50
-rw-r--r--fs/9p/vfs_super.c19
-rw-r--r--include/linux/mmc/sdio_ids.h6
-rw-r--r--include/net/9p/9p.h21
-rw-r--r--include/net/9p/client.h9
-rw-r--r--include/net/9p/conn.h4
-rw-r--r--include/net/9p/transport.h27
-rw-r--r--net/9p/Kconfig10
-rw-r--r--net/9p/Makefile5
-rw-r--r--net/9p/client.c13
-rw-r--r--net/9p/conv.c32
-rw-r--r--net/9p/mod.c71
-rw-r--r--net/9p/mux.c5
-rw-r--r--net/9p/sysctl.c81
-rw-r--r--net/9p/trans_fd.c419
27 files changed, 1832 insertions, 493 deletions
diff --git a/Documentation/filesystems/9p.txt b/Documentation/filesystems/9p.txt
index cda6905cbe49..d6fd6c6e4244 100644
--- a/Documentation/filesystems/9p.txt
+++ b/Documentation/filesystems/9p.txt
@@ -35,12 +35,12 @@ For remote file server:
35 35
36For Plan 9 From User Space applications (http://swtch.com/plan9) 36For Plan 9 From User Space applications (http://swtch.com/plan9)
37 37
38 mount -t 9p `namespace`/acme /mnt/9 -o proto=unix,uname=$USER 38 mount -t 9p `namespace`/acme /mnt/9 -o trans=unix,uname=$USER
39 39
40OPTIONS 40OPTIONS
41======= 41=======
42 42
43 proto=name select an alternative transport. Valid options are 43 trans=name select an alternative transport. Valid options are
44 currently: 44 currently:
45 unix - specifying a named pipe mount point 45 unix - specifying a named pipe mount point
46 tcp - specifying a normal TCP/IP connection 46 tcp - specifying a normal TCP/IP connection
@@ -68,9 +68,9 @@ OPTIONS
68 0x40 = display transport debug 68 0x40 = display transport debug
69 0x80 = display allocation debug 69 0x80 = display allocation debug
70 70
71 rfdno=n the file descriptor for reading with proto=fd 71 rfdno=n the file descriptor for reading with trans=fd
72 72
73 wfdno=n the file descriptor for writing with proto=fd 73 wfdno=n the file descriptor for writing with trans=fd
74 74
75 maxdata=n the number of bytes to use for 9p packet payload (msize) 75 maxdata=n the number of bytes to use for 9p packet payload (msize)
76 76
@@ -78,9 +78,9 @@ OPTIONS
78 78
79 noextend force legacy mode (no 9p2000.u semantics) 79 noextend force legacy mode (no 9p2000.u semantics)
80 80
81 uid attempt to mount as a particular uid 81 dfltuid attempt to mount as a particular uid
82 82
83 gid attempt to mount with a particular gid 83 dfltgid attempt to mount with a particular gid
84 84
85 afid security channel - used by Plan 9 authentication protocols 85 afid security channel - used by Plan 9 authentication protocols
86 86
@@ -88,6 +88,16 @@ OPTIONS
88 This can be used to share devices/named pipes/sockets between 88 This can be used to share devices/named pipes/sockets between
89 hosts. This functionality will be expanded in later versions. 89 hosts. This functionality will be expanded in later versions.
90 90
91 access there are three access modes.
92 user = if a user tries to access a file on v9fs
93 filesystem for the first time, v9fs sends an
94 attach command (Tattach) for that user.
95 This is the default mode.
96 <uid> = allows only user with uid=<uid> to access
97 the files on the mounted filesystem
98 any = v9fs does single attach and performs all
99 operations as one user
100
91RESOURCES 101RESOURCES
92========= 102=========
93 103
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 65fe28860f54..68c0e3b2f0e8 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -213,7 +213,8 @@ static int mmc_read_ext_csd(struct mmc_card *card)
213 printk(KERN_ERR "%s: unrecognised EXT_CSD structure " 213 printk(KERN_ERR "%s: unrecognised EXT_CSD structure "
214 "version %d\n", mmc_hostname(card->host), 214 "version %d\n", mmc_hostname(card->host),
215 ext_csd_struct); 215 ext_csd_struct);
216 return -EINVAL; 216 err = -EINVAL;
217 goto out;
217 } 218 }
218 219
219 if (ext_csd_struct >= 2) { 220 if (ext_csd_struct >= 2) {
diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c
index 6ba98a49612d..7a452c2ad1f9 100644
--- a/drivers/mmc/host/at91_mci.c
+++ b/drivers/mmc/host/at91_mci.c
@@ -581,9 +581,7 @@ static void at91_mci_completed_command(struct at91mci_host *host)
581 pr_debug("Status = %08X [%08X %08X %08X %08X]\n", 581 pr_debug("Status = %08X [%08X %08X %08X %08X]\n",
582 status, cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]); 582 status, cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
583 583
584 if (status & (AT91_MCI_RINDE | AT91_MCI_RDIRE | AT91_MCI_RCRCE | 584 if (status & AT91_MCI_ERRORS) {
585 AT91_MCI_RENDE | AT91_MCI_RTOE | AT91_MCI_DCRCE |
586 AT91_MCI_DTOE | AT91_MCI_OVRE | AT91_MCI_UNRE)) {
587 if ((status & AT91_MCI_RCRCE) && !(mmc_resp_type(cmd) & MMC_RSP_CRC)) { 585 if ((status & AT91_MCI_RCRCE) && !(mmc_resp_type(cmd) & MMC_RSP_CRC)) {
588 cmd->error = 0; 586 cmd->error = 0;
589 } 587 }
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 5a6fdfd0f140..dae5c8d5a318 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -282,6 +282,12 @@ config LIBERTAS_CS
282 ---help--- 282 ---help---
283 A driver for Marvell Libertas 8385 CompactFlash devices. 283 A driver for Marvell Libertas 8385 CompactFlash devices.
284 284
285config LIBERTAS_SDIO
286 tristate "Marvell Libertas 8385 and 8686 SDIO 802.11b/g cards"
287 depends on LIBERTAS && MMC
288 ---help---
289 A driver for Marvell Libertas 8385 and 8686 SDIO devices.
290
285config LIBERTAS_DEBUG 291config LIBERTAS_DEBUG
286 bool "Enable full debugging output in the Libertas module." 292 bool "Enable full debugging output in the Libertas module."
287 depends on LIBERTAS 293 depends on LIBERTAS
diff --git a/drivers/net/wireless/libertas/Makefile b/drivers/net/wireless/libertas/Makefile
index c469d569f090..0e2787691f96 100644
--- a/drivers/net/wireless/libertas/Makefile
+++ b/drivers/net/wireless/libertas/Makefile
@@ -7,7 +7,9 @@ libertas-objs := main.o wext.o \
7 7
8usb8xxx-objs += if_usb.o 8usb8xxx-objs += if_usb.o
9libertas_cs-objs += if_cs.o 9libertas_cs-objs += if_cs.o
10libertas_sdio-objs += if_sdio.o
10 11
11obj-$(CONFIG_LIBERTAS) += libertas.o 12obj-$(CONFIG_LIBERTAS) += libertas.o
12obj-$(CONFIG_LIBERTAS_USB) += usb8xxx.o 13obj-$(CONFIG_LIBERTAS_USB) += usb8xxx.o
13obj-$(CONFIG_LIBERTAS_CS) += libertas_cs.o 14obj-$(CONFIG_LIBERTAS_CS) += libertas_cs.o
15obj-$(CONFIG_LIBERTAS_SDIO) += libertas_sdio.o
diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h
index 7c5b7f7b45db..3a0c9beefcf8 100644
--- a/drivers/net/wireless/libertas/defs.h
+++ b/drivers/net/wireless/libertas/defs.h
@@ -39,6 +39,7 @@
39#define LBS_DEB_FW 0x00080000 39#define LBS_DEB_FW 0x00080000
40#define LBS_DEB_THREAD 0x00100000 40#define LBS_DEB_THREAD 0x00100000
41#define LBS_DEB_HEX 0x00200000 41#define LBS_DEB_HEX 0x00200000
42#define LBS_DEB_SDIO 0x00400000
42 43
43extern unsigned int libertas_debug; 44extern unsigned int libertas_debug;
44 45
@@ -80,6 +81,7 @@ do { if ((libertas_debug & (grp)) == (grp)) \
80#define lbs_deb_usbd(dev, fmt, args...) LBS_DEB_LL(LBS_DEB_USB, " usbd", "%s:" fmt, (dev)->bus_id, ##args) 81#define lbs_deb_usbd(dev, fmt, args...) LBS_DEB_LL(LBS_DEB_USB, " usbd", "%s:" fmt, (dev)->bus_id, ##args)
81#define lbs_deb_cs(fmt, args...) LBS_DEB_LL(LBS_DEB_CS, " cs", fmt, ##args) 82#define lbs_deb_cs(fmt, args...) LBS_DEB_LL(LBS_DEB_CS, " cs", fmt, ##args)
82#define lbs_deb_thread(fmt, args...) LBS_DEB_LL(LBS_DEB_THREAD, " thread", fmt, ##args) 83#define lbs_deb_thread(fmt, args...) LBS_DEB_LL(LBS_DEB_THREAD, " thread", fmt, ##args)
84#define lbs_deb_sdio(fmt, args...) LBS_DEB_LL(LBS_DEB_SDIO, " thread", fmt, ##args)
83 85
84#define lbs_pr_info(format, args...) \ 86#define lbs_pr_info(format, args...) \
85 printk(KERN_INFO DRV_NAME": " format, ## args) 87 printk(KERN_INFO DRV_NAME": " format, ## args)
diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c
new file mode 100644
index 000000000000..a8e17076e7de
--- /dev/null
+++ b/drivers/net/wireless/libertas/if_sdio.c
@@ -0,0 +1,1079 @@
1/*
2 * linux/drivers/net/wireless/libertas/if_sdio.c
3 *
4 * Copyright 2007 Pierre Ossman
5 *
6 * Inspired by if_cs.c, Copyright 2007 Holger Schurig
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 (at
11 * your option) any later version.
12 *
13 * This hardware has more or less no CMD53 support, so all registers
14 * must be accessed using sdio_readb()/sdio_writeb().
15 *
16 * Transfers must be in one transaction or the firmware goes bonkers.
17 * This means that the transfer must either be small enough to do a
18 * byte based transfer or it must be padded to a multiple of the
19 * current block size.
20 *
21 * As SDIO is still new to the kernel, it is unfortunately common with
22 * bugs in the host controllers related to that. One such bug is that
23 * controllers cannot do transfers that aren't a multiple of 4 bytes.
24 * If you don't have time to fix the host controller driver, you can
25 * work around the problem by modifying if_sdio_host_to_card() and
26 * if_sdio_card_to_host() to pad the data.
27 */
28
29#include <linux/moduleparam.h>
30#include <linux/firmware.h>
31#include <linux/netdevice.h>
32#include <linux/delay.h>
33#include <linux/mmc/card.h>
34#include <linux/mmc/sdio_func.h>
35#include <linux/mmc/sdio_ids.h>
36
37#include "host.h"
38#include "decl.h"
39#include "defs.h"
40#include "dev.h"
41#include "if_sdio.h"
42
43static char *libertas_helper_name = NULL;
44module_param_named(helper_name, libertas_helper_name, charp, 0644);
45
46static char *libertas_fw_name = NULL;
47module_param_named(fw_name, libertas_fw_name, charp, 0644);
48
49static const struct sdio_device_id if_sdio_ids[] = {
50 { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_LIBERTAS) },
51 { /* end: all zeroes */ },
52};
53
54MODULE_DEVICE_TABLE(sdio, if_sdio_ids);
55
56struct if_sdio_model {
57 int model;
58 const char *helper;
59 const char *firmware;
60};
61
62static struct if_sdio_model if_sdio_models[] = {
63 {
64 /* 8385 */
65 .model = 0x04,
66 .helper = "sd8385_helper.bin",
67 .firmware = "sd8385.bin",
68 },
69 {
70 /* 8686 */
71 .model = 0x0B,
72 .helper = "sd8686_helper.bin",
73 .firmware = "sd8686.bin",
74 },
75};
76
77struct if_sdio_packet {
78 struct if_sdio_packet *next;
79 u16 nb;
80 u8 buffer[0] __attribute__((aligned(4)));
81};
82
83struct if_sdio_card {
84 struct sdio_func *func;
85 wlan_private *priv;
86
87 int model;
88 unsigned long ioport;
89
90 const char *helper;
91 const char *firmware;
92
93 u8 buffer[65536];
94 u8 int_cause;
95 u32 event;
96
97 spinlock_t lock;
98 struct if_sdio_packet *packets;
99 struct work_struct packet_worker;
100};
101
102/********************************************************************/
103/* I/O */
104/********************************************************************/
105
106static u16 if_sdio_read_scratch(struct if_sdio_card *card, int *err)
107{
108 int ret, reg;
109 u16 scratch;
110
111 if (card->model == 0x04)
112 reg = IF_SDIO_SCRATCH_OLD;
113 else
114 reg = IF_SDIO_SCRATCH;
115
116 scratch = sdio_readb(card->func, reg, &ret);
117 if (!ret)
118 scratch |= sdio_readb(card->func, reg + 1, &ret) << 8;
119
120 if (err)
121 *err = ret;
122
123 if (ret)
124 return 0xffff;
125
126 return scratch;
127}
128
129static int if_sdio_handle_cmd(struct if_sdio_card *card,
130 u8 *buffer, unsigned size)
131{
132 int ret;
133 unsigned long flags;
134
135 lbs_deb_enter(LBS_DEB_SDIO);
136
137 spin_lock_irqsave(&card->priv->adapter->driver_lock, flags);
138
139 if (!card->priv->adapter->cur_cmd) {
140 lbs_deb_sdio("discarding spurious response\n");
141 ret = 0;
142 goto out;
143 }
144
145 if (size > MRVDRV_SIZE_OF_CMD_BUFFER) {
146 lbs_deb_sdio("response packet too large (%d bytes)\n",
147 (int)size);
148 ret = -E2BIG;
149 goto out;
150 }
151
152 memcpy(card->priv->adapter->cur_cmd->bufvirtualaddr, buffer, size);
153 card->priv->upld_len = size;
154
155 card->int_cause |= MRVDRV_CMD_UPLD_RDY;
156
157 libertas_interrupt(card->priv->dev);
158
159 ret = 0;
160
161out:
162 spin_unlock_irqrestore(&card->priv->adapter->driver_lock, flags);
163
164 lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
165
166 return ret;
167}
168
169static int if_sdio_handle_data(struct if_sdio_card *card,
170 u8 *buffer, unsigned size)
171{
172 int ret;
173 struct sk_buff *skb;
174 char *data;
175
176 lbs_deb_enter(LBS_DEB_SDIO);
177
178 if (size > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) {
179 lbs_deb_sdio("response packet too large (%d bytes)\n",
180 (int)size);
181 ret = -E2BIG;
182 goto out;
183 }
184
185 skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE);
186 if (!skb) {
187 ret = -ENOMEM;
188 goto out;
189 }
190
191 data = skb_put(skb, size);
192
193 memcpy(data, buffer, size);
194
195 libertas_process_rxed_packet(card->priv, skb);
196
197 ret = 0;
198
199out:
200 lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
201
202 return ret;
203}
204
205static int if_sdio_handle_event(struct if_sdio_card *card,
206 u8 *buffer, unsigned size)
207{
208 int ret;
209 unsigned long flags;
210 u32 event;
211
212 lbs_deb_enter(LBS_DEB_SDIO);
213
214 if (card->model == 0x04) {
215 event = sdio_readb(card->func, IF_SDIO_EVENT, &ret);
216 if (ret)
217 goto out;
218 } else {
219 if (size < 4) {
220 lbs_deb_sdio("event packet too small (%d bytes)\n",
221 (int)size);
222 ret = -EINVAL;
223 goto out;
224 }
225 event = buffer[3] << 24;
226 event |= buffer[2] << 16;
227 event |= buffer[1] << 8;
228 event |= buffer[0] << 0;
229 event <<= SBI_EVENT_CAUSE_SHIFT;
230 }
231
232 spin_lock_irqsave(&card->priv->adapter->driver_lock, flags);
233
234 card->event = event;
235 card->int_cause |= MRVDRV_CARDEVENT;
236
237 libertas_interrupt(card->priv->dev);
238
239 spin_unlock_irqrestore(&card->priv->adapter->driver_lock, flags);
240
241 ret = 0;
242
243out:
244 lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
245
246 return ret;
247}
248
249static int if_sdio_card_to_host(struct if_sdio_card *card)
250{
251 int ret;
252 u8 status;
253 u16 size, type, chunk;
254 unsigned long timeout;
255
256 lbs_deb_enter(LBS_DEB_SDIO);
257
258 size = if_sdio_read_scratch(card, &ret);
259 if (ret)
260 goto out;
261
262 if (size < 4) {
263 lbs_deb_sdio("invalid packet size (%d bytes) from firmware\n",
264 (int)size);
265 ret = -EINVAL;
266 goto out;
267 }
268
269 timeout = jiffies + HZ;
270 while (1) {
271 status = sdio_readb(card->func, IF_SDIO_STATUS, &ret);
272 if (ret)
273 goto out;
274 if (status & IF_SDIO_IO_RDY)
275 break;
276 if (time_after(jiffies, timeout)) {
277 ret = -ETIMEDOUT;
278 goto out;
279 }
280 mdelay(1);
281 }
282
283 /*
284 * The transfer must be in one transaction or the firmware
285 * goes suicidal.
286 */
287 chunk = size;
288 if ((chunk > card->func->cur_blksize) || (chunk > 512)) {
289 chunk = (chunk + card->func->cur_blksize - 1) /
290 card->func->cur_blksize * card->func->cur_blksize;
291 }
292
293 ret = sdio_readsb(card->func, card->buffer, card->ioport, chunk);
294 if (ret)
295 goto out;
296
297 chunk = card->buffer[0] | (card->buffer[1] << 8);
298 type = card->buffer[2] | (card->buffer[3] << 8);
299
300 lbs_deb_sdio("packet of type %d and size %d bytes\n",
301 (int)type, (int)chunk);
302
303 if (chunk > size) {
304 lbs_deb_sdio("packet fragment (%d > %d)\n",
305 (int)chunk, (int)size);
306 ret = -EINVAL;
307 goto out;
308 }
309
310 if (chunk < size) {
311 lbs_deb_sdio("packet fragment (%d < %d)\n",
312 (int)chunk, (int)size);
313 }
314
315 switch (type) {
316 case MVMS_CMD:
317 ret = if_sdio_handle_cmd(card, card->buffer + 4, chunk - 4);
318 if (ret)
319 goto out;
320 break;
321 case MVMS_DAT:
322 ret = if_sdio_handle_data(card, card->buffer + 4, chunk - 4);
323 if (ret)
324 goto out;
325 break;
326 case MVMS_EVENT:
327 ret = if_sdio_handle_event(card, card->buffer + 4, chunk - 4);
328 if (ret)
329 goto out;
330 break;
331 default:
332 lbs_deb_sdio("invalid type (%d) from firmware\n",
333 (int)type);
334 ret = -EINVAL;
335 goto out;
336 }
337
338out:
339 if (ret)
340 lbs_pr_err("problem fetching packet from firmware\n");
341
342 lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
343
344 return ret;
345}
346
347static void if_sdio_host_to_card_worker(struct work_struct *work)
348{
349 struct if_sdio_card *card;
350 struct if_sdio_packet *packet;
351 unsigned long timeout;
352 u8 status;
353 int ret;
354 unsigned long flags;
355
356 lbs_deb_enter(LBS_DEB_SDIO);
357
358 card = container_of(work, struct if_sdio_card, packet_worker);
359
360 while (1) {
361 spin_lock_irqsave(&card->lock, flags);
362 packet = card->packets;
363 if (packet)
364 card->packets = packet->next;
365 spin_unlock_irqrestore(&card->lock, flags);
366
367 if (!packet)
368 break;
369
370 sdio_claim_host(card->func);
371
372 timeout = jiffies + HZ;
373 while (1) {
374 status = sdio_readb(card->func, IF_SDIO_STATUS, &ret);
375 if (ret)
376 goto release;
377 if (status & IF_SDIO_IO_RDY)
378 break;
379 if (time_after(jiffies, timeout)) {
380 ret = -ETIMEDOUT;
381 goto release;
382 }
383 mdelay(1);
384 }
385
386 ret = sdio_writesb(card->func, card->ioport,
387 packet->buffer, packet->nb);
388 if (ret)
389 goto release;
390release:
391 sdio_release_host(card->func);
392
393 kfree(packet);
394 }
395
396 lbs_deb_leave(LBS_DEB_SDIO);
397}
398
399/********************************************************************/
400/* Firmware */
401/********************************************************************/
402
403static int if_sdio_prog_helper(struct if_sdio_card *card)
404{
405 int ret;
406 u8 status;
407 const struct firmware *fw;
408 unsigned long timeout;
409 u8 *chunk_buffer;
410 u32 chunk_size;
411 u8 *firmware;
412 size_t size;
413
414 lbs_deb_enter(LBS_DEB_SDIO);
415
416 ret = request_firmware(&fw, card->helper, &card->func->dev);
417 if (ret) {
418 lbs_pr_err("can't load helper firmware\n");
419 goto out;
420 }
421
422 chunk_buffer = kzalloc(64, GFP_KERNEL);
423 if (!chunk_buffer) {
424 ret = -ENOMEM;
425 goto release_fw;
426 }
427
428 sdio_claim_host(card->func);
429
430 ret = sdio_set_block_size(card->func, 32);
431 if (ret)
432 goto release;
433
434 firmware = fw->data;
435 size = fw->size;
436
437 while (size) {
438 timeout = jiffies + HZ;
439 while (1) {
440 status = sdio_readb(card->func, IF_SDIO_STATUS, &ret);
441 if (ret)
442 goto release;
443 if ((status & IF_SDIO_IO_RDY) &&
444 (status & IF_SDIO_DL_RDY))
445 break;
446 if (time_after(jiffies, timeout)) {
447 ret = -ETIMEDOUT;
448 goto release;
449 }
450 mdelay(1);
451 }
452
453 chunk_size = min(size, (size_t)60);
454
455 *((u32*)chunk_buffer) = cpu_to_le32(chunk_size);
456 memcpy(chunk_buffer + 4, firmware, chunk_size);
457/*
458 lbs_deb_sdio("sending %d bytes chunk\n", chunk_size);
459*/
460 ret = sdio_writesb(card->func, card->ioport,
461 chunk_buffer, 64);
462 if (ret)
463 goto release;
464
465 firmware += chunk_size;
466 size -= chunk_size;
467 }
468
469 /* an empty block marks the end of the transfer */
470 memset(chunk_buffer, 0, 4);
471 ret = sdio_writesb(card->func, card->ioport, chunk_buffer, 64);
472 if (ret)
473 goto release;
474
475 lbs_deb_sdio("waiting for helper to boot...\n");
476
477 /* wait for the helper to boot by looking at the size register */
478 timeout = jiffies + HZ;
479 while (1) {
480 u16 req_size;
481
482 req_size = sdio_readb(card->func, IF_SDIO_RD_BASE, &ret);
483 if (ret)
484 goto release;
485
486 req_size |= sdio_readb(card->func, IF_SDIO_RD_BASE + 1, &ret) << 8;
487 if (ret)
488 goto release;
489
490 if (req_size != 0)
491 break;
492
493 if (time_after(jiffies, timeout)) {
494 ret = -ETIMEDOUT;
495 goto release;
496 }
497
498 msleep(10);
499 }
500
501 ret = 0;
502
503release:
504 sdio_set_block_size(card->func, 0);
505 sdio_release_host(card->func);
506 kfree(chunk_buffer);
507release_fw:
508 release_firmware(fw);
509
510out:
511 if (ret)
512 lbs_pr_err("failed to load helper firmware\n");
513
514 lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
515
516 return ret;
517}
518
519static int if_sdio_prog_real(struct if_sdio_card *card)
520{
521 int ret;
522 u8 status;
523 const struct firmware *fw;
524 unsigned long timeout;
525 u8 *chunk_buffer;
526 u32 chunk_size;
527 u8 *firmware;
528 size_t size, req_size;
529
530 lbs_deb_enter(LBS_DEB_SDIO);
531
532 ret = request_firmware(&fw, card->firmware, &card->func->dev);
533 if (ret) {
534 lbs_pr_err("can't load firmware\n");
535 goto out;
536 }
537
538 chunk_buffer = kzalloc(512, GFP_KERNEL);
539 if (!chunk_buffer) {
540 ret = -ENOMEM;
541 goto release_fw;
542 }
543
544 sdio_claim_host(card->func);
545
546 ret = sdio_set_block_size(card->func, 32);
547 if (ret)
548 goto release;
549
550 firmware = fw->data;
551 size = fw->size;
552
553 while (size) {
554 timeout = jiffies + HZ;
555 while (1) {
556 status = sdio_readb(card->func, IF_SDIO_STATUS, &ret);
557 if (ret)
558 goto release;
559 if ((status & IF_SDIO_IO_RDY) &&
560 (status & IF_SDIO_DL_RDY))
561 break;
562 if (time_after(jiffies, timeout)) {
563 ret = -ETIMEDOUT;
564 goto release;
565 }
566 mdelay(1);
567 }
568
569 req_size = sdio_readb(card->func, IF_SDIO_RD_BASE, &ret);
570 if (ret)
571 goto release;
572
573 req_size |= sdio_readb(card->func, IF_SDIO_RD_BASE + 1, &ret) << 8;
574 if (ret)
575 goto release;
576/*
577 lbs_deb_sdio("firmware wants %d bytes\n", (int)req_size);
578*/
579 if (req_size == 0) {
580 lbs_deb_sdio("firmware helper gave up early\n");
581 ret = -EIO;
582 goto release;
583 }
584
585 if (req_size & 0x01) {
586 lbs_deb_sdio("firmware helper signalled error\n");
587 ret = -EIO;
588 goto release;
589 }
590
591 if (req_size > size)
592 req_size = size;
593
594 while (req_size) {
595 chunk_size = min(req_size, (size_t)512);
596
597 memcpy(chunk_buffer, firmware, chunk_size);
598/*
599 lbs_deb_sdio("sending %d bytes (%d bytes) chunk\n",
600 chunk_size, (chunk_size + 31) / 32 * 32);
601*/
602 ret = sdio_writesb(card->func, card->ioport,
603 chunk_buffer, (chunk_size + 31) / 32 * 32);
604 if (ret)
605 goto release;
606
607 firmware += chunk_size;
608 size -= chunk_size;
609 req_size -= chunk_size;
610 }
611 }
612
613 ret = 0;
614
615 lbs_deb_sdio("waiting for firmware to boot...\n");
616
617 /* wait for the firmware to boot */
618 timeout = jiffies + HZ;
619 while (1) {
620 u16 scratch;
621
622 scratch = if_sdio_read_scratch(card, &ret);
623 if (ret)
624 goto release;
625
626 if (scratch == IF_SDIO_FIRMWARE_OK)
627 break;
628
629 if (time_after(jiffies, timeout)) {
630 ret = -ETIMEDOUT;
631 goto release;
632 }
633
634 msleep(10);
635 }
636
637 ret = 0;
638
639release:
640 sdio_set_block_size(card->func, 0);
641 sdio_release_host(card->func);
642 kfree(chunk_buffer);
643release_fw:
644 release_firmware(fw);
645
646out:
647 if (ret)
648 lbs_pr_err("failed to load firmware\n");
649
650 lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
651
652 return ret;
653}
654
655static int if_sdio_prog_firmware(struct if_sdio_card *card)
656{
657 int ret;
658 u16 scratch;
659
660 lbs_deb_enter(LBS_DEB_SDIO);
661
662 sdio_claim_host(card->func);
663 scratch = if_sdio_read_scratch(card, &ret);
664 sdio_release_host(card->func);
665
666 if (ret)
667 goto out;
668
669 if (scratch == IF_SDIO_FIRMWARE_OK) {
670 lbs_deb_sdio("firmware already loaded\n");
671 goto success;
672 }
673
674 ret = if_sdio_prog_helper(card);
675 if (ret)
676 goto out;
677
678 ret = if_sdio_prog_real(card);
679 if (ret)
680 goto out;
681
682success:
683 ret = 0;
684
685out:
686 lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
687
688 return ret;
689}
690
691/*******************************************************************/
692/* Libertas callbacks */
693/*******************************************************************/
694
695static int if_sdio_host_to_card(wlan_private *priv, u8 type, u8 *buf, u16 nb)
696{
697 int ret;
698 struct if_sdio_card *card;
699 struct if_sdio_packet *packet, *cur;
700 u16 size;
701 unsigned long flags;
702
703 lbs_deb_enter_args(LBS_DEB_SDIO, "type %d, bytes %d", type, nb);
704
705 card = priv->card;
706
707 if (nb > (65536 - sizeof(struct if_sdio_packet) - 4)) {
708 ret = -EINVAL;
709 goto out;
710 }
711
712 /*
713 * The transfer must be in one transaction or the firmware
714 * goes suicidal.
715 */
716 size = nb + 4;
717 if ((size > card->func->cur_blksize) || (size > 512)) {
718 size = (size + card->func->cur_blksize - 1) /
719 card->func->cur_blksize * card->func->cur_blksize;
720 }
721
722 packet = kzalloc(sizeof(struct if_sdio_packet) + size,
723 GFP_ATOMIC);
724 if (!packet) {
725 ret = -ENOMEM;
726 goto out;
727 }
728
729 packet->next = NULL;
730 packet->nb = size;
731
732 /*
733 * SDIO specific header.
734 */
735 packet->buffer[0] = (nb + 4) & 0xff;
736 packet->buffer[1] = ((nb + 4) >> 8) & 0xff;
737 packet->buffer[2] = type;
738 packet->buffer[3] = 0;
739
740 memcpy(packet->buffer + 4, buf, nb);
741
742 spin_lock_irqsave(&card->lock, flags);
743
744 if (!card->packets)
745 card->packets = packet;
746 else {
747 cur = card->packets;
748 while (cur->next)
749 cur = cur->next;
750 cur->next = packet;
751 }
752
753 switch (type) {
754 case MVMS_CMD:
755 priv->dnld_sent = DNLD_CMD_SENT;
756 break;
757 case MVMS_DAT:
758 priv->dnld_sent = DNLD_DATA_SENT;
759 break;
760 default:
761 lbs_deb_sdio("unknown packet type %d\n", (int)type);
762 }
763
764 spin_unlock_irqrestore(&card->lock, flags);
765
766 schedule_work(&card->packet_worker);
767
768 ret = 0;
769
770out:
771 lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
772
773 return ret;
774}
775
776static int if_sdio_get_int_status(wlan_private *priv, u8 *ireg)
777{
778 struct if_sdio_card *card;
779
780 lbs_deb_enter(LBS_DEB_SDIO);
781
782 card = priv->card;
783
784 *ireg = card->int_cause;
785 card->int_cause = 0;
786
787 lbs_deb_leave(LBS_DEB_SDIO);
788
789 return 0;
790}
791
792static int if_sdio_read_event_cause(wlan_private *priv)
793{
794 struct if_sdio_card *card;
795
796 lbs_deb_enter(LBS_DEB_SDIO);
797
798 card = priv->card;
799
800 priv->adapter->eventcause = card->event;
801
802 lbs_deb_leave(LBS_DEB_SDIO);
803
804 return 0;
805}
806
807/*******************************************************************/
808/* SDIO callbacks */
809/*******************************************************************/
810
811static void if_sdio_interrupt(struct sdio_func *func)
812{
813 int ret;
814 struct if_sdio_card *card;
815 u8 cause;
816
817 lbs_deb_enter(LBS_DEB_SDIO);
818
819 card = sdio_get_drvdata(func);
820
821 cause = sdio_readb(card->func, IF_SDIO_H_INT_STATUS, &ret);
822 if (ret)
823 goto out;
824
825 lbs_deb_sdio("interrupt: 0x%X\n", (unsigned)cause);
826
827 sdio_writeb(card->func, ~cause, IF_SDIO_H_INT_STATUS, &ret);
828 if (ret)
829 goto out;
830
831 /*
832 * Ignore the define name, this really means the card has
833 * successfully received the command.
834 */
835 if (cause & IF_SDIO_H_INT_DNLD) {
836 if ((card->priv->dnld_sent == DNLD_DATA_SENT) &&
837 (card->priv->adapter->connect_status == LIBERTAS_CONNECTED))
838 netif_wake_queue(card->priv->dev);
839 card->priv->dnld_sent = DNLD_RES_RECEIVED;
840 }
841
842 if (cause & IF_SDIO_H_INT_UPLD) {
843 ret = if_sdio_card_to_host(card);
844 if (ret)
845 goto out;
846 }
847
848 ret = 0;
849
850out:
851 lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
852}
853
854static int if_sdio_probe(struct sdio_func *func,
855 const struct sdio_device_id *id)
856{
857 struct if_sdio_card *card;
858 wlan_private *priv;
859 int ret, i;
860 unsigned int model;
861 struct if_sdio_packet *packet;
862
863 lbs_deb_enter(LBS_DEB_SDIO);
864
865 for (i = 0;i < func->card->num_info;i++) {
866 if (sscanf(func->card->info[i],
867 "802.11 SDIO ID: %x", &model) == 1)
868 break;
869 if (sscanf(func->card->info[i],
870 "ID: %x", &model) == 1)
871 break;
872 }
873
874 if (i == func->card->num_info) {
875 lbs_pr_err("unable to identify card model\n");
876 return -ENODEV;
877 }
878
879 card = kzalloc(sizeof(struct if_sdio_card), GFP_KERNEL);
880 if (!card)
881 return -ENOMEM;
882
883 card->func = func;
884 card->model = model;
885 spin_lock_init(&card->lock);
886 INIT_WORK(&card->packet_worker, if_sdio_host_to_card_worker);
887
888 for (i = 0;i < ARRAY_SIZE(if_sdio_models);i++) {
889 if (card->model == if_sdio_models[i].model)
890 break;
891 }
892
893 if (i == ARRAY_SIZE(if_sdio_models)) {
894 lbs_pr_err("unkown card model 0x%x\n", card->model);
895 ret = -ENODEV;
896 goto free;
897 }
898
899 card->helper = if_sdio_models[i].helper;
900 card->firmware = if_sdio_models[i].firmware;
901
902 if (libertas_helper_name) {
903 lbs_deb_sdio("overriding helper firmware: %s\n",
904 libertas_helper_name);
905 card->helper = libertas_helper_name;
906 }
907
908 if (libertas_fw_name) {
909 lbs_deb_sdio("overriding firmware: %s\n", libertas_fw_name);
910 card->firmware = libertas_fw_name;
911 }
912
913 sdio_claim_host(func);
914
915 ret = sdio_enable_func(func);
916 if (ret)
917 goto release;
918
919 ret = sdio_claim_irq(func, if_sdio_interrupt);
920 if (ret)
921 goto disable;
922
923 card->ioport = sdio_readb(func, IF_SDIO_IOPORT, &ret);
924 if (ret)
925 goto release_int;
926
927 card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 1, &ret) << 8;
928 if (ret)
929 goto release_int;
930
931 card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 2, &ret) << 16;
932 if (ret)
933 goto release_int;
934
935 sdio_release_host(func);
936
937 sdio_set_drvdata(func, card);
938
939 lbs_deb_sdio("class = 0x%X, vendor = 0x%X, "
940 "device = 0x%X, model = 0x%X, ioport = 0x%X\n",
941 func->class, func->vendor, func->device,
942 model, (unsigned)card->ioport);
943
944 ret = if_sdio_prog_firmware(card);
945 if (ret)
946 goto reclaim;
947
948 priv = libertas_add_card(card, &func->dev);
949 if (!priv) {
950 ret = -ENOMEM;
951 goto reclaim;
952 }
953
954 card->priv = priv;
955
956 priv->card = card;
957 priv->hw_host_to_card = if_sdio_host_to_card;
958 priv->hw_get_int_status = if_sdio_get_int_status;
959 priv->hw_read_event_cause = if_sdio_read_event_cause;
960
961 priv->adapter->fw_ready = 1;
962
963 /*
964 * Enable interrupts now that everything is set up
965 */
966 sdio_claim_host(func);
967 sdio_writeb(func, 0x0f, IF_SDIO_H_INT_MASK, &ret);
968 sdio_release_host(func);
969 if (ret)
970 goto reclaim;
971
972 ret = libertas_start_card(priv);
973 if (ret)
974 goto err_activate_card;
975
976out:
977 lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
978
979 return ret;
980
981err_activate_card:
982 flush_scheduled_work();
983 free_netdev(priv->dev);
984 kfree(priv->adapter);
985reclaim:
986 sdio_claim_host(func);
987release_int:
988 sdio_release_irq(func);
989disable:
990 sdio_disable_func(func);
991release:
992 sdio_release_host(func);
993free:
994 while (card->packets) {
995 packet = card->packets;
996 card->packets = card->packets->next;
997 kfree(packet);
998 }
999
1000 kfree(card);
1001
1002 goto out;
1003}
1004
1005static void if_sdio_remove(struct sdio_func *func)
1006{
1007 struct if_sdio_card *card;
1008 struct if_sdio_packet *packet;
1009
1010 lbs_deb_enter(LBS_DEB_SDIO);
1011
1012 card = sdio_get_drvdata(func);
1013
1014 card->priv->adapter->surpriseremoved = 1;
1015
1016 lbs_deb_sdio("call remove card\n");
1017 libertas_stop_card(card->priv);
1018 libertas_remove_card(card->priv);
1019
1020 flush_scheduled_work();
1021
1022 sdio_claim_host(func);
1023 sdio_release_irq(func);
1024 sdio_disable_func(func);
1025 sdio_release_host(func);
1026
1027 while (card->packets) {
1028 packet = card->packets;
1029 card->packets = card->packets->next;
1030 kfree(packet);
1031 }
1032
1033 kfree(card);
1034
1035 lbs_deb_leave(LBS_DEB_SDIO);
1036}
1037
1038static struct sdio_driver if_sdio_driver = {
1039 .name = "libertas_sdio",
1040 .id_table = if_sdio_ids,
1041 .probe = if_sdio_probe,
1042 .remove = if_sdio_remove,
1043};
1044
1045/*******************************************************************/
1046/* Module functions */
1047/*******************************************************************/
1048
1049static int if_sdio_init_module(void)
1050{
1051 int ret = 0;
1052
1053 lbs_deb_enter(LBS_DEB_SDIO);
1054
1055 printk(KERN_INFO "libertas_sdio: Libertas SDIO driver\n");
1056 printk(KERN_INFO "libertas_sdio: Copyright Pierre Ossman\n");
1057
1058 ret = sdio_register_driver(&if_sdio_driver);
1059
1060 lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
1061
1062 return ret;
1063}
1064
1065static void if_sdio_exit_module(void)
1066{
1067 lbs_deb_enter(LBS_DEB_SDIO);
1068
1069 sdio_unregister_driver(&if_sdio_driver);
1070
1071 lbs_deb_leave(LBS_DEB_SDIO);
1072}
1073
1074module_init(if_sdio_init_module);
1075module_exit(if_sdio_exit_module);
1076
1077MODULE_DESCRIPTION("Libertas SDIO WLAN Driver");
1078MODULE_AUTHOR("Pierre Ossman");
1079MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/libertas/if_sdio.h b/drivers/net/wireless/libertas/if_sdio.h
new file mode 100644
index 000000000000..dfcaea7b168f
--- /dev/null
+++ b/drivers/net/wireless/libertas/if_sdio.h
@@ -0,0 +1,45 @@
1/*
2 * linux/drivers/net/wireless/libertas/if_sdio.h
3 *
4 * Copyright 2007 Pierre Ossman
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 (at
9 * your option) any later version.
10 */
11
12#ifndef LIBERTAS_IF_SDIO_H
13#define LIBERTAS_IF_SDIO_H
14
15#define IF_SDIO_IOPORT 0x00
16
17#define IF_SDIO_H_INT_MASK 0x04
18#define IF_SDIO_H_INT_OFLOW 0x08
19#define IF_SDIO_H_INT_UFLOW 0x04
20#define IF_SDIO_H_INT_DNLD 0x02
21#define IF_SDIO_H_INT_UPLD 0x01
22
23#define IF_SDIO_H_INT_STATUS 0x05
24#define IF_SDIO_H_INT_RSR 0x06
25#define IF_SDIO_H_INT_STATUS2 0x07
26
27#define IF_SDIO_RD_BASE 0x10
28
29#define IF_SDIO_STATUS 0x20
30#define IF_SDIO_IO_RDY 0x08
31#define IF_SDIO_CIS_RDY 0x04
32#define IF_SDIO_UL_RDY 0x02
33#define IF_SDIO_DL_RDY 0x01
34
35#define IF_SDIO_C_INT_MASK 0x24
36#define IF_SDIO_C_INT_STATUS 0x28
37#define IF_SDIO_C_INT_RSR 0x2C
38
39#define IF_SDIO_SCRATCH 0x34
40#define IF_SDIO_SCRATCH_OLD 0x80fe
41#define IF_SDIO_FIRMWARE_OK 0xfedc
42
43#define IF_SDIO_EVENT 0x80fc
44
45#endif
diff --git a/fs/9p/fid.c b/fs/9p/fid.c
index 15e05a15b575..b364da70ff28 100644
--- a/fs/9p/fid.c
+++ b/fs/9p/fid.c
@@ -1,6 +1,7 @@
1/* 1/*
2 * V9FS FID Management 2 * V9FS FID Management
3 * 3 *
4 * Copyright (C) 2007 by Latchesar Ionkov <lucho@ionkov.net>
4 * Copyright (C) 2005, 2006 by Eric Van Hensbergen <ericvh@gmail.com> 5 * Copyright (C) 2005, 2006 by Eric Van Hensbergen <ericvh@gmail.com>
5 * 6 *
6 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
@@ -34,9 +35,9 @@
34#include "fid.h" 35#include "fid.h"
35 36
36/** 37/**
37 * v9fs_fid_insert - add a fid to a dentry 38 * v9fs_fid_add - add a fid to a dentry
39 * @dentry: dentry that the fid is being added to
38 * @fid: fid to add 40 * @fid: fid to add
39 * @dentry: dentry that it is being added to
40 * 41 *
41 */ 42 */
42 43
@@ -66,52 +67,144 @@ int v9fs_fid_add(struct dentry *dentry, struct p9_fid *fid)
66} 67}
67 68
68/** 69/**
69 * v9fs_fid_lookup - return a locked fid from a dentry 70 * v9fs_fid_find - retrieve a fid that belongs to the specified uid
70 * @dentry: dentry to look for fid in 71 * @dentry: dentry to look for fid in
71 * 72 * @uid: return fid that belongs to the specified user
72 * find a fid in the dentry, obtain its semaphore and return a reference to it. 73 * @any: if non-zero, return any fid associated with the dentry
73 * code calling lookup is responsible for releasing lock
74 *
75 * TODO: only match fids that have the same uid as current user
76 * 74 *
77 */ 75 */
78 76
79struct p9_fid *v9fs_fid_lookup(struct dentry *dentry) 77static struct p9_fid *v9fs_fid_find(struct dentry *dentry, u32 uid, int any)
80{ 78{
81 struct v9fs_dentry *dent; 79 struct v9fs_dentry *dent;
82 struct p9_fid *fid; 80 struct p9_fid *fid, *ret;
83 81
84 P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry); 82 P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p) uid %d any %d\n",
85 dent = dentry->d_fsdata; 83 dentry->d_iname, dentry, uid, any);
86 if (dent) 84 dent = (struct v9fs_dentry *) dentry->d_fsdata;
87 fid = list_entry(dent->fidlist.next, struct p9_fid, dlist); 85 ret = NULL;
88 else 86 if (dent) {
89 fid = ERR_PTR(-EBADF); 87 spin_lock(&dent->lock);
88 list_for_each_entry(fid, &dent->fidlist, dlist) {
89 if (any || fid->uid == uid) {
90 ret = fid;
91 break;
92 }
93 }
94 spin_unlock(&dent->lock);
95 }
90 96
91 P9_DPRINTK(P9_DEBUG_VFS, " fid: %p\n", fid); 97 return ret;
92 return fid;
93} 98}
94 99
95/** 100/**
96 * v9fs_fid_clone - lookup the fid for a dentry, clone a private copy and 101 * v9fs_fid_lookup - lookup for a fid, try to walk if not found
97 * release it
98 * @dentry: dentry to look for fid in 102 * @dentry: dentry to look for fid in
99 * 103 *
100 * find a fid in the dentry and then clone to a new private fid 104 * Look for a fid in the specified dentry for the current user.
101 * 105 * If no fid is found, try to create one walking from a fid from the parent
102 * TODO: only match fids that have the same uid as current user 106 * dentry (if it has one), or the root dentry. If the user haven't accessed
103 * 107 * the fs yet, attach now and walk from the root.
104 */ 108 */
105 109
106struct p9_fid *v9fs_fid_clone(struct dentry *dentry) 110struct p9_fid *v9fs_fid_lookup(struct dentry *dentry)
107{ 111{
108 struct p9_fid *ofid, *fid; 112 int i, n, l, clone, any, access;
113 u32 uid;
114 struct p9_fid *fid;
115 struct dentry *d, *ds;
116 struct v9fs_session_info *v9ses;
117 char **wnames, *uname;
118
119 v9ses = v9fs_inode2v9ses(dentry->d_inode);
120 access = v9ses->flags & V9FS_ACCESS_MASK;
121 switch (access) {
122 case V9FS_ACCESS_SINGLE:
123 case V9FS_ACCESS_USER:
124 uid = current->fsuid;
125 any = 0;
126 break;
127
128 case V9FS_ACCESS_ANY:
129 uid = v9ses->uid;
130 any = 1;
131 break;
132
133 default:
134 uid = ~0;
135 any = 0;
136 break;
137 }
109 138
110 P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry); 139 fid = v9fs_fid_find(dentry, uid, any);
111 ofid = v9fs_fid_lookup(dentry); 140 if (fid)
112 if (IS_ERR(ofid)) 141 return fid;
113 return ofid; 142
143 ds = dentry->d_parent;
144 fid = v9fs_fid_find(ds, uid, any);
145 if (!fid) { /* walk from the root */
146 n = 0;
147 for (ds = dentry; !IS_ROOT(ds); ds = ds->d_parent)
148 n++;
149
150 fid = v9fs_fid_find(ds, uid, any);
151 if (!fid) { /* the user is not attached to the fs yet */
152 if (access == V9FS_ACCESS_SINGLE)
153 return ERR_PTR(-EPERM);
154
155 if (v9fs_extended(v9ses))
156 uname = NULL;
157 else
158 uname = v9ses->uname;
159
160 fid = p9_client_attach(v9ses->clnt, NULL, uname, uid,
161 v9ses->aname);
162
163 if (IS_ERR(fid))
164 return fid;
165
166 v9fs_fid_add(ds, fid);
167 }
168 } else /* walk from the parent */
169 n = 1;
170
171 if (ds == dentry)
172 return fid;
173
174 wnames = kmalloc(sizeof(char *) * n, GFP_KERNEL);
175 if (!wnames)
176 return ERR_PTR(-ENOMEM);
177
178 for (d = dentry, i = n; i >= 0; i--, d = d->d_parent)
179 wnames[i] = (char *) d->d_name.name;
180
181 clone = 1;
182 i = 0;
183 while (i < n) {
184 l = min(n - i, P9_MAXWELEM);
185 fid = p9_client_walk(fid, l, &wnames[i], clone);
186 if (!fid) {
187 kfree(wnames);
188 return fid;
189 }
190
191 i += l;
192 clone = 0;
193 }
114 194
115 fid = p9_client_walk(ofid, 0, NULL, 1); 195 kfree(wnames);
196 v9fs_fid_add(dentry, fid);
116 return fid; 197 return fid;
117} 198}
199
200struct p9_fid *v9fs_fid_clone(struct dentry *dentry)
201{
202 struct p9_fid *fid, *ret;
203
204 fid = v9fs_fid_lookup(dentry);
205 if (IS_ERR(fid))
206 return fid;
207
208 ret = p9_client_walk(fid, 0, NULL, 1);
209 return ret;
210}
diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c
index 0a7068e30ecb..873802de21cd 100644
--- a/fs/9p/v9fs.c
+++ b/fs/9p/v9fs.c
@@ -38,56 +38,41 @@
38 38
39/* 39/*
40 * Option Parsing (code inspired by NFS code) 40 * Option Parsing (code inspired by NFS code)
41 * 41 * NOTE: each transport will parse its own options
42 */ 42 */
43 43
44enum { 44enum {
45 /* Options that take integer arguments */ 45 /* Options that take integer arguments */
46 Opt_debug, Opt_port, Opt_msize, Opt_uid, Opt_gid, Opt_afid, 46 Opt_debug, Opt_msize, Opt_dfltuid, Opt_dfltgid, Opt_afid,
47 Opt_rfdno, Opt_wfdno,
48 /* String options */ 47 /* String options */
49 Opt_uname, Opt_remotename, 48 Opt_uname, Opt_remotename, Opt_trans,
50 /* Options that take no arguments */ 49 /* Options that take no arguments */
51 Opt_legacy, Opt_nodevmap, Opt_unix, Opt_tcp, Opt_fd, Opt_pci, 50 Opt_legacy, Opt_nodevmap,
52 /* Cache options */ 51 /* Cache options */
53 Opt_cache_loose, 52 Opt_cache_loose,
53 /* Access options */
54 Opt_access,
54 /* Error token */ 55 /* Error token */
55 Opt_err 56 Opt_err
56}; 57};
57 58
58static match_table_t tokens = { 59static match_table_t tokens = {
59 {Opt_debug, "debug=%x"}, 60 {Opt_debug, "debug=%x"},
60 {Opt_port, "port=%u"},
61 {Opt_msize, "msize=%u"}, 61 {Opt_msize, "msize=%u"},
62 {Opt_uid, "uid=%u"}, 62 {Opt_dfltuid, "dfltuid=%u"},
63 {Opt_gid, "gid=%u"}, 63 {Opt_dfltgid, "dfltgid=%u"},
64 {Opt_afid, "afid=%u"}, 64 {Opt_afid, "afid=%u"},
65 {Opt_rfdno, "rfdno=%u"},
66 {Opt_wfdno, "wfdno=%u"},
67 {Opt_uname, "uname=%s"}, 65 {Opt_uname, "uname=%s"},
68 {Opt_remotename, "aname=%s"}, 66 {Opt_remotename, "aname=%s"},
69 {Opt_unix, "proto=unix"}, 67 {Opt_trans, "trans=%s"},
70 {Opt_tcp, "proto=tcp"},
71 {Opt_fd, "proto=fd"},
72#ifdef CONFIG_PCI_9P
73 {Opt_pci, "proto=pci"},
74#endif
75 {Opt_tcp, "tcp"},
76 {Opt_unix, "unix"},
77 {Opt_fd, "fd"},
78 {Opt_legacy, "noextend"}, 68 {Opt_legacy, "noextend"},
79 {Opt_nodevmap, "nodevmap"}, 69 {Opt_nodevmap, "nodevmap"},
80 {Opt_cache_loose, "cache=loose"}, 70 {Opt_cache_loose, "cache=loose"},
81 {Opt_cache_loose, "loose"}, 71 {Opt_cache_loose, "loose"},
72 {Opt_access, "access=%s"},
82 {Opt_err, NULL} 73 {Opt_err, NULL}
83}; 74};
84 75
85extern struct p9_transport *p9pci_trans_create(void);
86
87/*
88 * Parse option string.
89 */
90
91/** 76/**
92 * v9fs_parse_options - parse mount options into session structure 77 * v9fs_parse_options - parse mount options into session structure
93 * @options: options string passed from mount 78 * @options: options string passed from mount
@@ -95,23 +80,21 @@ extern struct p9_transport *p9pci_trans_create(void);
95 * 80 *
96 */ 81 */
97 82
98static void v9fs_parse_options(char *options, struct v9fs_session_info *v9ses) 83static void v9fs_parse_options(struct v9fs_session_info *v9ses)
99{ 84{
100 char *p; 85 char *options = v9ses->options;
101 substring_t args[MAX_OPT_ARGS]; 86 substring_t args[MAX_OPT_ARGS];
87 char *p;
102 int option; 88 int option;
103 int ret; 89 int ret;
90 char *s, *e;
104 91
105 /* setup defaults */ 92 /* setup defaults */
106 v9ses->port = V9FS_PORT; 93 v9ses->maxdata = 8192;
107 v9ses->maxdata = 9000;
108 v9ses->proto = PROTO_TCP;
109 v9ses->extended = 1;
110 v9ses->afid = ~0; 94 v9ses->afid = ~0;
111 v9ses->debug = 0; 95 v9ses->debug = 0;
112 v9ses->rfdno = ~0;
113 v9ses->wfdno = ~0;
114 v9ses->cache = 0; 96 v9ses->cache = 0;
97 v9ses->trans = v9fs_default_trans();
115 98
116 if (!options) 99 if (!options)
117 return; 100 return;
@@ -135,47 +118,29 @@ static void v9fs_parse_options(char *options, struct v9fs_session_info *v9ses)
135 p9_debug_level = option; 118 p9_debug_level = option;
136#endif 119#endif
137 break; 120 break;
138 case Opt_port:
139 v9ses->port = option;
140 break;
141 case Opt_msize: 121 case Opt_msize:
142 v9ses->maxdata = option; 122 v9ses->maxdata = option;
143 break; 123 break;
144 case Opt_uid: 124 case Opt_dfltuid:
145 v9ses->uid = option; 125 v9ses->dfltuid = option;
146 break; 126 break;
147 case Opt_gid: 127 case Opt_dfltgid:
148 v9ses->gid = option; 128 v9ses->dfltgid = option;
149 break; 129 break;
150 case Opt_afid: 130 case Opt_afid:
151 v9ses->afid = option; 131 v9ses->afid = option;
152 break; 132 break;
153 case Opt_rfdno: 133 case Opt_trans:
154 v9ses->rfdno = option; 134 v9ses->trans = v9fs_match_trans(&args[0]);
155 break;
156 case Opt_wfdno:
157 v9ses->wfdno = option;
158 break;
159 case Opt_tcp:
160 v9ses->proto = PROTO_TCP;
161 break;
162 case Opt_unix:
163 v9ses->proto = PROTO_UNIX;
164 break;
165 case Opt_pci:
166 v9ses->proto = PROTO_PCI;
167 break;
168 case Opt_fd:
169 v9ses->proto = PROTO_FD;
170 break; 135 break;
171 case Opt_uname: 136 case Opt_uname:
172 match_strcpy(v9ses->name, &args[0]); 137 match_strcpy(v9ses->uname, &args[0]);
173 break; 138 break;
174 case Opt_remotename: 139 case Opt_remotename:
175 match_strcpy(v9ses->remotename, &args[0]); 140 match_strcpy(v9ses->aname, &args[0]);
176 break; 141 break;
177 case Opt_legacy: 142 case Opt_legacy:
178 v9ses->extended = 0; 143 v9ses->flags &= ~V9FS_EXTENDED;
179 break; 144 break;
180 case Opt_nodevmap: 145 case Opt_nodevmap:
181 v9ses->nodev = 1; 146 v9ses->nodev = 1;
@@ -183,6 +148,22 @@ static void v9fs_parse_options(char *options, struct v9fs_session_info *v9ses)
183 case Opt_cache_loose: 148 case Opt_cache_loose:
184 v9ses->cache = CACHE_LOOSE; 149 v9ses->cache = CACHE_LOOSE;
185 break; 150 break;
151
152 case Opt_access:
153 s = match_strdup(&args[0]);
154 v9ses->flags &= ~V9FS_ACCESS_MASK;
155 if (strcmp(s, "user") == 0)
156 v9ses->flags |= V9FS_ACCESS_USER;
157 else if (strcmp(s, "any") == 0)
158 v9ses->flags |= V9FS_ACCESS_ANY;
159 else {
160 v9ses->flags |= V9FS_ACCESS_SINGLE;
161 v9ses->uid = simple_strtol(s, &e, 10);
162 if (*e != '\0')
163 v9ses->uid = ~0;
164 }
165 break;
166
186 default: 167 default:
187 continue; 168 continue;
188 } 169 }
@@ -201,56 +182,46 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
201 const char *dev_name, char *data) 182 const char *dev_name, char *data)
202{ 183{
203 int retval = -EINVAL; 184 int retval = -EINVAL;
204 struct p9_transport *trans; 185 struct p9_trans *trans = NULL;
205 struct p9_fid *fid; 186 struct p9_fid *fid;
206 187
207 v9ses->name = __getname(); 188 v9ses->uname = __getname();
208 if (!v9ses->name) 189 if (!v9ses->uname)
209 return ERR_PTR(-ENOMEM); 190 return ERR_PTR(-ENOMEM);
210 191
211 v9ses->remotename = __getname(); 192 v9ses->aname = __getname();
212 if (!v9ses->remotename) { 193 if (!v9ses->aname) {
213 __putname(v9ses->name); 194 __putname(v9ses->uname);
214 return ERR_PTR(-ENOMEM); 195 return ERR_PTR(-ENOMEM);
215 } 196 }
216 197
217 strcpy(v9ses->name, V9FS_DEFUSER); 198 v9ses->flags = V9FS_EXTENDED | V9FS_ACCESS_USER;
218 strcpy(v9ses->remotename, V9FS_DEFANAME); 199 strcpy(v9ses->uname, V9FS_DEFUSER);
219 200 strcpy(v9ses->aname, V9FS_DEFANAME);
220 v9fs_parse_options(data, v9ses); 201 v9ses->uid = ~0;
221 202 v9ses->dfltuid = V9FS_DEFUID;
222 switch (v9ses->proto) { 203 v9ses->dfltgid = V9FS_DEFGID;
223 case PROTO_TCP: 204 v9ses->options = kstrdup(data, GFP_KERNEL);
224 trans = p9_trans_create_tcp(dev_name, v9ses->port); 205 v9fs_parse_options(v9ses);
225 break; 206
226 case PROTO_UNIX: 207 if (v9ses->trans == NULL) {
227 trans = p9_trans_create_unix(dev_name); 208 retval = -EPROTONOSUPPORT;
228 *v9ses->remotename = 0; 209 P9_DPRINTK(P9_DEBUG_ERROR,
229 break; 210 "No transport defined or default transport\n");
230 case PROTO_FD:
231 trans = p9_trans_create_fd(v9ses->rfdno, v9ses->wfdno);
232 *v9ses->remotename = 0;
233 break;
234#ifdef CONFIG_PCI_9P
235 case PROTO_PCI:
236 trans = p9pci_trans_create();
237 *v9ses->remotename = 0;
238 break;
239#endif
240 default:
241 printk(KERN_ERR "v9fs: Bad mount protocol %d\n", v9ses->proto);
242 retval = -ENOPROTOOPT;
243 goto error; 211 goto error;
244 }; 212 }
245 213
214 trans = v9ses->trans->create(dev_name, v9ses->options);
246 if (IS_ERR(trans)) { 215 if (IS_ERR(trans)) {
247 retval = PTR_ERR(trans); 216 retval = PTR_ERR(trans);
248 trans = NULL; 217 trans = NULL;
249 goto error; 218 goto error;
250 } 219 }
220 if ((v9ses->maxdata+P9_IOHDRSZ) > v9ses->trans->maxsize)
221 v9ses->maxdata = v9ses->trans->maxsize-P9_IOHDRSZ;
251 222
252 v9ses->clnt = p9_client_create(trans, v9ses->maxdata + P9_IOHDRSZ, 223 v9ses->clnt = p9_client_create(trans, v9ses->maxdata+P9_IOHDRSZ,
253 v9ses->extended); 224 v9fs_extended(v9ses));
254 225
255 if (IS_ERR(v9ses->clnt)) { 226 if (IS_ERR(v9ses->clnt)) {
256 retval = PTR_ERR(v9ses->clnt); 227 retval = PTR_ERR(v9ses->clnt);
@@ -259,8 +230,20 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
259 goto error; 230 goto error;
260 } 231 }
261 232
262 fid = p9_client_attach(v9ses->clnt, NULL, v9ses->name, 233 if (!v9ses->clnt->dotu)
263 v9ses->remotename); 234 v9ses->flags &= ~V9FS_EXTENDED;
235
236 /* for legacy mode, fall back to V9FS_ACCESS_ANY */
237 if (!v9fs_extended(v9ses) &&
238 ((v9ses->flags&V9FS_ACCESS_MASK) == V9FS_ACCESS_USER)) {
239
240 v9ses->flags &= ~V9FS_ACCESS_MASK;
241 v9ses->flags |= V9FS_ACCESS_ANY;
242 v9ses->uid = ~0;
243 }
244
245 fid = p9_client_attach(v9ses->clnt, NULL, v9ses->uname, ~0,
246 v9ses->aname);
264 if (IS_ERR(fid)) { 247 if (IS_ERR(fid)) {
265 retval = PTR_ERR(fid); 248 retval = PTR_ERR(fid);
266 fid = NULL; 249 fid = NULL;
@@ -268,6 +251,11 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
268 goto error; 251 goto error;
269 } 252 }
270 253
254 if ((v9ses->flags & V9FS_ACCESS_MASK) == V9FS_ACCESS_SINGLE)
255 fid->uid = v9ses->uid;
256 else
257 fid->uid = ~0;
258
271 return fid; 259 return fid;
272 260
273error: 261error:
@@ -288,8 +276,9 @@ void v9fs_session_close(struct v9fs_session_info *v9ses)
288 v9ses->clnt = NULL; 276 v9ses->clnt = NULL;
289 } 277 }
290 278
291 __putname(v9ses->name); 279 __putname(v9ses->uname);
292 __putname(v9ses->remotename); 280 __putname(v9ses->aname);
281 kfree(v9ses->options);
293} 282}
294 283
295/** 284/**
@@ -311,7 +300,7 @@ extern int v9fs_error_init(void);
311static int __init init_v9fs(void) 300static int __init init_v9fs(void)
312{ 301{
313 printk(KERN_INFO "Installing v9fs 9p2000 file system support\n"); 302 printk(KERN_INFO "Installing v9fs 9p2000 file system support\n");
314 303 /* TODO: Setup list of registered trasnport modules */
315 return register_filesystem(&v9fs_fs_type); 304 return register_filesystem(&v9fs_fs_type);
316} 305}
317 306
diff --git a/fs/9p/v9fs.h b/fs/9p/v9fs.h
index abc4b1668ace..db4b4193f2e2 100644
--- a/fs/9p/v9fs.h
+++ b/fs/9p/v9fs.h
@@ -29,31 +29,30 @@
29struct v9fs_session_info { 29struct v9fs_session_info {
30 /* options */ 30 /* options */
31 unsigned int maxdata; 31 unsigned int maxdata;
32 unsigned char extended; /* set to 1 if we are using UNIX extensions */ 32 unsigned char flags; /* session flags */
33 unsigned char nodev; /* set to 1 if no disable device mapping */ 33 unsigned char nodev; /* set to 1 if no disable device mapping */
34 unsigned short port; /* port to connect to */
35 unsigned short debug; /* debug level */ 34 unsigned short debug; /* debug level */
36 unsigned short proto; /* protocol to use */
37 unsigned int afid; /* authentication fid */ 35 unsigned int afid; /* authentication fid */
38 unsigned int rfdno; /* read file descriptor number */
39 unsigned int wfdno; /* write file descriptor number */
40 unsigned int cache; /* cache mode */ 36 unsigned int cache; /* cache mode */
41 37
42 char *name; /* user name to mount as */ 38 char *options; /* copy of mount options */
43 char *remotename; /* name of remote hierarchy being mounted */ 39 char *uname; /* user name to mount as */
44 unsigned int uid; /* default uid/muid for legacy support */ 40 char *aname; /* name of remote hierarchy being mounted */
45 unsigned int gid; /* default gid for legacy support */ 41 unsigned int dfltuid; /* default uid/muid for legacy support */
46 42 unsigned int dfltgid; /* default gid for legacy support */
43 u32 uid; /* if ACCESS_SINGLE, the uid that has access */
44 struct p9_trans_module *trans; /* 9p transport */
47 struct p9_client *clnt; /* 9p client */ 45 struct p9_client *clnt; /* 9p client */
48 struct dentry *debugfs_dir; 46 struct dentry *debugfs_dir;
49}; 47};
50 48
51/* possible values of ->proto */ 49/* session flags */
52enum { 50enum {
53 PROTO_TCP, 51 V9FS_EXTENDED = 0x01, /* 9P2000.u */
54 PROTO_UNIX, 52 V9FS_ACCESS_MASK = 0x06, /* access mask */
55 PROTO_FD, 53 V9FS_ACCESS_SINGLE = 0x02, /* only one user can access the files */
56 PROTO_PCI, 54 V9FS_ACCESS_USER = 0x04, /* attache per user */
55 V9FS_ACCESS_ANY = 0x06, /* use the same attach for all users */
57}; 56};
58 57
59/* possible values of ->cache */ 58/* possible values of ->cache */
@@ -73,11 +72,18 @@ void v9fs_session_cancel(struct v9fs_session_info *v9ses);
73#define V9FS_MAGIC 0x01021997 72#define V9FS_MAGIC 0x01021997
74 73
75/* other default globals */ 74/* other default globals */
76#define V9FS_PORT 564 75#define V9FS_PORT 564
77#define V9FS_DEFUSER "nobody" 76#define V9FS_DEFUSER "nobody"
78#define V9FS_DEFANAME "" 77#define V9FS_DEFANAME ""
78#define V9FS_DEFUID (-2)
79#define V9FS_DEFGID (-2)
79 80
80static inline struct v9fs_session_info *v9fs_inode2v9ses(struct inode *inode) 81static inline struct v9fs_session_info *v9fs_inode2v9ses(struct inode *inode)
81{ 82{
82 return (inode->i_sb->s_fs_info); 83 return (inode->i_sb->s_fs_info);
83} 84}
85
86static inline int v9fs_extended(struct v9fs_session_info *v9ses)
87{
88 return v9ses->flags & V9FS_EXTENDED;
89}
diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c
index 716691689fd5..ba4b1caa9c43 100644
--- a/fs/9p/vfs_file.c
+++ b/fs/9p/vfs_file.c
@@ -162,15 +162,17 @@ v9fs_file_write(struct file *filp, const char __user * data,
162 162
163 fid = filp->private_data; 163 fid = filp->private_data;
164 ret = p9_client_uwrite(fid, data, *offset, count); 164 ret = p9_client_uwrite(fid, data, *offset, count);
165 if (ret > 0) 165 if (ret > 0) {
166 invalidate_inode_pages2_range(inode->i_mapping, *offset,
167 *offset+ret);
166 *offset += ret; 168 *offset += ret;
169 }
167 170
168 if (*offset > inode->i_size) { 171 if (*offset > inode->i_size) {
169 inode->i_size = *offset; 172 inode->i_size = *offset;
170 inode->i_blocks = (inode->i_size + 512 - 1) >> 9; 173 inode->i_blocks = (inode->i_size + 512 - 1) >> 9;
171 } 174 }
172 175
173 invalidate_inode_pages2(inode->i_mapping);
174 return ret; 176 return ret;
175} 177}
176 178
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index e5c45eed58a9..175b4d9bf3f8 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -59,7 +59,7 @@ static int unixmode2p9mode(struct v9fs_session_info *v9ses, int mode)
59 res = mode & 0777; 59 res = mode & 0777;
60 if (S_ISDIR(mode)) 60 if (S_ISDIR(mode))
61 res |= P9_DMDIR; 61 res |= P9_DMDIR;
62 if (v9ses->extended) { 62 if (v9fs_extended(v9ses)) {
63 if (S_ISLNK(mode)) 63 if (S_ISLNK(mode))
64 res |= P9_DMSYMLINK; 64 res |= P9_DMSYMLINK;
65 if (v9ses->nodev == 0) { 65 if (v9ses->nodev == 0) {
@@ -99,21 +99,21 @@ static int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode)
99 99
100 if ((mode & P9_DMDIR) == P9_DMDIR) 100 if ((mode & P9_DMDIR) == P9_DMDIR)
101 res |= S_IFDIR; 101 res |= S_IFDIR;
102 else if ((mode & P9_DMSYMLINK) && (v9ses->extended)) 102 else if ((mode & P9_DMSYMLINK) && (v9fs_extended(v9ses)))
103 res |= S_IFLNK; 103 res |= S_IFLNK;
104 else if ((mode & P9_DMSOCKET) && (v9ses->extended) 104 else if ((mode & P9_DMSOCKET) && (v9fs_extended(v9ses))
105 && (v9ses->nodev == 0)) 105 && (v9ses->nodev == 0))
106 res |= S_IFSOCK; 106 res |= S_IFSOCK;
107 else if ((mode & P9_DMNAMEDPIPE) && (v9ses->extended) 107 else if ((mode & P9_DMNAMEDPIPE) && (v9fs_extended(v9ses))
108 && (v9ses->nodev == 0)) 108 && (v9ses->nodev == 0))
109 res |= S_IFIFO; 109 res |= S_IFIFO;
110 else if ((mode & P9_DMDEVICE) && (v9ses->extended) 110 else if ((mode & P9_DMDEVICE) && (v9fs_extended(v9ses))
111 && (v9ses->nodev == 0)) 111 && (v9ses->nodev == 0))
112 res |= S_IFBLK; 112 res |= S_IFBLK;
113 else 113 else
114 res |= S_IFREG; 114 res |= S_IFREG;
115 115
116 if (v9ses->extended) { 116 if (v9fs_extended(v9ses)) {
117 if ((mode & P9_DMSETUID) == P9_DMSETUID) 117 if ((mode & P9_DMSETUID) == P9_DMSETUID)
118 res |= S_ISUID; 118 res |= S_ISUID;
119 119
@@ -214,7 +214,7 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode)
214 case S_IFBLK: 214 case S_IFBLK:
215 case S_IFCHR: 215 case S_IFCHR:
216 case S_IFSOCK: 216 case S_IFSOCK:
217 if(!v9ses->extended) { 217 if (!v9fs_extended(v9ses)) {
218 P9_DPRINTK(P9_DEBUG_ERROR, 218 P9_DPRINTK(P9_DEBUG_ERROR,
219 "special files without extended mode\n"); 219 "special files without extended mode\n");
220 return ERR_PTR(-EINVAL); 220 return ERR_PTR(-EINVAL);
@@ -227,7 +227,7 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode)
227 inode->i_fop = &v9fs_file_operations; 227 inode->i_fop = &v9fs_file_operations;
228 break; 228 break;
229 case S_IFLNK: 229 case S_IFLNK:
230 if(!v9ses->extended) { 230 if (!v9fs_extended(v9ses)) {
231 P9_DPRINTK(P9_DEBUG_ERROR, 231 P9_DPRINTK(P9_DEBUG_ERROR,
232 "extended modes used w/o 9P2000.u\n"); 232 "extended modes used w/o 9P2000.u\n");
233 return ERR_PTR(-EINVAL); 233 return ERR_PTR(-EINVAL);
@@ -236,7 +236,7 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode)
236 break; 236 break;
237 case S_IFDIR: 237 case S_IFDIR:
238 inc_nlink(inode); 238 inc_nlink(inode);
239 if(v9ses->extended) 239 if (v9fs_extended(v9ses))
240 inode->i_op = &v9fs_dir_inode_operations_ext; 240 inode->i_op = &v9fs_dir_inode_operations_ext;
241 else 241 else
242 inode->i_op = &v9fs_dir_inode_operations; 242 inode->i_op = &v9fs_dir_inode_operations;
@@ -364,7 +364,7 @@ static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir)
364 file_inode = file->d_inode; 364 file_inode = file->d_inode;
365 v9ses = v9fs_inode2v9ses(file_inode); 365 v9ses = v9fs_inode2v9ses(file_inode);
366 v9fid = v9fs_fid_clone(file); 366 v9fid = v9fs_fid_clone(file);
367 if(IS_ERR(v9fid)) 367 if (IS_ERR(v9fid))
368 return PTR_ERR(v9fid); 368 return PTR_ERR(v9fid);
369 369
370 return p9_client_remove(v9fid); 370 return p9_client_remove(v9fid);
@@ -398,7 +398,7 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,
398 fid = NULL; 398 fid = NULL;
399 name = (char *) dentry->d_name.name; 399 name = (char *) dentry->d_name.name;
400 dfid = v9fs_fid_clone(dentry->d_parent); 400 dfid = v9fs_fid_clone(dentry->d_parent);
401 if(IS_ERR(dfid)) { 401 if (IS_ERR(dfid)) {
402 err = PTR_ERR(dfid); 402 err = PTR_ERR(dfid);
403 dfid = NULL; 403 dfid = NULL;
404 goto error; 404 goto error;
@@ -432,7 +432,7 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,
432 goto error; 432 goto error;
433 } 433 }
434 434
435 if(v9ses->cache) 435 if (v9ses->cache)
436 dentry->d_op = &v9fs_cached_dentry_operations; 436 dentry->d_op = &v9fs_cached_dentry_operations;
437 else 437 else
438 dentry->d_op = &v9fs_dentry_operations; 438 dentry->d_op = &v9fs_dentry_operations;
@@ -593,7 +593,7 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
593 if (result < 0) 593 if (result < 0)
594 goto error; 594 goto error;
595 595
596 if((fid->qid.version)&&(v9ses->cache)) 596 if ((fid->qid.version) && (v9ses->cache))
597 dentry->d_op = &v9fs_cached_dentry_operations; 597 dentry->d_op = &v9fs_cached_dentry_operations;
598 else 598 else
599 dentry->d_op = &v9fs_dentry_operations; 599 dentry->d_op = &v9fs_dentry_operations;
@@ -658,17 +658,17 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
658 old_inode = old_dentry->d_inode; 658 old_inode = old_dentry->d_inode;
659 v9ses = v9fs_inode2v9ses(old_inode); 659 v9ses = v9fs_inode2v9ses(old_inode);
660 oldfid = v9fs_fid_lookup(old_dentry); 660 oldfid = v9fs_fid_lookup(old_dentry);
661 if(IS_ERR(oldfid)) 661 if (IS_ERR(oldfid))
662 return PTR_ERR(oldfid); 662 return PTR_ERR(oldfid);
663 663
664 olddirfid = v9fs_fid_clone(old_dentry->d_parent); 664 olddirfid = v9fs_fid_clone(old_dentry->d_parent);
665 if(IS_ERR(olddirfid)) { 665 if (IS_ERR(olddirfid)) {
666 retval = PTR_ERR(olddirfid); 666 retval = PTR_ERR(olddirfid);
667 goto done; 667 goto done;
668 } 668 }
669 669
670 newdirfid = v9fs_fid_clone(new_dentry->d_parent); 670 newdirfid = v9fs_fid_clone(new_dentry->d_parent);
671 if(IS_ERR(newdirfid)) { 671 if (IS_ERR(newdirfid)) {
672 retval = PTR_ERR(newdirfid); 672 retval = PTR_ERR(newdirfid);
673 goto clunk_olddir; 673 goto clunk_olddir;
674 } 674 }
@@ -682,7 +682,7 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
682 } 682 }
683 683
684 v9fs_blank_wstat(&wstat); 684 v9fs_blank_wstat(&wstat);
685 wstat.muid = v9ses->name; 685 wstat.muid = v9ses->uname;
686 wstat.name = (char *) new_dentry->d_name.name; 686 wstat.name = (char *) new_dentry->d_name.name;
687 retval = p9_client_wstat(oldfid, &wstat); 687 retval = p9_client_wstat(oldfid, &wstat);
688 688
@@ -768,7 +768,7 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
768 if (iattr->ia_valid & ATTR_SIZE) 768 if (iattr->ia_valid & ATTR_SIZE)
769 wstat.length = iattr->ia_size; 769 wstat.length = iattr->ia_size;
770 770
771 if (v9ses->extended) { 771 if (v9fs_extended(v9ses)) {
772 if (iattr->ia_valid & ATTR_UID) 772 if (iattr->ia_valid & ATTR_UID)
773 wstat.n_uid = iattr->ia_uid; 773 wstat.n_uid = iattr->ia_uid;
774 774
@@ -805,10 +805,10 @@ v9fs_stat2inode(struct p9_stat *stat, struct inode *inode,
805 inode->i_mtime.tv_sec = stat->mtime; 805 inode->i_mtime.tv_sec = stat->mtime;
806 inode->i_ctime.tv_sec = stat->mtime; 806 inode->i_ctime.tv_sec = stat->mtime;
807 807
808 inode->i_uid = v9ses->uid; 808 inode->i_uid = v9ses->dfltuid;
809 inode->i_gid = v9ses->gid; 809 inode->i_gid = v9ses->dfltgid;
810 810
811 if (v9ses->extended) { 811 if (v9fs_extended(v9ses)) {
812 inode->i_uid = stat->n_uid; 812 inode->i_uid = stat->n_uid;
813 inode->i_gid = stat->n_gid; 813 inode->i_gid = stat->n_gid;
814 } 814 }
@@ -887,10 +887,10 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen)
887 retval = -EPERM; 887 retval = -EPERM;
888 v9ses = v9fs_inode2v9ses(dentry->d_inode); 888 v9ses = v9fs_inode2v9ses(dentry->d_inode);
889 fid = v9fs_fid_lookup(dentry); 889 fid = v9fs_fid_lookup(dentry);
890 if(IS_ERR(fid)) 890 if (IS_ERR(fid))
891 return PTR_ERR(fid); 891 return PTR_ERR(fid);
892 892
893 if (!v9ses->extended) 893 if (!v9fs_extended(v9ses))
894 return -EBADF; 894 return -EBADF;
895 895
896 st = p9_client_stat(fid); 896 st = p9_client_stat(fid);
@@ -1011,7 +1011,7 @@ static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry,
1011 struct p9_fid *fid; 1011 struct p9_fid *fid;
1012 1012
1013 v9ses = v9fs_inode2v9ses(dir); 1013 v9ses = v9fs_inode2v9ses(dir);
1014 if (!v9ses->extended) { 1014 if (!v9fs_extended(v9ses)) {
1015 P9_DPRINTK(P9_DEBUG_ERROR, "not extended\n"); 1015 P9_DPRINTK(P9_DEBUG_ERROR, "not extended\n");
1016 return -EPERM; 1016 return -EPERM;
1017 } 1017 }
@@ -1070,7 +1070,7 @@ v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir,
1070 old_dentry->d_name.name); 1070 old_dentry->d_name.name);
1071 1071
1072 oldfid = v9fs_fid_clone(old_dentry); 1072 oldfid = v9fs_fid_clone(old_dentry);
1073 if(IS_ERR(oldfid)) 1073 if (IS_ERR(oldfid))
1074 return PTR_ERR(oldfid); 1074 return PTR_ERR(oldfid);
1075 1075
1076 name = __getname(); 1076 name = __getname();
diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c
index ba904371218b..bb0cef9a6b8a 100644
--- a/fs/9p/vfs_super.c
+++ b/fs/9p/vfs_super.c
@@ -216,24 +216,7 @@ static int v9fs_show_options(struct seq_file *m, struct vfsmount *mnt)
216{ 216{
217 struct v9fs_session_info *v9ses = mnt->mnt_sb->s_fs_info; 217 struct v9fs_session_info *v9ses = mnt->mnt_sb->s_fs_info;
218 218
219 if (v9ses->debug != 0) 219 seq_printf(m, "%s", v9ses->options);
220 seq_printf(m, ",debug=%x", v9ses->debug);
221 if (v9ses->port != V9FS_PORT)
222 seq_printf(m, ",port=%u", v9ses->port);
223 if (v9ses->maxdata != 9000)
224 seq_printf(m, ",msize=%u", v9ses->maxdata);
225 if (v9ses->afid != ~0)
226 seq_printf(m, ",afid=%u", v9ses->afid);
227 if (v9ses->proto == PROTO_UNIX)
228 seq_puts(m, ",proto=unix");
229 if (v9ses->extended == 0)
230 seq_puts(m, ",noextend");
231 if (v9ses->nodev == 1)
232 seq_puts(m, ",nodevmap");
233 seq_printf(m, ",name=%s", v9ses->name);
234 seq_printf(m, ",aname=%s", v9ses->remotename);
235 seq_printf(m, ",uid=%u", v9ses->uid);
236 seq_printf(m, ",gid=%u", v9ses->gid);
237 return 0; 220 return 0;
238} 221}
239 222
diff --git a/include/linux/mmc/sdio_ids.h b/include/linux/mmc/sdio_ids.h
index 09306d47ff5e..ea1bf5ba092f 100644
--- a/include/linux/mmc/sdio_ids.h
+++ b/include/linux/mmc/sdio_ids.h
@@ -19,5 +19,11 @@
19#define SDIO_CLASS_WLAN 0x07 /* WLAN interface */ 19#define SDIO_CLASS_WLAN 0x07 /* WLAN interface */
20#define SDIO_CLASS_ATA 0x08 /* Embedded SDIO-ATA std interface */ 20#define SDIO_CLASS_ATA 0x08 /* Embedded SDIO-ATA std interface */
21 21
22/*
23 * Vendors and devices. Sort key: vendor first, device next.
24 */
25
26#define SDIO_VENDOR_ID_MARVELL 0x02df
27#define SDIO_DEVICE_ID_MARVELL_LIBERTAS 0x9103
22 28
23#endif 29#endif
diff --git a/include/net/9p/9p.h b/include/net/9p/9p.h
index 7726ff41c3e6..686425a97b0f 100644
--- a/include/net/9p/9p.h
+++ b/include/net/9p/9p.h
@@ -216,6 +216,7 @@ struct p9_tauth {
216 u32 afid; 216 u32 afid;
217 struct p9_str uname; 217 struct p9_str uname;
218 struct p9_str aname; 218 struct p9_str aname;
219 u32 n_uname; /* 9P2000.u extensions */
219}; 220};
220 221
221struct p9_rauth { 222struct p9_rauth {
@@ -239,6 +240,7 @@ struct p9_tattach {
239 u32 afid; 240 u32 afid;
240 struct p9_str uname; 241 struct p9_str uname;
241 struct p9_str aname; 242 struct p9_str aname;
243 u32 n_uname; /* 9P2000.u extensions */
242}; 244};
243 245
244struct p9_rattach { 246struct p9_rattach {
@@ -382,8 +384,9 @@ int p9_deserialize_fcall(void *buf, u32 buflen, struct p9_fcall *fc, int dotu);
382void p9_set_tag(struct p9_fcall *fc, u16 tag); 384void p9_set_tag(struct p9_fcall *fc, u16 tag);
383struct p9_fcall *p9_create_tversion(u32 msize, char *version); 385struct p9_fcall *p9_create_tversion(u32 msize, char *version);
384struct p9_fcall *p9_create_tattach(u32 fid, u32 afid, char *uname, 386struct p9_fcall *p9_create_tattach(u32 fid, u32 afid, char *uname,
385 char *aname); 387 char *aname, u32 n_uname, int dotu);
386struct p9_fcall *p9_create_tauth(u32 afid, char *uname, char *aname); 388struct p9_fcall *p9_create_tauth(u32 afid, char *uname, char *aname,
389 u32 n_uname, int dotu);
387struct p9_fcall *p9_create_tflush(u16 oldtag); 390struct p9_fcall *p9_create_tflush(u16 oldtag);
388struct p9_fcall *p9_create_twalk(u32 fid, u32 newfid, u16 nwname, 391struct p9_fcall *p9_create_twalk(u32 fid, u32 newfid, u16 nwname,
389 char **wnames); 392 char **wnames);
@@ -412,18 +415,4 @@ int p9_idpool_check(int id, struct p9_idpool *p);
412 415
413int p9_error_init(void); 416int p9_error_init(void);
414int p9_errstr2errno(char *, int); 417int p9_errstr2errno(char *, int);
415
416#ifdef CONFIG_SYSCTL
417int __init p9_sysctl_register(void);
418void __exit p9_sysctl_unregister(void);
419#else
420static inline int p9_sysctl_register(void)
421{
422 return 0;
423}
424static inline void p9_sysctl_unregister(void)
425{
426}
427#endif
428
429#endif /* NET_9P_H */ 418#endif /* NET_9P_H */
diff --git a/include/net/9p/client.h b/include/net/9p/client.h
index d65ed7c69063..9b9221a21392 100644
--- a/include/net/9p/client.h
+++ b/include/net/9p/client.h
@@ -29,7 +29,7 @@ struct p9_client {
29 spinlock_t lock; /* protect client structure */ 29 spinlock_t lock; /* protect client structure */
30 int msize; 30 int msize;
31 unsigned char dotu; 31 unsigned char dotu;
32 struct p9_transport *trans; 32 struct p9_trans *trans;
33 struct p9_conn *conn; 33 struct p9_conn *conn;
34 34
35 struct p9_idpool *fidpool; 35 struct p9_idpool *fidpool;
@@ -52,13 +52,14 @@ struct p9_fid {
52 struct list_head dlist; /* list of all fids attached to a dentry */ 52 struct list_head dlist; /* list of all fids attached to a dentry */
53}; 53};
54 54
55struct p9_client *p9_client_create(struct p9_transport *trans, int msize, 55struct p9_client *p9_client_create(struct p9_trans *trans, int msize,
56 int dotu); 56 int dotu);
57void p9_client_destroy(struct p9_client *clnt); 57void p9_client_destroy(struct p9_client *clnt);
58void p9_client_disconnect(struct p9_client *clnt); 58void p9_client_disconnect(struct p9_client *clnt);
59struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid, 59struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid,
60 char *uname, char *aname); 60 char *uname, u32 n_uname, char *aname);
61struct p9_fid *p9_client_auth(struct p9_client *clnt, char *uname, char *aname); 61struct p9_fid *p9_client_auth(struct p9_client *clnt, char *uname,
62 u32 n_uname, char *aname);
62struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames, 63struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames,
63 int clone); 64 int clone);
64int p9_client_open(struct p9_fid *fid, int mode); 65int p9_client_open(struct p9_fid *fid, int mode);
diff --git a/include/net/9p/conn.h b/include/net/9p/conn.h
index 583b6a2cb3df..756d8784f953 100644
--- a/include/net/9p/conn.h
+++ b/include/net/9p/conn.h
@@ -42,8 +42,8 @@ struct p9_req;
42 */ 42 */
43typedef void (*p9_conn_req_callback)(struct p9_req *req, void *a); 43typedef void (*p9_conn_req_callback)(struct p9_req *req, void *a);
44 44
45struct p9_conn *p9_conn_create(struct p9_transport *trans, int msize, 45struct p9_conn *p9_conn_create(struct p9_trans *trans, int msize,
46 unsigned char *dotu); 46 unsigned char *dotu);
47void p9_conn_destroy(struct p9_conn *); 47void p9_conn_destroy(struct p9_conn *);
48int p9_conn_rpc(struct p9_conn *m, struct p9_fcall *tc, struct p9_fcall **rc); 48int p9_conn_rpc(struct p9_conn *m, struct p9_fcall *tc, struct p9_fcall **rc);
49 49
diff --git a/include/net/9p/transport.h b/include/net/9p/transport.h
index 462d42279fb0..9dd4a05619a8 100644
--- a/include/net/9p/transport.h
+++ b/include/net/9p/transport.h
@@ -26,24 +26,31 @@
26#ifndef NET_9P_TRANSPORT_H 26#ifndef NET_9P_TRANSPORT_H
27#define NET_9P_TRANSPORT_H 27#define NET_9P_TRANSPORT_H
28 28
29enum p9_transport_status { 29enum p9_trans_status {
30 Connected, 30 Connected,
31 Disconnected, 31 Disconnected,
32 Hung, 32 Hung,
33}; 33};
34 34
35struct p9_transport { 35struct p9_trans {
36 enum p9_transport_status status; 36 enum p9_trans_status status;
37 void *priv; 37 void *priv;
38 int (*write) (struct p9_trans *, void *, int);
39 int (*read) (struct p9_trans *, void *, int);
40 void (*close) (struct p9_trans *);
41 unsigned int (*poll)(struct p9_trans *, struct poll_table_struct *);
42};
38 43
39 int (*write) (struct p9_transport *, void *, int); 44struct p9_trans_module {
40 int (*read) (struct p9_transport *, void *, int); 45 struct list_head list;
41 void (*close) (struct p9_transport *); 46 char *name; /* name of transport */
42 unsigned int (*poll)(struct p9_transport *, struct poll_table_struct *); 47 int maxsize; /* max message size of transport */
48 int def; /* this transport should be default */
49 struct p9_trans * (*create)(const char *devname, char *options);
43}; 50};
44 51
45struct p9_transport *p9_trans_create_tcp(const char *addr, int port); 52void v9fs_register_trans(struct p9_trans_module *m);
46struct p9_transport *p9_trans_create_unix(const char *addr); 53struct p9_trans_module *v9fs_match_trans(const substring_t *name);
47struct p9_transport *p9_trans_create_fd(int rfd, int wfd); 54struct p9_trans_module *v9fs_default_trans(void);
48 55
49#endif /* NET_9P_TRANSPORT_H */ 56#endif /* NET_9P_TRANSPORT_H */
diff --git a/net/9p/Kconfig b/net/9p/Kconfig
index 66821cd64a76..eecbf12f6393 100644
--- a/net/9p/Kconfig
+++ b/net/9p/Kconfig
@@ -13,6 +13,16 @@ menuconfig NET_9P
13 13
14 If unsure, say N. 14 If unsure, say N.
15 15
16config NET_9P_FD
17 depends on NET_9P
18 default y if NET_9P
19 tristate "9P File Descriptor Transports (Experimental)"
20 help
21 This builds support for file descriptor transports for 9p
22 which includes support for TCP/IP, named pipes, or passed
23 file descriptors. TCP/IP is the default transport for 9p,
24 so if you are going to use 9p, you'll likely want this.
25
16config NET_9P_DEBUG 26config NET_9P_DEBUG
17 bool "Debug information" 27 bool "Debug information"
18 depends on NET_9P 28 depends on NET_9P
diff --git a/net/9p/Makefile b/net/9p/Makefile
index 85b3a7838acf..5059bc06f8f3 100644
--- a/net/9p/Makefile
+++ b/net/9p/Makefile
@@ -1,8 +1,8 @@
1obj-$(CONFIG_NET_9P) := 9pnet.o 1obj-$(CONFIG_NET_9P) := 9pnet.o
2obj-$(CONFIG_NET_9P_FD) += 9pnet_fd.o
2 3
39pnet-objs := \ 49pnet-objs := \
4 mod.o \ 5 mod.o \
5 trans_fd.o \
6 mux.o \ 6 mux.o \
7 client.o \ 7 client.o \
8 conv.o \ 8 conv.o \
@@ -10,4 +10,5 @@ obj-$(CONFIG_NET_9P) := 9pnet.o
10 fcprint.o \ 10 fcprint.o \
11 util.o \ 11 util.o \
12 12
139pnet-$(CONFIG_SYSCTL) += sysctl.o 139pnet_fd-objs := \
14 trans_fd.o \
diff --git a/net/9p/client.c b/net/9p/client.c
index cb170750337c..af9199364049 100644
--- a/net/9p/client.c
+++ b/net/9p/client.c
@@ -30,6 +30,7 @@
30#include <linux/sched.h> 30#include <linux/sched.h>
31#include <linux/uaccess.h> 31#include <linux/uaccess.h>
32#include <net/9p/9p.h> 32#include <net/9p/9p.h>
33#include <linux/parser.h>
33#include <net/9p/transport.h> 34#include <net/9p/transport.h>
34#include <net/9p/conn.h> 35#include <net/9p/conn.h>
35#include <net/9p/client.h> 36#include <net/9p/client.h>
@@ -38,7 +39,7 @@ static struct p9_fid *p9_fid_create(struct p9_client *clnt);
38static void p9_fid_destroy(struct p9_fid *fid); 39static void p9_fid_destroy(struct p9_fid *fid);
39static struct p9_stat *p9_clone_stat(struct p9_stat *st, int dotu); 40static struct p9_stat *p9_clone_stat(struct p9_stat *st, int dotu);
40 41
41struct p9_client *p9_client_create(struct p9_transport *trans, int msize, 42struct p9_client *p9_client_create(struct p9_trans *trans, int msize,
42 int dotu) 43 int dotu)
43{ 44{
44 int err, n; 45 int err, n;
@@ -146,7 +147,7 @@ void p9_client_disconnect(struct p9_client *clnt)
146EXPORT_SYMBOL(p9_client_disconnect); 147EXPORT_SYMBOL(p9_client_disconnect);
147 148
148struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid, 149struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid,
149 char *uname, char *aname) 150 char *uname, u32 n_uname, char *aname)
150{ 151{
151 int err; 152 int err;
152 struct p9_fcall *tc, *rc; 153 struct p9_fcall *tc, *rc;
@@ -165,7 +166,8 @@ struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid,
165 goto error; 166 goto error;
166 } 167 }
167 168
168 tc = p9_create_tattach(fid->fid, afid?afid->fid:P9_NOFID, uname, aname); 169 tc = p9_create_tattach(fid->fid, afid?afid->fid:P9_NOFID, uname, aname,
170 n_uname, clnt->dotu);
169 if (IS_ERR(tc)) { 171 if (IS_ERR(tc)) {
170 err = PTR_ERR(tc); 172 err = PTR_ERR(tc);
171 tc = NULL; 173 tc = NULL;
@@ -190,7 +192,8 @@ error:
190} 192}
191EXPORT_SYMBOL(p9_client_attach); 193EXPORT_SYMBOL(p9_client_attach);
192 194
193struct p9_fid *p9_client_auth(struct p9_client *clnt, char *uname, char *aname) 195struct p9_fid *p9_client_auth(struct p9_client *clnt, char *uname,
196 u32 n_uname, char *aname)
194{ 197{
195 int err; 198 int err;
196 struct p9_fcall *tc, *rc; 199 struct p9_fcall *tc, *rc;
@@ -209,7 +212,7 @@ struct p9_fid *p9_client_auth(struct p9_client *clnt, char *uname, char *aname)
209 goto error; 212 goto error;
210 } 213 }
211 214
212 tc = p9_create_tauth(fid->fid, uname, aname); 215 tc = p9_create_tauth(fid->fid, uname, aname, n_uname, clnt->dotu);
213 if (IS_ERR(tc)) { 216 if (IS_ERR(tc)) {
214 err = PTR_ERR(tc); 217 err = PTR_ERR(tc);
215 tc = NULL; 218 tc = NULL;
diff --git a/net/9p/conv.c b/net/9p/conv.c
index d979d958ea19..aa2aa9884f95 100644
--- a/net/9p/conv.c
+++ b/net/9p/conv.c
@@ -547,7 +547,8 @@ error:
547} 547}
548EXPORT_SYMBOL(p9_create_tversion); 548EXPORT_SYMBOL(p9_create_tversion);
549 549
550struct p9_fcall *p9_create_tauth(u32 afid, char *uname, char *aname) 550struct p9_fcall *p9_create_tauth(u32 afid, char *uname, char *aname,
551 u32 n_uname, int dotu)
551{ 552{
552 int size; 553 int size;
553 struct p9_fcall *fc; 554 struct p9_fcall *fc;
@@ -555,7 +556,16 @@ struct p9_fcall *p9_create_tauth(u32 afid, char *uname, char *aname)
555 struct cbuf *bufp = &buffer; 556 struct cbuf *bufp = &buffer;
556 557
557 /* afid[4] uname[s] aname[s] */ 558 /* afid[4] uname[s] aname[s] */
558 size = 4 + 2 + strlen(uname) + 2 + strlen(aname); 559 size = 4 + 2 + 2;
560 if (uname)
561 size += strlen(uname);
562
563 if (aname)
564 size += strlen(aname);
565
566 if (dotu)
567 size += 4; /* n_uname */
568
559 fc = p9_create_common(bufp, size, P9_TAUTH); 569 fc = p9_create_common(bufp, size, P9_TAUTH);
560 if (IS_ERR(fc)) 570 if (IS_ERR(fc))
561 goto error; 571 goto error;
@@ -563,6 +573,8 @@ struct p9_fcall *p9_create_tauth(u32 afid, char *uname, char *aname)
563 p9_put_int32(bufp, afid, &fc->params.tauth.afid); 573 p9_put_int32(bufp, afid, &fc->params.tauth.afid);
564 p9_put_str(bufp, uname, &fc->params.tauth.uname); 574 p9_put_str(bufp, uname, &fc->params.tauth.uname);
565 p9_put_str(bufp, aname, &fc->params.tauth.aname); 575 p9_put_str(bufp, aname, &fc->params.tauth.aname);
576 if (dotu)
577 p9_put_int32(bufp, n_uname, &fc->params.tauth.n_uname);
566 578
567 if (buf_check_overflow(bufp)) { 579 if (buf_check_overflow(bufp)) {
568 kfree(fc); 580 kfree(fc);
@@ -574,7 +586,8 @@ error:
574EXPORT_SYMBOL(p9_create_tauth); 586EXPORT_SYMBOL(p9_create_tauth);
575 587
576struct p9_fcall * 588struct p9_fcall *
577p9_create_tattach(u32 fid, u32 afid, char *uname, char *aname) 589p9_create_tattach(u32 fid, u32 afid, char *uname, char *aname,
590 u32 n_uname, int dotu)
578{ 591{
579 int size; 592 int size;
580 struct p9_fcall *fc; 593 struct p9_fcall *fc;
@@ -582,7 +595,16 @@ p9_create_tattach(u32 fid, u32 afid, char *uname, char *aname)
582 struct cbuf *bufp = &buffer; 595 struct cbuf *bufp = &buffer;
583 596
584 /* fid[4] afid[4] uname[s] aname[s] */ 597 /* fid[4] afid[4] uname[s] aname[s] */
585 size = 4 + 4 + 2 + strlen(uname) + 2 + strlen(aname); 598 size = 4 + 4 + 2 + 2;
599 if (uname)
600 size += strlen(uname);
601
602 if (aname)
603 size += strlen(aname);
604
605 if (dotu)
606 size += 4; /* n_uname */
607
586 fc = p9_create_common(bufp, size, P9_TATTACH); 608 fc = p9_create_common(bufp, size, P9_TATTACH);
587 if (IS_ERR(fc)) 609 if (IS_ERR(fc))
588 goto error; 610 goto error;
@@ -591,6 +613,8 @@ p9_create_tattach(u32 fid, u32 afid, char *uname, char *aname)
591 p9_put_int32(bufp, afid, &fc->params.tattach.afid); 613 p9_put_int32(bufp, afid, &fc->params.tattach.afid);
592 p9_put_str(bufp, uname, &fc->params.tattach.uname); 614 p9_put_str(bufp, uname, &fc->params.tattach.uname);
593 p9_put_str(bufp, aname, &fc->params.tattach.aname); 615 p9_put_str(bufp, aname, &fc->params.tattach.aname);
616 if (dotu)
617 p9_put_int32(bufp, n_uname, &fc->params.tattach.n_uname);
594 618
595error: 619error:
596 return fc; 620 return fc;
diff --git a/net/9p/mod.c b/net/9p/mod.c
index 4f9e1d2ac257..41d70f47375d 100644
--- a/net/9p/mod.c
+++ b/net/9p/mod.c
@@ -27,6 +27,10 @@
27#include <linux/module.h> 27#include <linux/module.h>
28#include <linux/moduleparam.h> 28#include <linux/moduleparam.h>
29#include <net/9p/9p.h> 29#include <net/9p/9p.h>
30#include <linux/fs.h>
31#include <linux/parser.h>
32#include <net/9p/transport.h>
33#include <linux/list.h>
30 34
31#ifdef CONFIG_NET_9P_DEBUG 35#ifdef CONFIG_NET_9P_DEBUG
32unsigned int p9_debug_level = 0; /* feature-rific global debug level */ 36unsigned int p9_debug_level = 0; /* feature-rific global debug level */
@@ -37,8 +41,64 @@ MODULE_PARM_DESC(debug, "9P debugging level");
37 41
38extern int p9_mux_global_init(void); 42extern int p9_mux_global_init(void);
39extern void p9_mux_global_exit(void); 43extern void p9_mux_global_exit(void);
40extern int p9_sysctl_register(void); 44
41extern void p9_sysctl_unregister(void); 45/*
46 * Dynamic Transport Registration Routines
47 *
48 */
49
50static LIST_HEAD(v9fs_trans_list);
51static struct p9_trans_module *v9fs_default_transport;
52
53/**
54 * v9fs_register_trans - register a new transport with 9p
55 * @m - structure describing the transport module and entry points
56 *
57 */
58void v9fs_register_trans(struct p9_trans_module *m)
59{
60 list_add_tail(&m->list, &v9fs_trans_list);
61 if (m->def)
62 v9fs_default_transport = m;
63}
64EXPORT_SYMBOL(v9fs_register_trans);
65
66/**
67 * v9fs_match_trans - match transport versus registered transports
68 * @arg: string identifying transport
69 *
70 */
71struct p9_trans_module *v9fs_match_trans(const substring_t *name)
72{
73 struct list_head *p;
74 struct p9_trans_module *t = NULL;
75
76 list_for_each(p, &v9fs_trans_list) {
77 t = list_entry(p, struct p9_trans_module, list);
78 if (strncmp(t->name, name->from, name->to-name->from) == 0)
79 break;
80 }
81 return t;
82}
83EXPORT_SYMBOL(v9fs_match_trans);
84
85/**
86 * v9fs_default_trans - returns pointer to default transport
87 *
88 */
89
90struct p9_trans_module *v9fs_default_trans(void)
91{
92 if (v9fs_default_transport)
93 return v9fs_default_transport;
94 else if (!list_empty(&v9fs_trans_list))
95 return list_first_entry(&v9fs_trans_list,
96 struct p9_trans_module, list);
97 else
98 return NULL;
99}
100EXPORT_SYMBOL(v9fs_default_trans);
101
42 102
43/** 103/**
44 * v9fs_init - Initialize module 104 * v9fs_init - Initialize module
@@ -56,12 +116,6 @@ static int __init init_p9(void)
56 return ret; 116 return ret;
57 } 117 }
58 118
59 ret = p9_sysctl_register();
60 if (ret) {
61 printk(KERN_WARNING "9p: registering sysctl failed\n");
62 return ret;
63 }
64
65 return ret; 119 return ret;
66} 120}
67 121
@@ -72,7 +126,6 @@ static int __init init_p9(void)
72 126
73static void __exit exit_p9(void) 127static void __exit exit_p9(void)
74{ 128{
75 p9_sysctl_unregister();
76 p9_mux_global_exit(); 129 p9_mux_global_exit();
77} 130}
78 131
diff --git a/net/9p/mux.c b/net/9p/mux.c
index 5d70558c4c61..f14014793bed 100644
--- a/net/9p/mux.c
+++ b/net/9p/mux.c
@@ -31,6 +31,7 @@
31#include <linux/idr.h> 31#include <linux/idr.h>
32#include <linux/mutex.h> 32#include <linux/mutex.h>
33#include <net/9p/9p.h> 33#include <net/9p/9p.h>
34#include <linux/parser.h>
34#include <net/9p/transport.h> 35#include <net/9p/transport.h>
35#include <net/9p/conn.h> 36#include <net/9p/conn.h>
36 37
@@ -71,7 +72,7 @@ struct p9_conn {
71 struct p9_mux_poll_task *poll_task; 72 struct p9_mux_poll_task *poll_task;
72 int msize; 73 int msize;
73 unsigned char *extended; 74 unsigned char *extended;
74 struct p9_transport *trans; 75 struct p9_trans *trans;
75 struct p9_idpool *tagpool; 76 struct p9_idpool *tagpool;
76 int err; 77 int err;
77 wait_queue_head_t equeue; 78 wait_queue_head_t equeue;
@@ -271,7 +272,7 @@ static void p9_mux_poll_stop(struct p9_conn *m)
271 * @msize - maximum message size 272 * @msize - maximum message size
272 * @extended - pointer to the extended flag 273 * @extended - pointer to the extended flag
273 */ 274 */
274struct p9_conn *p9_conn_create(struct p9_transport *trans, int msize, 275struct p9_conn *p9_conn_create(struct p9_trans *trans, int msize,
275 unsigned char *extended) 276 unsigned char *extended)
276{ 277{
277 int i, n; 278 int i, n;
diff --git a/net/9p/sysctl.c b/net/9p/sysctl.c
deleted file mode 100644
index 8b61027a24ea..000000000000
--- a/net/9p/sysctl.c
+++ /dev/null
@@ -1,81 +0,0 @@
1/*
2 * net/9p/sysctl.c
3 *
4 * 9P sysctl interface
5 *
6 * Copyright (C) 2007 by Latchesar Ionkov <lucho@ionkov.net>
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 version 2
10 * as published by the Free Software Foundation.
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#include <linux/kernel.h>
26#include <linux/mm.h>
27#include <linux/sysctl.h>
28#include <linux/init.h>
29#include <net/9p/9p.h>
30
31static struct ctl_table p9_table[] = {
32#ifdef CONFIG_NET_9P_DEBUG
33 {
34 .ctl_name = CTL_UNNUMBERED,
35 .procname = "debug",
36 .data = &p9_debug_level,
37 .maxlen = sizeof(int),
38 .mode = 0644,
39 .proc_handler = &proc_dointvec
40 },
41#endif
42 {},
43};
44
45static struct ctl_table p9_net_table[] = {
46 {
47 .ctl_name = CTL_UNNUMBERED,
48 .procname = "9p",
49 .maxlen = 0,
50 .mode = 0555,
51 .child = p9_table,
52 },
53 {},
54};
55
56static struct ctl_table p9_ctl_table[] = {
57 {
58 .ctl_name = CTL_NET,
59 .procname = "net",
60 .maxlen = 0,
61 .mode = 0555,
62 .child = p9_net_table,
63 },
64 {},
65};
66
67static struct ctl_table_header *p9_table_header;
68
69int __init p9_sysctl_register(void)
70{
71 p9_table_header = register_sysctl_table(p9_ctl_table);
72 if (!p9_table_header)
73 return -ENOMEM;
74
75 return 0;
76}
77
78void __exit p9_sysctl_unregister(void)
79{
80 unregister_sysctl_table(p9_table_header);
81}
diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c
index fd636e94358f..30269a4ff22a 100644
--- a/net/9p/trans_fd.c
+++ b/net/9p/trans_fd.c
@@ -5,7 +5,7 @@
5 * 5 *
6 * Copyright (C) 2006 by Russ Cox <rsc@swtch.com> 6 * Copyright (C) 2006 by Russ Cox <rsc@swtch.com>
7 * Copyright (C) 2004-2005 by Latchesar Ionkov <lucho@ionkov.net> 7 * Copyright (C) 2004-2005 by Latchesar Ionkov <lucho@ionkov.net>
8 * Copyright (C) 2004-2005 by Eric Van Hensbergen <ericvh@gmail.com> 8 * Copyright (C) 2004-2007 by Eric Van Hensbergen <ericvh@gmail.com>
9 * Copyright (C) 1997-2002 by Ron Minnich <rminnich@sarnoff.com> 9 * Copyright (C) 1997-2002 by Ron Minnich <rminnich@sarnoff.com>
10 * 10 *
11 * This program is free software; you can redistribute it and/or modify 11 * This program is free software; you can redistribute it and/or modify
@@ -36,160 +36,114 @@
36#include <linux/inet.h> 36#include <linux/inet.h>
37#include <linux/idr.h> 37#include <linux/idr.h>
38#include <linux/file.h> 38#include <linux/file.h>
39#include <linux/parser.h>
39#include <net/9p/9p.h> 40#include <net/9p/9p.h>
40#include <net/9p/transport.h> 41#include <net/9p/transport.h>
41 42
42#define P9_PORT 564 43#define P9_PORT 564
44#define MAX_SOCK_BUF (64*1024)
45
46
47struct p9_fd_opts {
48 int rfd;
49 int wfd;
50 u16 port;
51};
43 52
44struct p9_trans_fd { 53struct p9_trans_fd {
45 struct file *rd; 54 struct file *rd;
46 struct file *wr; 55 struct file *wr;
47}; 56};
48 57
49static int p9_socket_open(struct p9_transport *trans, struct socket *csocket); 58/*
50static int p9_fd_open(struct p9_transport *trans, int rfd, int wfd); 59 * Option Parsing (code inspired by NFS code)
51static int p9_fd_read(struct p9_transport *trans, void *v, int len); 60 * - a little lazy - parse all fd-transport options
52static int p9_fd_write(struct p9_transport *trans, void *v, int len); 61 */
53static unsigned int p9_fd_poll(struct p9_transport *trans,
54 struct poll_table_struct *pt);
55static void p9_fd_close(struct p9_transport *trans);
56
57struct p9_transport *p9_trans_create_tcp(const char *addr, int port)
58{
59 int err;
60 struct p9_transport *trans;
61 struct socket *csocket;
62 struct sockaddr_in sin_server;
63
64 csocket = NULL;
65 trans = kmalloc(sizeof(struct p9_transport), GFP_KERNEL);
66 if (!trans)
67 return ERR_PTR(-ENOMEM);
68
69 trans->write = p9_fd_write;
70 trans->read = p9_fd_read;
71 trans->close = p9_fd_close;
72 trans->poll = p9_fd_poll;
73
74 sin_server.sin_family = AF_INET;
75 sin_server.sin_addr.s_addr = in_aton(addr);
76 sin_server.sin_port = htons(port);
77 sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &csocket);
78
79 if (!csocket) {
80 P9_EPRINTK(KERN_ERR, "p9_trans_tcp: problem creating socket\n");
81 err = -EIO;
82 goto error;
83 }
84
85 err = csocket->ops->connect(csocket,
86 (struct sockaddr *)&sin_server,
87 sizeof(struct sockaddr_in), 0);
88 if (err < 0) {
89 P9_EPRINTK(KERN_ERR,
90 "p9_trans_tcp: problem connecting socket to %s\n",
91 addr);
92 goto error;
93 }
94
95 err = p9_socket_open(trans, csocket);
96 if (err < 0)
97 goto error;
98 62
99 return trans; 63enum {
64 /* Options that take integer arguments */
65 Opt_port, Opt_rfdno, Opt_wfdno,
66};
100 67
101error: 68static match_table_t tokens = {
102 if (csocket) 69 {Opt_port, "port=%u"},
103 sock_release(csocket); 70 {Opt_rfdno, "rfdno=%u"},
71 {Opt_wfdno, "wfdno=%u"},
72};
104 73
105 kfree(trans); 74/**
106 return ERR_PTR(err); 75 * v9fs_parse_options - parse mount options into session structure
107} 76 * @options: options string passed from mount
108EXPORT_SYMBOL(p9_trans_create_tcp); 77 * @v9ses: existing v9fs session information
78 *
79 */
109 80
110struct p9_transport *p9_trans_create_unix(const char *addr) 81static void parse_opts(char *options, struct p9_fd_opts *opts)
111{ 82{
112 int err; 83 char *p;
113 struct socket *csocket; 84 substring_t args[MAX_OPT_ARGS];
114 struct sockaddr_un sun_server; 85 int option;
115 struct p9_transport *trans; 86 int ret;
116
117 csocket = NULL;
118 trans = kmalloc(sizeof(struct p9_transport), GFP_KERNEL);
119 if (!trans)
120 return ERR_PTR(-ENOMEM);
121 87
122 trans->write = p9_fd_write; 88 opts->port = P9_PORT;
123 trans->read = p9_fd_read; 89 opts->rfd = ~0;
124 trans->close = p9_fd_close; 90 opts->wfd = ~0;
125 trans->poll = p9_fd_poll;
126 91
127 if (strlen(addr) > UNIX_PATH_MAX) { 92 if (!options)
128 P9_EPRINTK(KERN_ERR, "p9_trans_unix: address too long: %s\n", 93 return;
129 addr);
130 err = -ENAMETOOLONG;
131 goto error;
132 }
133 94
134 sun_server.sun_family = PF_UNIX; 95 while ((p = strsep(&options, ",")) != NULL) {
135 strcpy(sun_server.sun_path, addr); 96 int token;
136 sock_create_kern(PF_UNIX, SOCK_STREAM, 0, &csocket); 97 if (!*p)
137 err = csocket->ops->connect(csocket, (struct sockaddr *)&sun_server, 98 continue;
138 sizeof(struct sockaddr_un) - 1, 0); 99 token = match_token(p, tokens, args);
139 if (err < 0) { 100 ret = match_int(&args[0], &option);
140 P9_EPRINTK(KERN_ERR, 101 if (ret < 0) {
141 "p9_trans_unix: problem connecting socket: %s: %d\n", 102 P9_DPRINTK(P9_DEBUG_ERROR,
142 addr, err); 103 "integer field, but no integer?\n");
143 goto error; 104 continue;
105 }
106 switch (token) {
107 case Opt_port:
108 opts->port = option;
109 break;
110 case Opt_rfdno:
111 opts->rfd = option;
112 break;
113 case Opt_wfdno:
114 opts->wfd = option;
115 break;
116 default:
117 continue;
118 }
144 } 119 }
145
146 err = p9_socket_open(trans, csocket);
147 if (err < 0)
148 goto error;
149
150 return trans;
151
152error:
153 if (csocket)
154 sock_release(csocket);
155
156 kfree(trans);
157 return ERR_PTR(err);
158} 120}
159EXPORT_SYMBOL(p9_trans_create_unix);
160 121
161struct p9_transport *p9_trans_create_fd(int rfd, int wfd) 122static int p9_fd_open(struct p9_trans *trans, int rfd, int wfd)
162{ 123{
163 int err; 124 struct p9_trans_fd *ts = kmalloc(sizeof(struct p9_trans_fd),
164 struct p9_transport *trans; 125 GFP_KERNEL);
126 if (!ts)
127 return -ENOMEM;
165 128
166 if (rfd == ~0 || wfd == ~0) { 129 ts->rd = fget(rfd);
167 printk(KERN_ERR "v9fs: Insufficient options for proto=fd\n"); 130 ts->wr = fget(wfd);
168 return ERR_PTR(-ENOPROTOOPT); 131 if (!ts->rd || !ts->wr) {
132 if (ts->rd)
133 fput(ts->rd);
134 if (ts->wr)
135 fput(ts->wr);
136 kfree(ts);
137 return -EIO;
169 } 138 }
170 139
171 trans = kmalloc(sizeof(struct p9_transport), GFP_KERNEL); 140 trans->priv = ts;
172 if (!trans) 141 trans->status = Connected;
173 return ERR_PTR(-ENOMEM);
174
175 trans->write = p9_fd_write;
176 trans->read = p9_fd_read;
177 trans->close = p9_fd_close;
178 trans->poll = p9_fd_poll;
179
180 err = p9_fd_open(trans, rfd, wfd);
181 if (err < 0)
182 goto error;
183
184 return trans;
185 142
186error: 143 return 0;
187 kfree(trans);
188 return ERR_PTR(err);
189} 144}
190EXPORT_SYMBOL(p9_trans_create_fd);
191 145
192static int p9_socket_open(struct p9_transport *trans, struct socket *csocket) 146static int p9_socket_open(struct p9_trans *trans, struct socket *csocket)
193{ 147{
194 int fd, ret; 148 int fd, ret;
195 149
@@ -212,30 +166,6 @@ static int p9_socket_open(struct p9_transport *trans, struct socket *csocket)
212 return 0; 166 return 0;
213} 167}
214 168
215static int p9_fd_open(struct p9_transport *trans, int rfd, int wfd)
216{
217 struct p9_trans_fd *ts = kmalloc(sizeof(struct p9_trans_fd),
218 GFP_KERNEL);
219 if (!ts)
220 return -ENOMEM;
221
222 ts->rd = fget(rfd);
223 ts->wr = fget(wfd);
224 if (!ts->rd || !ts->wr) {
225 if (ts->rd)
226 fput(ts->rd);
227 if (ts->wr)
228 fput(ts->wr);
229 kfree(ts);
230 return -EIO;
231 }
232
233 trans->priv = ts;
234 trans->status = Connected;
235
236 return 0;
237}
238
239/** 169/**
240 * p9_fd_read- read from a fd 170 * p9_fd_read- read from a fd
241 * @v9ses: session information 171 * @v9ses: session information
@@ -243,7 +173,7 @@ static int p9_fd_open(struct p9_transport *trans, int rfd, int wfd)
243 * @len: size of receive buffer 173 * @len: size of receive buffer
244 * 174 *
245 */ 175 */
246static int p9_fd_read(struct p9_transport *trans, void *v, int len) 176static int p9_fd_read(struct p9_trans *trans, void *v, int len)
247{ 177{
248 int ret; 178 int ret;
249 struct p9_trans_fd *ts = NULL; 179 struct p9_trans_fd *ts = NULL;
@@ -270,7 +200,7 @@ static int p9_fd_read(struct p9_transport *trans, void *v, int len)
270 * @len: size of send buffer 200 * @len: size of send buffer
271 * 201 *
272 */ 202 */
273static int p9_fd_write(struct p9_transport *trans, void *v, int len) 203static int p9_fd_write(struct p9_trans *trans, void *v, int len)
274{ 204{
275 int ret; 205 int ret;
276 mm_segment_t oldfs; 206 mm_segment_t oldfs;
@@ -297,7 +227,7 @@ static int p9_fd_write(struct p9_transport *trans, void *v, int len)
297} 227}
298 228
299static unsigned int 229static unsigned int
300p9_fd_poll(struct p9_transport *trans, struct poll_table_struct *pt) 230p9_fd_poll(struct p9_trans *trans, struct poll_table_struct *pt)
301{ 231{
302 int ret, n; 232 int ret, n;
303 struct p9_trans_fd *ts = NULL; 233 struct p9_trans_fd *ts = NULL;
@@ -341,7 +271,7 @@ end:
341 * @trans: private socket structure 271 * @trans: private socket structure
342 * 272 *
343 */ 273 */
344static void p9_fd_close(struct p9_transport *trans) 274static void p9_fd_close(struct p9_trans *trans)
345{ 275{
346 struct p9_trans_fd *ts; 276 struct p9_trans_fd *ts;
347 277
@@ -361,3 +291,182 @@ static void p9_fd_close(struct p9_transport *trans)
361 kfree(ts); 291 kfree(ts);
362} 292}
363 293
294static struct p9_trans *p9_trans_create_tcp(const char *addr, char *args)
295{
296 int err;
297 struct p9_trans *trans;
298 struct socket *csocket;
299 struct sockaddr_in sin_server;
300 struct p9_fd_opts opts;
301
302 parse_opts(args, &opts);
303
304 csocket = NULL;
305 trans = kmalloc(sizeof(struct p9_trans), GFP_KERNEL);
306 if (!trans)
307 return ERR_PTR(-ENOMEM);
308
309 trans->write = p9_fd_write;
310 trans->read = p9_fd_read;
311 trans->close = p9_fd_close;
312 trans->poll = p9_fd_poll;
313
314 sin_server.sin_family = AF_INET;
315 sin_server.sin_addr.s_addr = in_aton(addr);
316 sin_server.sin_port = htons(opts.port);
317 sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &csocket);
318
319 if (!csocket) {
320 P9_EPRINTK(KERN_ERR, "p9_trans_tcp: problem creating socket\n");
321 err = -EIO;
322 goto error;
323 }
324
325 err = csocket->ops->connect(csocket,
326 (struct sockaddr *)&sin_server,
327 sizeof(struct sockaddr_in), 0);
328 if (err < 0) {
329 P9_EPRINTK(KERN_ERR,
330 "p9_trans_tcp: problem connecting socket to %s\n",
331 addr);
332 goto error;
333 }
334
335 err = p9_socket_open(trans, csocket);
336 if (err < 0)
337 goto error;
338
339 return trans;
340
341error:
342 if (csocket)
343 sock_release(csocket);
344
345 kfree(trans);
346 return ERR_PTR(err);
347}
348
349static struct p9_trans *p9_trans_create_unix(const char *addr, char *args)
350{
351 int err;
352 struct socket *csocket;
353 struct sockaddr_un sun_server;
354 struct p9_trans *trans;
355
356 csocket = NULL;
357 trans = kmalloc(sizeof(struct p9_trans), GFP_KERNEL);
358 if (!trans)
359 return ERR_PTR(-ENOMEM);
360
361 trans->write = p9_fd_write;
362 trans->read = p9_fd_read;
363 trans->close = p9_fd_close;
364 trans->poll = p9_fd_poll;
365
366 if (strlen(addr) > UNIX_PATH_MAX) {
367 P9_EPRINTK(KERN_ERR, "p9_trans_unix: address too long: %s\n",
368 addr);
369 err = -ENAMETOOLONG;
370 goto error;
371 }
372
373 sun_server.sun_family = PF_UNIX;
374 strcpy(sun_server.sun_path, addr);
375 sock_create_kern(PF_UNIX, SOCK_STREAM, 0, &csocket);
376 err = csocket->ops->connect(csocket, (struct sockaddr *)&sun_server,
377 sizeof(struct sockaddr_un) - 1, 0);
378 if (err < 0) {
379 P9_EPRINTK(KERN_ERR,
380 "p9_trans_unix: problem connecting socket: %s: %d\n",
381 addr, err);
382 goto error;
383 }
384
385 err = p9_socket_open(trans, csocket);
386 if (err < 0)
387 goto error;
388
389 return trans;
390
391error:
392 if (csocket)
393 sock_release(csocket);
394
395 kfree(trans);
396 return ERR_PTR(err);
397}
398
399static struct p9_trans *p9_trans_create_fd(const char *name, char *args)
400{
401 int err;
402 struct p9_trans *trans;
403 struct p9_fd_opts opts;
404
405 parse_opts(args, &opts);
406
407 if (opts.rfd == ~0 || opts.wfd == ~0) {
408 printk(KERN_ERR "v9fs: Insufficient options for proto=fd\n");
409 return ERR_PTR(-ENOPROTOOPT);
410 }
411
412 trans = kmalloc(sizeof(struct p9_trans), GFP_KERNEL);
413 if (!trans)
414 return ERR_PTR(-ENOMEM);
415
416 trans->write = p9_fd_write;
417 trans->read = p9_fd_read;
418 trans->close = p9_fd_close;
419 trans->poll = p9_fd_poll;
420
421 err = p9_fd_open(trans, opts.rfd, opts.wfd);
422 if (err < 0)
423 goto error;
424
425 return trans;
426
427error:
428 kfree(trans);
429 return ERR_PTR(err);
430}
431
432static struct p9_trans_module p9_tcp_trans = {
433 .name = "tcp",
434 .maxsize = MAX_SOCK_BUF,
435 .def = 1,
436 .create = p9_trans_create_tcp,
437};
438
439static struct p9_trans_module p9_unix_trans = {
440 .name = "unix",
441 .maxsize = MAX_SOCK_BUF,
442 .def = 0,
443 .create = p9_trans_create_unix,
444};
445
446static struct p9_trans_module p9_fd_trans = {
447 .name = "fd",
448 .maxsize = MAX_SOCK_BUF,
449 .def = 0,
450 .create = p9_trans_create_fd,
451};
452
453static int __init p9_trans_fd_init(void)
454{
455 v9fs_register_trans(&p9_tcp_trans);
456 v9fs_register_trans(&p9_unix_trans);
457 v9fs_register_trans(&p9_fd_trans);
458
459 return 1;
460}
461
462static void __exit p9_trans_fd_exit(void) {
463 printk(KERN_ERR "Removal of 9p transports not implemented\n");
464 BUG();
465}
466
467module_init(p9_trans_fd_init);
468module_exit(p9_trans_fd_exit);
469
470MODULE_AUTHOR("Latchesar Ionkov <lucho@ionkov.net>");
471MODULE_AUTHOR("Eric Van Hensbergen <ericvh@gmail.com>");
472MODULE_LICENSE("GPL");