diff options
-rw-r--r-- | Documentation/filesystems/sysfs.txt | 5 | ||||
-rw-r--r-- | fs/fuse/dev.c | 35 | ||||
-rw-r--r-- | fs/fuse/fuse_i.h | 12 | ||||
-rw-r--r-- | fs/fuse/inode.c | 40 | ||||
-rw-r--r-- | net/bridge/br_forward.c | 8 |
5 files changed, 59 insertions, 41 deletions
diff --git a/Documentation/filesystems/sysfs.txt b/Documentation/filesystems/sysfs.txt index c8bce82ddcac..89b1d196ca80 100644 --- a/Documentation/filesystems/sysfs.txt +++ b/Documentation/filesystems/sysfs.txt | |||
@@ -246,6 +246,7 @@ class/ | |||
246 | devices/ | 246 | devices/ |
247 | firmware/ | 247 | firmware/ |
248 | net/ | 248 | net/ |
249 | fs/ | ||
249 | 250 | ||
250 | devices/ contains a filesystem representation of the device tree. It maps | 251 | devices/ contains a filesystem representation of the device tree. It maps |
251 | directly to the internal kernel device tree, which is a hierarchy of | 252 | directly to the internal kernel device tree, which is a hierarchy of |
@@ -264,6 +265,10 @@ drivers/ contains a directory for each device driver that is loaded | |||
264 | for devices on that particular bus (this assumes that drivers do not | 265 | for devices on that particular bus (this assumes that drivers do not |
265 | span multiple bus types). | 266 | span multiple bus types). |
266 | 267 | ||
268 | fs/ contains a directory for some filesystems. Currently each | ||
269 | filesystem wanting to export attributes must create its own hierarchy | ||
270 | below fs/ (see ./fuse.txt for an example). | ||
271 | |||
267 | 272 | ||
268 | More information can driver-model specific features can be found in | 273 | More information can driver-model specific features can be found in |
269 | Documentation/driver-model/. | 274 | Documentation/driver-model/. |
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index cc750c68fe70..104a62dadb94 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c | |||
@@ -128,14 +128,24 @@ void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req) | |||
128 | } | 128 | } |
129 | } | 129 | } |
130 | 130 | ||
131 | void fuse_remove_background(struct fuse_conn *fc, struct fuse_req *req) | 131 | /* |
132 | * Called with sbput_sem held for read (request_end) or write | ||
133 | * (fuse_put_super). By the time fuse_put_super() is finished, all | ||
134 | * inodes belonging to background requests must be released, so the | ||
135 | * iputs have to be done within the locked region. | ||
136 | */ | ||
137 | void fuse_release_background(struct fuse_conn *fc, struct fuse_req *req) | ||
132 | { | 138 | { |
133 | list_del_init(&req->bg_entry); | 139 | iput(req->inode); |
140 | iput(req->inode2); | ||
141 | spin_lock(&fc->lock); | ||
142 | list_del(&req->bg_entry); | ||
134 | if (fc->num_background == FUSE_MAX_BACKGROUND) { | 143 | if (fc->num_background == FUSE_MAX_BACKGROUND) { |
135 | fc->blocked = 0; | 144 | fc->blocked = 0; |
136 | wake_up_all(&fc->blocked_waitq); | 145 | wake_up_all(&fc->blocked_waitq); |
137 | } | 146 | } |
138 | fc->num_background--; | 147 | fc->num_background--; |
148 | spin_unlock(&fc->lock); | ||
139 | } | 149 | } |
140 | 150 | ||
141 | /* | 151 | /* |
@@ -165,27 +175,22 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req) | |||
165 | wake_up(&req->waitq); | 175 | wake_up(&req->waitq); |
166 | fuse_put_request(fc, req); | 176 | fuse_put_request(fc, req); |
167 | } else { | 177 | } else { |
168 | struct inode *inode = req->inode; | ||
169 | struct inode *inode2 = req->inode2; | ||
170 | struct file *file = req->file; | ||
171 | void (*end) (struct fuse_conn *, struct fuse_req *) = req->end; | 178 | void (*end) (struct fuse_conn *, struct fuse_req *) = req->end; |
172 | req->end = NULL; | 179 | req->end = NULL; |
173 | req->inode = NULL; | ||
174 | req->inode2 = NULL; | ||
175 | req->file = NULL; | ||
176 | if (!list_empty(&req->bg_entry)) | ||
177 | fuse_remove_background(fc, req); | ||
178 | spin_unlock(&fc->lock); | 180 | spin_unlock(&fc->lock); |
181 | down_read(&fc->sbput_sem); | ||
182 | if (fc->mounted) | ||
183 | fuse_release_background(fc, req); | ||
184 | up_read(&fc->sbput_sem); | ||
185 | |||
186 | /* fput must go outside sbput_sem, otherwise it can deadlock */ | ||
187 | if (req->file) | ||
188 | fput(req->file); | ||
179 | 189 | ||
180 | if (end) | 190 | if (end) |
181 | end(fc, req); | 191 | end(fc, req); |
182 | else | 192 | else |
183 | fuse_put_request(fc, req); | 193 | fuse_put_request(fc, req); |
184 | |||
185 | if (file) | ||
186 | fput(file); | ||
187 | iput(inode); | ||
188 | iput(inode2); | ||
189 | } | 194 | } |
190 | } | 195 | } |
191 | 196 | ||
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 59661c481d9d..0474202cb5dc 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h | |||
@@ -258,9 +258,15 @@ struct fuse_conn { | |||
258 | /** waitq for blocked connection */ | 258 | /** waitq for blocked connection */ |
259 | wait_queue_head_t blocked_waitq; | 259 | wait_queue_head_t blocked_waitq; |
260 | 260 | ||
261 | /** RW semaphore for exclusion with fuse_put_super() */ | ||
262 | struct rw_semaphore sbput_sem; | ||
263 | |||
261 | /** The next unique request id */ | 264 | /** The next unique request id */ |
262 | u64 reqctr; | 265 | u64 reqctr; |
263 | 266 | ||
267 | /** Mount is active */ | ||
268 | unsigned mounted; | ||
269 | |||
264 | /** Connection established, cleared on umount, connection | 270 | /** Connection established, cleared on umount, connection |
265 | abort and device release */ | 271 | abort and device release */ |
266 | unsigned connected; | 272 | unsigned connected; |
@@ -471,11 +477,11 @@ void request_send_noreply(struct fuse_conn *fc, struct fuse_req *req); | |||
471 | void request_send_background(struct fuse_conn *fc, struct fuse_req *req); | 477 | void request_send_background(struct fuse_conn *fc, struct fuse_req *req); |
472 | 478 | ||
473 | /** | 479 | /** |
474 | * Remove request from the the background list | 480 | * Release inodes and file associated with background request |
475 | */ | 481 | */ |
476 | void fuse_remove_background(struct fuse_conn *fc, struct fuse_req *req); | 482 | void fuse_release_background(struct fuse_conn *fc, struct fuse_req *req); |
477 | 483 | ||
478 | /** Abort all requests */ | 484 | /* Abort all requests */ |
479 | void fuse_abort_conn(struct fuse_conn *fc); | 485 | void fuse_abort_conn(struct fuse_conn *fc); |
480 | 486 | ||
481 | /** | 487 | /** |
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 43a6fc0db8a7..7627022446b2 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c | |||
@@ -204,26 +204,17 @@ static void fuse_put_super(struct super_block *sb) | |||
204 | { | 204 | { |
205 | struct fuse_conn *fc = get_fuse_conn_super(sb); | 205 | struct fuse_conn *fc = get_fuse_conn_super(sb); |
206 | 206 | ||
207 | down_write(&fc->sbput_sem); | ||
208 | while (!list_empty(&fc->background)) | ||
209 | fuse_release_background(fc, | ||
210 | list_entry(fc->background.next, | ||
211 | struct fuse_req, bg_entry)); | ||
212 | |||
207 | spin_lock(&fc->lock); | 213 | spin_lock(&fc->lock); |
214 | fc->mounted = 0; | ||
208 | fc->connected = 0; | 215 | fc->connected = 0; |
209 | while (!list_empty(&fc->background)) { | ||
210 | struct fuse_req *req = list_entry(fc->background.next, | ||
211 | struct fuse_req, bg_entry); | ||
212 | struct inode *inode = req->inode; | ||
213 | struct inode *inode2 = req->inode2; | ||
214 | |||
215 | /* File would hold a reference to vfsmount */ | ||
216 | BUG_ON(req->file); | ||
217 | req->inode = NULL; | ||
218 | req->inode2 = NULL; | ||
219 | fuse_remove_background(fc, req); | ||
220 | |||
221 | spin_unlock(&fc->lock); | ||
222 | iput(inode); | ||
223 | iput(inode2); | ||
224 | spin_lock(&fc->lock); | ||
225 | } | ||
226 | spin_unlock(&fc->lock); | 216 | spin_unlock(&fc->lock); |
217 | up_write(&fc->sbput_sem); | ||
227 | /* Flush all readers on this fs */ | 218 | /* Flush all readers on this fs */ |
228 | kill_fasync(&fc->fasync, SIGIO, POLL_IN); | 219 | kill_fasync(&fc->fasync, SIGIO, POLL_IN); |
229 | wake_up_all(&fc->waitq); | 220 | wake_up_all(&fc->waitq); |
@@ -395,6 +386,7 @@ static struct fuse_conn *new_conn(void) | |||
395 | INIT_LIST_HEAD(&fc->processing); | 386 | INIT_LIST_HEAD(&fc->processing); |
396 | INIT_LIST_HEAD(&fc->io); | 387 | INIT_LIST_HEAD(&fc->io); |
397 | INIT_LIST_HEAD(&fc->background); | 388 | INIT_LIST_HEAD(&fc->background); |
389 | init_rwsem(&fc->sbput_sem); | ||
398 | kobj_set_kset_s(fc, connections_subsys); | 390 | kobj_set_kset_s(fc, connections_subsys); |
399 | kobject_init(&fc->kobj); | 391 | kobject_init(&fc->kobj); |
400 | atomic_set(&fc->num_waiting, 0); | 392 | atomic_set(&fc->num_waiting, 0); |
@@ -508,11 +500,6 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) | |||
508 | if (file->f_op != &fuse_dev_operations) | 500 | if (file->f_op != &fuse_dev_operations) |
509 | return -EINVAL; | 501 | return -EINVAL; |
510 | 502 | ||
511 | /* Setting file->private_data can't race with other mount() | ||
512 | instances, since BKL is held for ->get_sb() */ | ||
513 | if (file->private_data) | ||
514 | return -EINVAL; | ||
515 | |||
516 | fc = new_conn(); | 503 | fc = new_conn(); |
517 | if (!fc) | 504 | if (!fc) |
518 | return -ENOMEM; | 505 | return -ENOMEM; |
@@ -548,7 +535,14 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) | |||
548 | if (err) | 535 | if (err) |
549 | goto err_free_req; | 536 | goto err_free_req; |
550 | 537 | ||
538 | /* Setting file->private_data can't race with other mount() | ||
539 | instances, since BKL is held for ->get_sb() */ | ||
540 | err = -EINVAL; | ||
541 | if (file->private_data) | ||
542 | goto err_kobject_del; | ||
543 | |||
551 | sb->s_root = root_dentry; | 544 | sb->s_root = root_dentry; |
545 | fc->mounted = 1; | ||
552 | fc->connected = 1; | 546 | fc->connected = 1; |
553 | kobject_get(&fc->kobj); | 547 | kobject_get(&fc->kobj); |
554 | file->private_data = fc; | 548 | file->private_data = fc; |
@@ -563,6 +557,8 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) | |||
563 | 557 | ||
564 | return 0; | 558 | return 0; |
565 | 559 | ||
560 | err_kobject_del: | ||
561 | kobject_del(&fc->kobj); | ||
566 | err_free_req: | 562 | err_free_req: |
567 | fuse_request_free(init_req); | 563 | fuse_request_free(init_req); |
568 | err_put_root: | 564 | err_put_root: |
diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c index 2d24fb400e0c..56f3aa47e758 100644 --- a/net/bridge/br_forward.c +++ b/net/bridge/br_forward.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
17 | #include <linux/netdevice.h> | 17 | #include <linux/netdevice.h> |
18 | #include <linux/skbuff.h> | 18 | #include <linux/skbuff.h> |
19 | #include <linux/if_vlan.h> | ||
19 | #include <linux/netfilter_bridge.h> | 20 | #include <linux/netfilter_bridge.h> |
20 | #include "br_private.h" | 21 | #include "br_private.h" |
21 | 22 | ||
@@ -29,10 +30,15 @@ static inline int should_deliver(const struct net_bridge_port *p, | |||
29 | return 1; | 30 | return 1; |
30 | } | 31 | } |
31 | 32 | ||
33 | static inline unsigned packet_length(const struct sk_buff *skb) | ||
34 | { | ||
35 | return skb->len - (skb->protocol == htons(ETH_P_8021Q) ? VLAN_HLEN : 0); | ||
36 | } | ||
37 | |||
32 | int br_dev_queue_push_xmit(struct sk_buff *skb) | 38 | int br_dev_queue_push_xmit(struct sk_buff *skb) |
33 | { | 39 | { |
34 | /* drop mtu oversized packets except tso */ | 40 | /* drop mtu oversized packets except tso */ |
35 | if (skb->len > skb->dev->mtu && !skb_shinfo(skb)->tso_size) | 41 | if (packet_length(skb) > skb->dev->mtu && !skb_shinfo(skb)->tso_size) |
36 | kfree_skb(skb); | 42 | kfree_skb(skb); |
37 | else { | 43 | else { |
38 | #ifdef CONFIG_BRIDGE_NETFILTER | 44 | #ifdef CONFIG_BRIDGE_NETFILTER |