diff options
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/exec.c | 27 | ||||
| -rw-r--r-- | fs/ext3/resize.c | 1 | ||||
| -rw-r--r-- | fs/fuse/dev.c | 54 | ||||
| -rw-r--r-- | fs/fuse/file.c | 10 | ||||
| -rw-r--r-- | fs/fuse/fuse_i.h | 15 | ||||
| -rw-r--r-- | fs/fuse/inode.c | 27 | ||||
| -rw-r--r-- | fs/partitions/check.c | 43 | ||||
| -rw-r--r-- | fs/pipe.c | 7 | ||||
| -rw-r--r-- | fs/splice.c | 272 | ||||
| -rw-r--r-- | fs/sysfs/dir.c | 1 | ||||
| -rw-r--r-- | fs/sysfs/file.c | 76 | ||||
| -rw-r--r-- | fs/sysfs/sysfs.h | 1 | ||||
| -rw-r--r-- | fs/xfs/linux-2.6/xfs_file.c | 12 | ||||
| -rw-r--r-- | fs/xfs/linux-2.6/xfs_lrw.c | 14 | ||||
| -rw-r--r-- | fs/xfs/linux-2.6/xfs_lrw.h | 4 | ||||
| -rw-r--r-- | fs/xfs/linux-2.6/xfs_vnode.h | 12 |
16 files changed, 440 insertions, 136 deletions
| @@ -665,9 +665,7 @@ static int de_thread(struct task_struct *tsk) | |||
| 665 | * and to assume its PID: | 665 | * and to assume its PID: |
| 666 | */ | 666 | */ |
| 667 | if (!thread_group_leader(current)) { | 667 | if (!thread_group_leader(current)) { |
| 668 | struct task_struct *parent; | ||
| 669 | struct dentry *proc_dentry1, *proc_dentry2; | 668 | struct dentry *proc_dentry1, *proc_dentry2; |
| 670 | unsigned long ptrace; | ||
| 671 | 669 | ||
| 672 | /* | 670 | /* |
| 673 | * Wait for the thread group leader to be a zombie. | 671 | * Wait for the thread group leader to be a zombie. |
| @@ -704,22 +702,6 @@ static int de_thread(struct task_struct *tsk) | |||
| 704 | * two threads with a switched PID, and release | 702 | * two threads with a switched PID, and release |
| 705 | * the former thread group leader: | 703 | * the former thread group leader: |
| 706 | */ | 704 | */ |
| 707 | ptrace = leader->ptrace; | ||
| 708 | parent = leader->parent; | ||
| 709 | if (unlikely(ptrace) && unlikely(parent == current)) { | ||
| 710 | /* | ||
| 711 | * Joker was ptracing his own group leader, | ||
| 712 | * and now he wants to be his own parent! | ||
| 713 | * We can't have that. | ||
| 714 | */ | ||
| 715 | ptrace = 0; | ||
| 716 | } | ||
| 717 | |||
| 718 | ptrace_unlink(current); | ||
| 719 | ptrace_unlink(leader); | ||
| 720 | remove_parent(current); | ||
| 721 | remove_parent(leader); | ||
| 722 | |||
| 723 | 705 | ||
| 724 | /* Become a process group leader with the old leader's pid. | 706 | /* Become a process group leader with the old leader's pid. |
| 725 | * Note: The old leader also uses thispid until release_task | 707 | * Note: The old leader also uses thispid until release_task |
| @@ -732,8 +714,6 @@ static int de_thread(struct task_struct *tsk) | |||
| 732 | attach_pid(current, PIDTYPE_SID, current->signal->session); | 714 | attach_pid(current, PIDTYPE_SID, current->signal->session); |
| 733 | list_add_tail(¤t->tasks, &init_task.tasks); | 715 | list_add_tail(¤t->tasks, &init_task.tasks); |
| 734 | 716 | ||
| 735 | current->parent = current->real_parent = leader->real_parent; | ||
| 736 | leader->parent = leader->real_parent = child_reaper; | ||
| 737 | current->group_leader = current; | 717 | current->group_leader = current; |
| 738 | leader->group_leader = current; | 718 | leader->group_leader = current; |
| 739 | 719 | ||
| @@ -742,13 +722,6 @@ static int de_thread(struct task_struct *tsk) | |||
| 742 | detach_pid(leader, PIDTYPE_SID); | 722 | detach_pid(leader, PIDTYPE_SID); |
| 743 | list_del_init(&leader->tasks); | 723 | list_del_init(&leader->tasks); |
| 744 | 724 | ||
| 745 | add_parent(current); | ||
| 746 | add_parent(leader); | ||
| 747 | if (ptrace) { | ||
| 748 | current->ptrace = ptrace; | ||
| 749 | __ptrace_link(current, parent); | ||
| 750 | } | ||
| 751 | |||
| 752 | current->exit_signal = SIGCHLD; | 725 | current->exit_signal = SIGCHLD; |
| 753 | 726 | ||
| 754 | BUG_ON(leader->exit_state != EXIT_ZOMBIE); | 727 | BUG_ON(leader->exit_state != EXIT_ZOMBIE); |
diff --git a/fs/ext3/resize.c b/fs/ext3/resize.c index 14f5f6ea3e72..c5ffa8523968 100644 --- a/fs/ext3/resize.c +++ b/fs/ext3/resize.c | |||
| @@ -767,6 +767,7 @@ int ext3_group_add(struct super_block *sb, struct ext3_new_group_data *input) | |||
| 767 | if (input->group != sbi->s_groups_count) { | 767 | if (input->group != sbi->s_groups_count) { |
| 768 | ext3_warning(sb, __FUNCTION__, | 768 | ext3_warning(sb, __FUNCTION__, |
| 769 | "multiple resizers run on filesystem!"); | 769 | "multiple resizers run on filesystem!"); |
| 770 | unlock_super(sb); | ||
| 770 | err = -EBUSY; | 771 | err = -EBUSY; |
| 771 | goto exit_journal; | 772 | goto exit_journal; |
| 772 | } | 773 | } |
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 6c740f860665..cc750c68fe70 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c | |||
| @@ -92,48 +92,50 @@ struct fuse_req *fuse_get_req(struct fuse_conn *fc) | |||
| 92 | { | 92 | { |
| 93 | struct fuse_req *req; | 93 | struct fuse_req *req; |
| 94 | sigset_t oldset; | 94 | sigset_t oldset; |
| 95 | int intr; | ||
| 95 | int err; | 96 | int err; |
| 96 | 97 | ||
| 98 | atomic_inc(&fc->num_waiting); | ||
| 97 | block_sigs(&oldset); | 99 | block_sigs(&oldset); |
| 98 | err = wait_event_interruptible(fc->blocked_waitq, !fc->blocked); | 100 | intr = wait_event_interruptible(fc->blocked_waitq, !fc->blocked); |
| 99 | restore_sigs(&oldset); | 101 | restore_sigs(&oldset); |
| 100 | if (err) | 102 | err = -EINTR; |
| 101 | return ERR_PTR(-EINTR); | 103 | if (intr) |
| 104 | goto out; | ||
| 102 | 105 | ||
| 103 | req = fuse_request_alloc(); | 106 | req = fuse_request_alloc(); |
| 107 | err = -ENOMEM; | ||
| 104 | if (!req) | 108 | if (!req) |
| 105 | return ERR_PTR(-ENOMEM); | 109 | goto out; |
| 106 | 110 | ||
| 107 | atomic_inc(&fc->num_waiting); | ||
| 108 | fuse_request_init(req); | ||
| 109 | req->in.h.uid = current->fsuid; | 111 | req->in.h.uid = current->fsuid; |
| 110 | req->in.h.gid = current->fsgid; | 112 | req->in.h.gid = current->fsgid; |
| 111 | req->in.h.pid = current->pid; | 113 | req->in.h.pid = current->pid; |
| 114 | req->waiting = 1; | ||
| 112 | return req; | 115 | return req; |
| 116 | |||
| 117 | out: | ||
| 118 | atomic_dec(&fc->num_waiting); | ||
| 119 | return ERR_PTR(err); | ||
| 113 | } | 120 | } |
| 114 | 121 | ||
| 115 | void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req) | 122 | void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req) |
| 116 | { | 123 | { |
| 117 | if (atomic_dec_and_test(&req->count)) { | 124 | if (atomic_dec_and_test(&req->count)) { |
| 118 | atomic_dec(&fc->num_waiting); | 125 | if (req->waiting) |
| 126 | atomic_dec(&fc->num_waiting); | ||
| 119 | fuse_request_free(req); | 127 | fuse_request_free(req); |
| 120 | } | 128 | } |
| 121 | } | 129 | } |
| 122 | 130 | ||
| 123 | void fuse_release_background(struct fuse_conn *fc, struct fuse_req *req) | 131 | void fuse_remove_background(struct fuse_conn *fc, struct fuse_req *req) |
| 124 | { | 132 | { |
| 125 | iput(req->inode); | 133 | list_del_init(&req->bg_entry); |
| 126 | iput(req->inode2); | ||
| 127 | if (req->file) | ||
| 128 | fput(req->file); | ||
| 129 | spin_lock(&fc->lock); | ||
| 130 | list_del(&req->bg_entry); | ||
| 131 | if (fc->num_background == FUSE_MAX_BACKGROUND) { | 134 | if (fc->num_background == FUSE_MAX_BACKGROUND) { |
| 132 | fc->blocked = 0; | 135 | fc->blocked = 0; |
| 133 | wake_up_all(&fc->blocked_waitq); | 136 | wake_up_all(&fc->blocked_waitq); |
| 134 | } | 137 | } |
| 135 | fc->num_background--; | 138 | fc->num_background--; |
| 136 | spin_unlock(&fc->lock); | ||
| 137 | } | 139 | } |
| 138 | 140 | ||
| 139 | /* | 141 | /* |
| @@ -163,17 +165,27 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req) | |||
| 163 | wake_up(&req->waitq); | 165 | wake_up(&req->waitq); |
| 164 | fuse_put_request(fc, req); | 166 | fuse_put_request(fc, req); |
| 165 | } else { | 167 | } else { |
| 168 | struct inode *inode = req->inode; | ||
| 169 | struct inode *inode2 = req->inode2; | ||
| 170 | struct file *file = req->file; | ||
| 166 | void (*end) (struct fuse_conn *, struct fuse_req *) = req->end; | 171 | void (*end) (struct fuse_conn *, struct fuse_req *) = req->end; |
| 167 | req->end = NULL; | 172 | 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); | ||
| 168 | spin_unlock(&fc->lock); | 178 | spin_unlock(&fc->lock); |
| 169 | down_read(&fc->sbput_sem); | 179 | |
| 170 | if (fc->mounted) | ||
| 171 | fuse_release_background(fc, req); | ||
| 172 | up_read(&fc->sbput_sem); | ||
| 173 | if (end) | 180 | if (end) |
| 174 | end(fc, req); | 181 | end(fc, req); |
| 175 | else | 182 | else |
| 176 | fuse_put_request(fc, req); | 183 | fuse_put_request(fc, req); |
| 184 | |||
| 185 | if (file) | ||
| 186 | fput(file); | ||
| 187 | iput(inode); | ||
| 188 | iput(inode2); | ||
| 177 | } | 189 | } |
| 178 | } | 190 | } |
| 179 | 191 | ||
| @@ -277,6 +289,10 @@ static void queue_request(struct fuse_conn *fc, struct fuse_req *req) | |||
| 277 | len_args(req->in.numargs, (struct fuse_arg *) req->in.args); | 289 | len_args(req->in.numargs, (struct fuse_arg *) req->in.args); |
| 278 | list_add_tail(&req->list, &fc->pending); | 290 | list_add_tail(&req->list, &fc->pending); |
| 279 | req->state = FUSE_REQ_PENDING; | 291 | req->state = FUSE_REQ_PENDING; |
| 292 | if (!req->waiting) { | ||
| 293 | req->waiting = 1; | ||
| 294 | atomic_inc(&fc->num_waiting); | ||
| 295 | } | ||
| 280 | wake_up(&fc->waitq); | 296 | wake_up(&fc->waitq); |
| 281 | kill_fasync(&fc->fasync, SIGIO, POLL_IN); | 297 | kill_fasync(&fc->fasync, SIGIO, POLL_IN); |
| 282 | } | 298 | } |
diff --git a/fs/fuse/file.c b/fs/fuse/file.c index e4f041a11bb5..fc342cf7c2cc 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | /* | 1 | /* |
| 2 | FUSE: Filesystem in Userspace | 2 | FUSE: Filesystem in Userspace |
| 3 | Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.hu> | 3 | Copyright (C) 2001-2006 Miklos Szeredi <miklos@szeredi.hu> |
| 4 | 4 | ||
| 5 | This program can be distributed under the terms of the GNU GPL. | 5 | This program can be distributed under the terms of the GNU GPL. |
| 6 | See the file COPYING. | 6 | See the file COPYING. |
| @@ -565,8 +565,12 @@ static ssize_t fuse_direct_io(struct file *file, const char __user *buf, | |||
| 565 | buf += nres; | 565 | buf += nres; |
| 566 | if (nres != nbytes) | 566 | if (nres != nbytes) |
| 567 | break; | 567 | break; |
| 568 | if (count) | 568 | if (count) { |
| 569 | fuse_reset_request(req); | 569 | fuse_put_request(fc, req); |
| 570 | req = fuse_get_req(fc); | ||
| 571 | if (IS_ERR(req)) | ||
| 572 | break; | ||
| 573 | } | ||
| 570 | } | 574 | } |
| 571 | fuse_put_request(fc, req); | 575 | fuse_put_request(fc, req); |
| 572 | if (res > 0) { | 576 | if (res > 0) { |
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 19c7185a7546..59661c481d9d 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h | |||
| @@ -159,6 +159,9 @@ struct fuse_req { | |||
| 159 | /** Data is being copied to/from the request */ | 159 | /** Data is being copied to/from the request */ |
| 160 | unsigned locked:1; | 160 | unsigned locked:1; |
| 161 | 161 | ||
| 162 | /** Request is counted as "waiting" */ | ||
| 163 | unsigned waiting:1; | ||
| 164 | |||
| 162 | /** State of the request */ | 165 | /** State of the request */ |
| 163 | enum fuse_req_state state; | 166 | enum fuse_req_state state; |
| 164 | 167 | ||
| @@ -255,15 +258,9 @@ struct fuse_conn { | |||
| 255 | /** waitq for blocked connection */ | 258 | /** waitq for blocked connection */ |
| 256 | wait_queue_head_t blocked_waitq; | 259 | wait_queue_head_t blocked_waitq; |
| 257 | 260 | ||
| 258 | /** RW semaphore for exclusion with fuse_put_super() */ | ||
| 259 | struct rw_semaphore sbput_sem; | ||
| 260 | |||
| 261 | /** The next unique request id */ | 261 | /** The next unique request id */ |
| 262 | u64 reqctr; | 262 | u64 reqctr; |
| 263 | 263 | ||
| 264 | /** Mount is active */ | ||
| 265 | unsigned mounted; | ||
| 266 | |||
| 267 | /** Connection established, cleared on umount, connection | 264 | /** Connection established, cleared on umount, connection |
| 268 | abort and device release */ | 265 | abort and device release */ |
| 269 | unsigned connected; | 266 | unsigned connected; |
| @@ -474,11 +471,11 @@ void request_send_noreply(struct fuse_conn *fc, struct fuse_req *req); | |||
| 474 | void request_send_background(struct fuse_conn *fc, struct fuse_req *req); | 471 | void request_send_background(struct fuse_conn *fc, struct fuse_req *req); |
| 475 | 472 | ||
| 476 | /** | 473 | /** |
| 477 | * Release inodes and file associated with background request | 474 | * Remove request from the the background list |
| 478 | */ | 475 | */ |
| 479 | void fuse_release_background(struct fuse_conn *fc, struct fuse_req *req); | 476 | void fuse_remove_background(struct fuse_conn *fc, struct fuse_req *req); |
| 480 | 477 | ||
| 481 | /* Abort all requests */ | 478 | /** Abort all requests */ |
| 482 | void fuse_abort_conn(struct fuse_conn *fc); | 479 | void fuse_abort_conn(struct fuse_conn *fc); |
| 483 | 480 | ||
| 484 | /** | 481 | /** |
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index fd34037b0588..43a6fc0db8a7 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c | |||
| @@ -204,17 +204,26 @@ 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 | |||
| 213 | spin_lock(&fc->lock); | 207 | spin_lock(&fc->lock); |
| 214 | fc->mounted = 0; | ||
| 215 | fc->connected = 0; | 208 | 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 | } | ||
| 216 | spin_unlock(&fc->lock); | 226 | spin_unlock(&fc->lock); |
| 217 | up_write(&fc->sbput_sem); | ||
| 218 | /* Flush all readers on this fs */ | 227 | /* Flush all readers on this fs */ |
| 219 | kill_fasync(&fc->fasync, SIGIO, POLL_IN); | 228 | kill_fasync(&fc->fasync, SIGIO, POLL_IN); |
| 220 | wake_up_all(&fc->waitq); | 229 | wake_up_all(&fc->waitq); |
| @@ -386,7 +395,6 @@ static struct fuse_conn *new_conn(void) | |||
| 386 | INIT_LIST_HEAD(&fc->processing); | 395 | INIT_LIST_HEAD(&fc->processing); |
| 387 | INIT_LIST_HEAD(&fc->io); | 396 | INIT_LIST_HEAD(&fc->io); |
| 388 | INIT_LIST_HEAD(&fc->background); | 397 | INIT_LIST_HEAD(&fc->background); |
| 389 | init_rwsem(&fc->sbput_sem); | ||
| 390 | kobj_set_kset_s(fc, connections_subsys); | 398 | kobj_set_kset_s(fc, connections_subsys); |
| 391 | kobject_init(&fc->kobj); | 399 | kobject_init(&fc->kobj); |
| 392 | atomic_set(&fc->num_waiting, 0); | 400 | atomic_set(&fc->num_waiting, 0); |
| @@ -541,7 +549,6 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) | |||
| 541 | goto err_free_req; | 549 | goto err_free_req; |
| 542 | 550 | ||
| 543 | sb->s_root = root_dentry; | 551 | sb->s_root = root_dentry; |
| 544 | fc->mounted = 1; | ||
| 545 | fc->connected = 1; | 552 | fc->connected = 1; |
| 546 | kobject_get(&fc->kobj); | 553 | kobject_get(&fc->kobj); |
| 547 | file->private_data = fc; | 554 | file->private_data = fc; |
diff --git a/fs/partitions/check.c b/fs/partitions/check.c index af0cb4b9e784..45ae7dd3c650 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c | |||
| @@ -331,7 +331,9 @@ void delete_partition(struct gendisk *disk, int part) | |||
| 331 | devfs_remove("%s/part%d", disk->devfs_name, part); | 331 | devfs_remove("%s/part%d", disk->devfs_name, part); |
| 332 | if (p->holder_dir) | 332 | if (p->holder_dir) |
| 333 | kobject_unregister(p->holder_dir); | 333 | kobject_unregister(p->holder_dir); |
| 334 | kobject_unregister(&p->kobj); | 334 | kobject_uevent(&p->kobj, KOBJ_REMOVE); |
| 335 | kobject_del(&p->kobj); | ||
| 336 | kobject_put(&p->kobj); | ||
| 335 | } | 337 | } |
| 336 | 338 | ||
| 337 | void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len) | 339 | void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len) |
| @@ -357,7 +359,10 @@ void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len) | |||
| 357 | snprintf(p->kobj.name,KOBJ_NAME_LEN,"%s%d",disk->kobj.name,part); | 359 | snprintf(p->kobj.name,KOBJ_NAME_LEN,"%s%d",disk->kobj.name,part); |
| 358 | p->kobj.parent = &disk->kobj; | 360 | p->kobj.parent = &disk->kobj; |
| 359 | p->kobj.ktype = &ktype_part; | 361 | p->kobj.ktype = &ktype_part; |
| 360 | kobject_register(&p->kobj); | 362 | kobject_init(&p->kobj); |
| 363 | kobject_add(&p->kobj); | ||
| 364 | if (!disk->part_uevent_suppress) | ||
| 365 | kobject_uevent(&p->kobj, KOBJ_ADD); | ||
| 361 | partition_sysfs_add_subdir(p); | 366 | partition_sysfs_add_subdir(p); |
| 362 | disk->part[part-1] = p; | 367 | disk->part[part-1] = p; |
| 363 | } | 368 | } |
| @@ -367,6 +372,7 @@ static char *make_block_name(struct gendisk *disk) | |||
| 367 | char *name; | 372 | char *name; |
| 368 | static char *block_str = "block:"; | 373 | static char *block_str = "block:"; |
| 369 | int size; | 374 | int size; |
| 375 | char *s; | ||
| 370 | 376 | ||
| 371 | size = strlen(block_str) + strlen(disk->disk_name) + 1; | 377 | size = strlen(block_str) + strlen(disk->disk_name) + 1; |
| 372 | name = kmalloc(size, GFP_KERNEL); | 378 | name = kmalloc(size, GFP_KERNEL); |
| @@ -374,6 +380,10 @@ static char *make_block_name(struct gendisk *disk) | |||
| 374 | return NULL; | 380 | return NULL; |
| 375 | strcpy(name, block_str); | 381 | strcpy(name, block_str); |
| 376 | strcat(name, disk->disk_name); | 382 | strcat(name, disk->disk_name); |
| 383 | /* ewww... some of these buggers have / in name... */ | ||
| 384 | s = strchr(name, '/'); | ||
| 385 | if (s) | ||
| 386 | *s = '!'; | ||
| 377 | return name; | 387 | return name; |
| 378 | } | 388 | } |
| 379 | 389 | ||
| @@ -395,6 +405,8 @@ void register_disk(struct gendisk *disk) | |||
| 395 | { | 405 | { |
| 396 | struct block_device *bdev; | 406 | struct block_device *bdev; |
| 397 | char *s; | 407 | char *s; |
| 408 | int i; | ||
| 409 | struct hd_struct *p; | ||
| 398 | int err; | 410 | int err; |
| 399 | 411 | ||
| 400 | strlcpy(disk->kobj.name,disk->disk_name,KOBJ_NAME_LEN); | 412 | strlcpy(disk->kobj.name,disk->disk_name,KOBJ_NAME_LEN); |
| @@ -406,13 +418,12 @@ void register_disk(struct gendisk *disk) | |||
| 406 | return; | 418 | return; |
| 407 | disk_sysfs_symlinks(disk); | 419 | disk_sysfs_symlinks(disk); |
| 408 | disk_sysfs_add_subdirs(disk); | 420 | disk_sysfs_add_subdirs(disk); |
| 409 | kobject_uevent(&disk->kobj, KOBJ_ADD); | ||
| 410 | 421 | ||
| 411 | /* No minors to use for partitions */ | 422 | /* No minors to use for partitions */ |
| 412 | if (disk->minors == 1) { | 423 | if (disk->minors == 1) { |
| 413 | if (disk->devfs_name[0] != '\0') | 424 | if (disk->devfs_name[0] != '\0') |
| 414 | devfs_add_disk(disk); | 425 | devfs_add_disk(disk); |
| 415 | return; | 426 | goto exit; |
| 416 | } | 427 | } |
| 417 | 428 | ||
| 418 | /* always add handle for the whole disk */ | 429 | /* always add handle for the whole disk */ |
| @@ -420,16 +431,32 @@ void register_disk(struct gendisk *disk) | |||
| 420 | 431 | ||
| 421 | /* No such device (e.g., media were just removed) */ | 432 | /* No such device (e.g., media were just removed) */ |
| 422 | if (!get_capacity(disk)) | 433 | if (!get_capacity(disk)) |
| 423 | return; | 434 | goto exit; |
| 424 | 435 | ||
| 425 | bdev = bdget_disk(disk, 0); | 436 | bdev = bdget_disk(disk, 0); |
| 426 | if (!bdev) | 437 | if (!bdev) |
| 427 | return; | 438 | goto exit; |
| 428 | 439 | ||
| 440 | /* scan partition table, but suppress uevents */ | ||
| 429 | bdev->bd_invalidated = 1; | 441 | bdev->bd_invalidated = 1; |
| 430 | if (blkdev_get(bdev, FMODE_READ, 0) < 0) | 442 | disk->part_uevent_suppress = 1; |
| 431 | return; | 443 | err = blkdev_get(bdev, FMODE_READ, 0); |
| 444 | disk->part_uevent_suppress = 0; | ||
| 445 | if (err < 0) | ||
| 446 | goto exit; | ||
| 432 | blkdev_put(bdev); | 447 | blkdev_put(bdev); |
| 448 | |||
| 449 | exit: | ||
| 450 | /* announce disk after possible partitions are already created */ | ||
| 451 | kobject_uevent(&disk->kobj, KOBJ_ADD); | ||
| 452 | |||
| 453 | /* announce possible partitions */ | ||
| 454 | for (i = 1; i < disk->minors; i++) { | ||
| 455 | p = disk->part[i-1]; | ||
| 456 | if (!p || !p->nr_sects) | ||
| 457 | continue; | ||
| 458 | kobject_uevent(&p->kobj, KOBJ_ADD); | ||
| 459 | } | ||
| 433 | } | 460 | } |
| 434 | 461 | ||
| 435 | int rescan_partitions(struct gendisk *disk, struct block_device *bdev) | 462 | int rescan_partitions(struct gendisk *disk, struct block_device *bdev) |
| @@ -131,12 +131,19 @@ static int anon_pipe_buf_steal(struct pipe_inode_info *pipe, | |||
| 131 | return 0; | 131 | return 0; |
| 132 | } | 132 | } |
| 133 | 133 | ||
| 134 | static void anon_pipe_buf_get(struct pipe_inode_info *info, | ||
| 135 | struct pipe_buffer *buf) | ||
| 136 | { | ||
| 137 | page_cache_get(buf->page); | ||
| 138 | } | ||
| 139 | |||
| 134 | static struct pipe_buf_operations anon_pipe_buf_ops = { | 140 | static struct pipe_buf_operations anon_pipe_buf_ops = { |
| 135 | .can_merge = 1, | 141 | .can_merge = 1, |
| 136 | .map = anon_pipe_buf_map, | 142 | .map = anon_pipe_buf_map, |
| 137 | .unmap = anon_pipe_buf_unmap, | 143 | .unmap = anon_pipe_buf_unmap, |
| 138 | .release = anon_pipe_buf_release, | 144 | .release = anon_pipe_buf_release, |
| 139 | .steal = anon_pipe_buf_steal, | 145 | .steal = anon_pipe_buf_steal, |
| 146 | .get = anon_pipe_buf_get, | ||
| 140 | }; | 147 | }; |
| 141 | 148 | ||
| 142 | static ssize_t | 149 | static ssize_t |
diff --git a/fs/splice.c b/fs/splice.c index e50a460239dd..8d57e89924a6 100644 --- a/fs/splice.c +++ b/fs/splice.c | |||
| @@ -125,12 +125,19 @@ static void page_cache_pipe_buf_unmap(struct pipe_inode_info *info, | |||
| 125 | kunmap(buf->page); | 125 | kunmap(buf->page); |
| 126 | } | 126 | } |
| 127 | 127 | ||
| 128 | static void page_cache_pipe_buf_get(struct pipe_inode_info *info, | ||
| 129 | struct pipe_buffer *buf) | ||
| 130 | { | ||
| 131 | page_cache_get(buf->page); | ||
| 132 | } | ||
| 133 | |||
| 128 | static struct pipe_buf_operations page_cache_pipe_buf_ops = { | 134 | static struct pipe_buf_operations page_cache_pipe_buf_ops = { |
| 129 | .can_merge = 0, | 135 | .can_merge = 0, |
| 130 | .map = page_cache_pipe_buf_map, | 136 | .map = page_cache_pipe_buf_map, |
| 131 | .unmap = page_cache_pipe_buf_unmap, | 137 | .unmap = page_cache_pipe_buf_unmap, |
| 132 | .release = page_cache_pipe_buf_release, | 138 | .release = page_cache_pipe_buf_release, |
| 133 | .steal = page_cache_pipe_buf_steal, | 139 | .steal = page_cache_pipe_buf_steal, |
| 140 | .get = page_cache_pipe_buf_get, | ||
| 134 | }; | 141 | }; |
| 135 | 142 | ||
| 136 | /* | 143 | /* |
| @@ -231,8 +238,9 @@ static ssize_t move_to_pipe(struct pipe_inode_info *pipe, struct page **pages, | |||
| 231 | } | 238 | } |
| 232 | 239 | ||
| 233 | static int | 240 | static int |
| 234 | __generic_file_splice_read(struct file *in, struct pipe_inode_info *pipe, | 241 | __generic_file_splice_read(struct file *in, loff_t *ppos, |
| 235 | size_t len, unsigned int flags) | 242 | struct pipe_inode_info *pipe, size_t len, |
| 243 | unsigned int flags) | ||
| 236 | { | 244 | { |
| 237 | struct address_space *mapping = in->f_mapping; | 245 | struct address_space *mapping = in->f_mapping; |
| 238 | unsigned int offset, nr_pages; | 246 | unsigned int offset, nr_pages; |
| @@ -241,8 +249,8 @@ __generic_file_splice_read(struct file *in, struct pipe_inode_info *pipe, | |||
| 241 | pgoff_t index; | 249 | pgoff_t index; |
| 242 | int i, error; | 250 | int i, error; |
| 243 | 251 | ||
| 244 | index = in->f_pos >> PAGE_CACHE_SHIFT; | 252 | index = *ppos >> PAGE_CACHE_SHIFT; |
| 245 | offset = in->f_pos & ~PAGE_CACHE_MASK; | 253 | offset = *ppos & ~PAGE_CACHE_MASK; |
| 246 | nr_pages = (len + offset + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; | 254 | nr_pages = (len + offset + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; |
| 247 | 255 | ||
| 248 | if (nr_pages > PIPE_BUFFERS) | 256 | if (nr_pages > PIPE_BUFFERS) |
| @@ -348,8 +356,9 @@ fill_it: | |||
| 348 | * | 356 | * |
| 349 | * Will read pages from given file and fill them into a pipe. | 357 | * Will read pages from given file and fill them into a pipe. |
| 350 | */ | 358 | */ |
| 351 | ssize_t generic_file_splice_read(struct file *in, struct pipe_inode_info *pipe, | 359 | ssize_t generic_file_splice_read(struct file *in, loff_t *ppos, |
| 352 | size_t len, unsigned int flags) | 360 | struct pipe_inode_info *pipe, size_t len, |
| 361 | unsigned int flags) | ||
| 353 | { | 362 | { |
| 354 | ssize_t spliced; | 363 | ssize_t spliced; |
| 355 | int ret; | 364 | int ret; |
| @@ -358,12 +367,12 @@ ssize_t generic_file_splice_read(struct file *in, struct pipe_inode_info *pipe, | |||
| 358 | spliced = 0; | 367 | spliced = 0; |
| 359 | 368 | ||
| 360 | while (len) { | 369 | while (len) { |
| 361 | ret = __generic_file_splice_read(in, pipe, len, flags); | 370 | ret = __generic_file_splice_read(in, ppos, pipe, len, flags); |
| 362 | 371 | ||
| 363 | if (ret <= 0) | 372 | if (ret <= 0) |
| 364 | break; | 373 | break; |
| 365 | 374 | ||
| 366 | in->f_pos += ret; | 375 | *ppos += ret; |
| 367 | len -= ret; | 376 | len -= ret; |
| 368 | spliced += ret; | 377 | spliced += ret; |
| 369 | 378 | ||
| @@ -561,7 +570,7 @@ typedef int (splice_actor)(struct pipe_inode_info *, struct pipe_buffer *, | |||
| 561 | * to the wanted destination. See pipe_to_file/pipe_to_sendpage above. | 570 | * to the wanted destination. See pipe_to_file/pipe_to_sendpage above. |
| 562 | */ | 571 | */ |
| 563 | static ssize_t move_from_pipe(struct pipe_inode_info *pipe, struct file *out, | 572 | static ssize_t move_from_pipe(struct pipe_inode_info *pipe, struct file *out, |
| 564 | size_t len, unsigned int flags, | 573 | loff_t *ppos, size_t len, unsigned int flags, |
| 565 | splice_actor *actor) | 574 | splice_actor *actor) |
| 566 | { | 575 | { |
| 567 | int ret, do_wakeup, err; | 576 | int ret, do_wakeup, err; |
| @@ -573,7 +582,7 @@ static ssize_t move_from_pipe(struct pipe_inode_info *pipe, struct file *out, | |||
| 573 | sd.total_len = len; | 582 | sd.total_len = len; |
| 574 | sd.flags = flags; | 583 | sd.flags = flags; |
| 575 | sd.file = out; | 584 | sd.file = out; |
| 576 | sd.pos = out->f_pos; | 585 | sd.pos = *ppos; |
| 577 | 586 | ||
| 578 | if (pipe->inode) | 587 | if (pipe->inode) |
| 579 | mutex_lock(&pipe->inode->i_mutex); | 588 | mutex_lock(&pipe->inode->i_mutex); |
| @@ -656,9 +665,7 @@ static ssize_t move_from_pipe(struct pipe_inode_info *pipe, struct file *out, | |||
| 656 | kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT); | 665 | kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT); |
| 657 | } | 666 | } |
| 658 | 667 | ||
| 659 | out->f_pos = sd.pos; | ||
| 660 | return ret; | 668 | return ret; |
| 661 | |||
| 662 | } | 669 | } |
| 663 | 670 | ||
| 664 | /** | 671 | /** |
| @@ -674,12 +681,12 @@ static ssize_t move_from_pipe(struct pipe_inode_info *pipe, struct file *out, | |||
| 674 | */ | 681 | */ |
| 675 | ssize_t | 682 | ssize_t |
| 676 | generic_file_splice_write(struct pipe_inode_info *pipe, struct file *out, | 683 | generic_file_splice_write(struct pipe_inode_info *pipe, struct file *out, |
| 677 | size_t len, unsigned int flags) | 684 | loff_t *ppos, size_t len, unsigned int flags) |
| 678 | { | 685 | { |
| 679 | struct address_space *mapping = out->f_mapping; | 686 | struct address_space *mapping = out->f_mapping; |
| 680 | ssize_t ret; | 687 | ssize_t ret; |
| 681 | 688 | ||
| 682 | ret = move_from_pipe(pipe, out, len, flags, pipe_to_file); | 689 | ret = move_from_pipe(pipe, out, ppos, len, flags, pipe_to_file); |
| 683 | 690 | ||
| 684 | /* | 691 | /* |
| 685 | * If file or inode is SYNC and we actually wrote some data, sync it. | 692 | * If file or inode is SYNC and we actually wrote some data, sync it. |
| @@ -715,9 +722,9 @@ EXPORT_SYMBOL(generic_file_splice_write); | |||
| 715 | * | 722 | * |
| 716 | */ | 723 | */ |
| 717 | ssize_t generic_splice_sendpage(struct pipe_inode_info *pipe, struct file *out, | 724 | ssize_t generic_splice_sendpage(struct pipe_inode_info *pipe, struct file *out, |
| 718 | size_t len, unsigned int flags) | 725 | loff_t *ppos, size_t len, unsigned int flags) |
| 719 | { | 726 | { |
| 720 | return move_from_pipe(pipe, out, len, flags, pipe_to_sendpage); | 727 | return move_from_pipe(pipe, out, ppos, len, flags, pipe_to_sendpage); |
| 721 | } | 728 | } |
| 722 | 729 | ||
| 723 | EXPORT_SYMBOL(generic_splice_sendpage); | 730 | EXPORT_SYMBOL(generic_splice_sendpage); |
| @@ -726,9 +733,8 @@ EXPORT_SYMBOL(generic_splice_sendpage); | |||
| 726 | * Attempt to initiate a splice from pipe to file. | 733 | * Attempt to initiate a splice from pipe to file. |
| 727 | */ | 734 | */ |
| 728 | static long do_splice_from(struct pipe_inode_info *pipe, struct file *out, | 735 | static long do_splice_from(struct pipe_inode_info *pipe, struct file *out, |
| 729 | size_t len, unsigned int flags) | 736 | loff_t *ppos, size_t len, unsigned int flags) |
| 730 | { | 737 | { |
| 731 | loff_t pos; | ||
| 732 | int ret; | 738 | int ret; |
| 733 | 739 | ||
| 734 | if (unlikely(!out->f_op || !out->f_op->splice_write)) | 740 | if (unlikely(!out->f_op || !out->f_op->splice_write)) |
| @@ -737,22 +743,21 @@ static long do_splice_from(struct pipe_inode_info *pipe, struct file *out, | |||
| 737 | if (unlikely(!(out->f_mode & FMODE_WRITE))) | 743 | if (unlikely(!(out->f_mode & FMODE_WRITE))) |
| 738 | return -EBADF; | 744 | return -EBADF; |
| 739 | 745 | ||
| 740 | pos = out->f_pos; | 746 | ret = rw_verify_area(WRITE, out, ppos, len); |
| 741 | |||
| 742 | ret = rw_verify_area(WRITE, out, &pos, len); | ||
| 743 | if (unlikely(ret < 0)) | 747 | if (unlikely(ret < 0)) |
| 744 | return ret; | 748 | return ret; |
| 745 | 749 | ||
| 746 | return out->f_op->splice_write(pipe, out, len, flags); | 750 | return out->f_op->splice_write(pipe, out, ppos, len, flags); |
| 747 | } | 751 | } |
| 748 | 752 | ||
| 749 | /* | 753 | /* |
| 750 | * Attempt to initiate a splice from a file to a pipe. | 754 | * Attempt to initiate a splice from a file to a pipe. |
| 751 | */ | 755 | */ |
| 752 | static long do_splice_to(struct file *in, struct pipe_inode_info *pipe, | 756 | static long do_splice_to(struct file *in, loff_t *ppos, |
| 753 | size_t len, unsigned int flags) | 757 | struct pipe_inode_info *pipe, size_t len, |
| 758 | unsigned int flags) | ||
| 754 | { | 759 | { |
| 755 | loff_t pos, isize, left; | 760 | loff_t isize, left; |
| 756 | int ret; | 761 | int ret; |
| 757 | 762 | ||
| 758 | if (unlikely(!in->f_op || !in->f_op->splice_read)) | 763 | if (unlikely(!in->f_op || !in->f_op->splice_read)) |
| @@ -761,28 +766,27 @@ static long do_splice_to(struct file *in, struct pipe_inode_info *pipe, | |||
| 761 | if (unlikely(!(in->f_mode & FMODE_READ))) | 766 | if (unlikely(!(in->f_mode & FMODE_READ))) |
| 762 | return -EBADF; | 767 | return -EBADF; |
| 763 | 768 | ||
| 764 | pos = in->f_pos; | 769 | ret = rw_verify_area(READ, in, ppos, len); |
| 765 | |||
| 766 | ret = rw_verify_area(READ, in, &pos, len); | ||
| 767 | if (unlikely(ret < 0)) | 770 | if (unlikely(ret < 0)) |
| 768 | return ret; | 771 | return ret; |
| 769 | 772 | ||
| 770 | isize = i_size_read(in->f_mapping->host); | 773 | isize = i_size_read(in->f_mapping->host); |
| 771 | if (unlikely(in->f_pos >= isize)) | 774 | if (unlikely(*ppos >= isize)) |
| 772 | return 0; | 775 | return 0; |
| 773 | 776 | ||
| 774 | left = isize - in->f_pos; | 777 | left = isize - *ppos; |
| 775 | if (unlikely(left < len)) | 778 | if (unlikely(left < len)) |
| 776 | len = left; | 779 | len = left; |
| 777 | 780 | ||
| 778 | return in->f_op->splice_read(in, pipe, len, flags); | 781 | return in->f_op->splice_read(in, ppos, pipe, len, flags); |
| 779 | } | 782 | } |
| 780 | 783 | ||
| 781 | long do_splice_direct(struct file *in, struct file *out, size_t len, | 784 | long do_splice_direct(struct file *in, loff_t *ppos, struct file *out, |
| 782 | unsigned int flags) | 785 | size_t len, unsigned int flags) |
| 783 | { | 786 | { |
| 784 | struct pipe_inode_info *pipe; | 787 | struct pipe_inode_info *pipe; |
| 785 | long ret, bytes; | 788 | long ret, bytes; |
| 789 | loff_t out_off; | ||
| 786 | umode_t i_mode; | 790 | umode_t i_mode; |
| 787 | int i; | 791 | int i; |
| 788 | 792 | ||
| @@ -820,6 +824,7 @@ long do_splice_direct(struct file *in, struct file *out, size_t len, | |||
| 820 | */ | 824 | */ |
| 821 | ret = 0; | 825 | ret = 0; |
| 822 | bytes = 0; | 826 | bytes = 0; |
| 827 | out_off = 0; | ||
| 823 | 828 | ||
| 824 | while (len) { | 829 | while (len) { |
| 825 | size_t read_len, max_read_len; | 830 | size_t read_len, max_read_len; |
| @@ -829,7 +834,7 @@ long do_splice_direct(struct file *in, struct file *out, size_t len, | |||
| 829 | */ | 834 | */ |
| 830 | max_read_len = min(len, (size_t)(PIPE_BUFFERS*PAGE_SIZE)); | 835 | max_read_len = min(len, (size_t)(PIPE_BUFFERS*PAGE_SIZE)); |
| 831 | 836 | ||
| 832 | ret = do_splice_to(in, pipe, max_read_len, flags); | 837 | ret = do_splice_to(in, ppos, pipe, max_read_len, flags); |
| 833 | if (unlikely(ret < 0)) | 838 | if (unlikely(ret < 0)) |
| 834 | goto out_release; | 839 | goto out_release; |
| 835 | 840 | ||
| @@ -840,7 +845,7 @@ long do_splice_direct(struct file *in, struct file *out, size_t len, | |||
| 840 | * must not do the output in nonblocking mode as then we | 845 | * must not do the output in nonblocking mode as then we |
| 841 | * could get stuck data in the internal pipe: | 846 | * could get stuck data in the internal pipe: |
| 842 | */ | 847 | */ |
| 843 | ret = do_splice_from(pipe, out, read_len, | 848 | ret = do_splice_from(pipe, out, &out_off, read_len, |
| 844 | flags & ~SPLICE_F_NONBLOCK); | 849 | flags & ~SPLICE_F_NONBLOCK); |
| 845 | if (unlikely(ret < 0)) | 850 | if (unlikely(ret < 0)) |
| 846 | goto out_release; | 851 | goto out_release; |
| @@ -898,6 +903,7 @@ static long do_splice(struct file *in, loff_t __user *off_in, | |||
| 898 | size_t len, unsigned int flags) | 903 | size_t len, unsigned int flags) |
| 899 | { | 904 | { |
| 900 | struct pipe_inode_info *pipe; | 905 | struct pipe_inode_info *pipe; |
| 906 | loff_t offset, *off; | ||
| 901 | 907 | ||
| 902 | pipe = in->f_dentry->d_inode->i_pipe; | 908 | pipe = in->f_dentry->d_inode->i_pipe; |
| 903 | if (pipe) { | 909 | if (pipe) { |
| @@ -906,12 +912,13 @@ static long do_splice(struct file *in, loff_t __user *off_in, | |||
| 906 | if (off_out) { | 912 | if (off_out) { |
| 907 | if (out->f_op->llseek == no_llseek) | 913 | if (out->f_op->llseek == no_llseek) |
| 908 | return -EINVAL; | 914 | return -EINVAL; |
| 909 | if (copy_from_user(&out->f_pos, off_out, | 915 | if (copy_from_user(&offset, off_out, sizeof(loff_t))) |
| 910 | sizeof(loff_t))) | ||
| 911 | return -EFAULT; | 916 | return -EFAULT; |
| 912 | } | 917 | off = &offset; |
| 918 | } else | ||
| 919 | off = &out->f_pos; | ||
| 913 | 920 | ||
| 914 | return do_splice_from(pipe, out, len, flags); | 921 | return do_splice_from(pipe, out, off, len, flags); |
| 915 | } | 922 | } |
| 916 | 923 | ||
| 917 | pipe = out->f_dentry->d_inode->i_pipe; | 924 | pipe = out->f_dentry->d_inode->i_pipe; |
| @@ -921,11 +928,13 @@ static long do_splice(struct file *in, loff_t __user *off_in, | |||
| 921 | if (off_in) { | 928 | if (off_in) { |
| 922 | if (in->f_op->llseek == no_llseek) | 929 | if (in->f_op->llseek == no_llseek) |
| 923 | return -EINVAL; | 930 | return -EINVAL; |
| 924 | if (copy_from_user(&in->f_pos, off_in, sizeof(loff_t))) | 931 | if (copy_from_user(&offset, off_in, sizeof(loff_t))) |
| 925 | return -EFAULT; | 932 | return -EFAULT; |
| 926 | } | 933 | off = &offset; |
| 934 | } else | ||
| 935 | off = &in->f_pos; | ||
| 927 | 936 | ||
| 928 | return do_splice_to(in, pipe, len, flags); | 937 | return do_splice_to(in, off, pipe, len, flags); |
| 929 | } | 938 | } |
| 930 | 939 | ||
| 931 | return -EINVAL; | 940 | return -EINVAL; |
| @@ -961,3 +970,182 @@ asmlinkage long sys_splice(int fd_in, loff_t __user *off_in, | |||
| 961 | 970 | ||
| 962 | return error; | 971 | return error; |
| 963 | } | 972 | } |
| 973 | |||
| 974 | /* | ||
| 975 | * Link contents of ipipe to opipe. | ||
| 976 | */ | ||
| 977 | static int link_pipe(struct pipe_inode_info *ipipe, | ||
| 978 | struct pipe_inode_info *opipe, | ||
| 979 | size_t len, unsigned int flags) | ||
| 980 | { | ||
| 981 | struct pipe_buffer *ibuf, *obuf; | ||
| 982 | int ret = 0, do_wakeup = 0, i; | ||
| 983 | |||
| 984 | /* | ||
| 985 | * Potential ABBA deadlock, work around it by ordering lock | ||
| 986 | * grabbing by inode address. Otherwise two different processes | ||
| 987 | * could deadlock (one doing tee from A -> B, the other from B -> A). | ||
| 988 | */ | ||
| 989 | if (ipipe->inode < opipe->inode) { | ||
| 990 | mutex_lock(&ipipe->inode->i_mutex); | ||
| 991 | mutex_lock(&opipe->inode->i_mutex); | ||
| 992 | } else { | ||
| 993 | mutex_lock(&opipe->inode->i_mutex); | ||
| 994 | mutex_lock(&ipipe->inode->i_mutex); | ||
| 995 | } | ||
| 996 | |||
| 997 | for (i = 0;; i++) { | ||
| 998 | if (!opipe->readers) { | ||
| 999 | send_sig(SIGPIPE, current, 0); | ||
| 1000 | if (!ret) | ||
| 1001 | ret = -EPIPE; | ||
| 1002 | break; | ||
| 1003 | } | ||
| 1004 | if (ipipe->nrbufs - i) { | ||
| 1005 | ibuf = ipipe->bufs + ((ipipe->curbuf + i) & (PIPE_BUFFERS - 1)); | ||
| 1006 | |||
| 1007 | /* | ||
| 1008 | * If we have room, fill this buffer | ||
| 1009 | */ | ||
| 1010 | if (opipe->nrbufs < PIPE_BUFFERS) { | ||
| 1011 | int nbuf = (opipe->curbuf + opipe->nrbufs) & (PIPE_BUFFERS - 1); | ||
| 1012 | |||
| 1013 | /* | ||
| 1014 | * Get a reference to this pipe buffer, | ||
| 1015 | * so we can copy the contents over. | ||
| 1016 | */ | ||
| 1017 | ibuf->ops->get(ipipe, ibuf); | ||
| 1018 | |||
| 1019 | obuf = opipe->bufs + nbuf; | ||
| 1020 | *obuf = *ibuf; | ||
| 1021 | |||
| 1022 | if (obuf->len > len) | ||
| 1023 | obuf->len = len; | ||
| 1024 | |||
| 1025 | opipe->nrbufs++; | ||
| 1026 | do_wakeup = 1; | ||
| 1027 | ret += obuf->len; | ||
| 1028 | len -= obuf->len; | ||
| 1029 | |||
| 1030 | if (!len) | ||
| 1031 | break; | ||
| 1032 | if (opipe->nrbufs < PIPE_BUFFERS) | ||
| 1033 | continue; | ||
| 1034 | } | ||
| 1035 | |||
| 1036 | /* | ||
| 1037 | * We have input available, but no output room. | ||
| 1038 | * If we already copied data, return that. | ||
| 1039 | */ | ||
| 1040 | if (flags & SPLICE_F_NONBLOCK) { | ||
| 1041 | if (!ret) | ||
| 1042 | ret = -EAGAIN; | ||
| 1043 | break; | ||
| 1044 | } | ||
| 1045 | if (signal_pending(current)) { | ||
| 1046 | if (!ret) | ||
| 1047 | ret = -ERESTARTSYS; | ||
| 1048 | break; | ||
| 1049 | } | ||
| 1050 | if (do_wakeup) { | ||
| 1051 | smp_mb(); | ||
| 1052 | if (waitqueue_active(&opipe->wait)) | ||
| 1053 | wake_up_interruptible(&opipe->wait); | ||
| 1054 | kill_fasync(&opipe->fasync_readers, SIGIO, POLL_IN); | ||
| 1055 | do_wakeup = 0; | ||
| 1056 | } | ||
| 1057 | |||
| 1058 | opipe->waiting_writers++; | ||
| 1059 | pipe_wait(opipe); | ||
| 1060 | opipe->waiting_writers--; | ||
| 1061 | continue; | ||
| 1062 | } | ||
| 1063 | |||
| 1064 | /* | ||
| 1065 | * No input buffers, do the usual checks for available | ||
| 1066 | * writers and blocking and wait if necessary | ||
| 1067 | */ | ||
| 1068 | if (!ipipe->writers) | ||
| 1069 | break; | ||
| 1070 | if (!ipipe->waiting_writers) { | ||
| 1071 | if (ret) | ||
| 1072 | break; | ||
| 1073 | } | ||
| 1074 | if (flags & SPLICE_F_NONBLOCK) { | ||
| 1075 | if (!ret) | ||
| 1076 | ret = -EAGAIN; | ||
| 1077 | break; | ||
| 1078 | } | ||
| 1079 | if (signal_pending(current)) { | ||
| 1080 | if (!ret) | ||
| 1081 | ret = -ERESTARTSYS; | ||
| 1082 | break; | ||
| 1083 | } | ||
| 1084 | |||
| 1085 | if (waitqueue_active(&ipipe->wait)) | ||
| 1086 | wake_up_interruptible_sync(&ipipe->wait); | ||
| 1087 | kill_fasync(&ipipe->fasync_writers, SIGIO, POLL_OUT); | ||
| 1088 | |||
| 1089 | pipe_wait(ipipe); | ||
| 1090 | } | ||
| 1091 | |||
| 1092 | mutex_unlock(&ipipe->inode->i_mutex); | ||
| 1093 | mutex_unlock(&opipe->inode->i_mutex); | ||
| 1094 | |||
| 1095 | if (do_wakeup) { | ||
| 1096 | smp_mb(); | ||
| 1097 | if (waitqueue_active(&opipe->wait)) | ||
| 1098 | wake_up_interruptible(&opipe->wait); | ||
| 1099 | kill_fasync(&opipe->fasync_readers, SIGIO, POLL_IN); | ||
| 1100 | } | ||
| 1101 | |||
| 1102 | return ret; | ||
| 1103 | } | ||
| 1104 | |||
| 1105 | /* | ||
| 1106 | * This is a tee(1) implementation that works on pipes. It doesn't copy | ||
| 1107 | * any data, it simply references the 'in' pages on the 'out' pipe. | ||
| 1108 | * The 'flags' used are the SPLICE_F_* variants, currently the only | ||
| 1109 | * applicable one is SPLICE_F_NONBLOCK. | ||
| 1110 | */ | ||
| 1111 | static long do_tee(struct file *in, struct file *out, size_t len, | ||
| 1112 | unsigned int flags) | ||
| 1113 | { | ||
| 1114 | struct pipe_inode_info *ipipe = in->f_dentry->d_inode->i_pipe; | ||
| 1115 | struct pipe_inode_info *opipe = out->f_dentry->d_inode->i_pipe; | ||
| 1116 | |||
| 1117 | /* | ||
| 1118 | * Link ipipe to the two output pipes, consuming as we go along. | ||
| 1119 | */ | ||
| 1120 | if (ipipe && opipe) | ||
| 1121 | return link_pipe(ipipe, opipe, len, flags); | ||
| 1122 | |||
| 1123 | return -EINVAL; | ||
| 1124 | } | ||
| 1125 | |||
| 1126 | asmlinkage long sys_tee(int fdin, int fdout, size_t len, unsigned int flags) | ||
| 1127 | { | ||
| 1128 | struct file *in; | ||
| 1129 | int error, fput_in; | ||
| 1130 | |||
| 1131 | if (unlikely(!len)) | ||
| 1132 | return 0; | ||
| 1133 | |||
| 1134 | error = -EBADF; | ||
| 1135 | in = fget_light(fdin, &fput_in); | ||
| 1136 | if (in) { | ||
| 1137 | if (in->f_mode & FMODE_READ) { | ||
| 1138 | int fput_out; | ||
| 1139 | struct file *out = fget_light(fdout, &fput_out); | ||
| 1140 | |||
| 1141 | if (out) { | ||
| 1142 | if (out->f_mode & FMODE_WRITE) | ||
| 1143 | error = do_tee(in, out, len, flags); | ||
| 1144 | fput_light(out, fput_out); | ||
| 1145 | } | ||
| 1146 | } | ||
| 1147 | fput_light(in, fput_in); | ||
| 1148 | } | ||
| 1149 | |||
| 1150 | return error; | ||
| 1151 | } | ||
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 6cfdc9a87772..610b5bdbe75b 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c | |||
| @@ -43,6 +43,7 @@ static struct sysfs_dirent * sysfs_new_dirent(struct sysfs_dirent * parent_sd, | |||
| 43 | 43 | ||
| 44 | memset(sd, 0, sizeof(*sd)); | 44 | memset(sd, 0, sizeof(*sd)); |
| 45 | atomic_set(&sd->s_count, 1); | 45 | atomic_set(&sd->s_count, 1); |
| 46 | atomic_set(&sd->s_event, 0); | ||
| 46 | INIT_LIST_HEAD(&sd->s_children); | 47 | INIT_LIST_HEAD(&sd->s_children); |
| 47 | list_add(&sd->s_sibling, &parent_sd->s_children); | 48 | list_add(&sd->s_sibling, &parent_sd->s_children); |
| 48 | sd->s_element = element; | 49 | sd->s_element = element; |
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index f1cb1ddde511..cf3786625bfa 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | #include <linux/fsnotify.h> | 6 | #include <linux/fsnotify.h> |
| 7 | #include <linux/kobject.h> | 7 | #include <linux/kobject.h> |
| 8 | #include <linux/namei.h> | 8 | #include <linux/namei.h> |
| 9 | #include <linux/poll.h> | ||
| 9 | #include <asm/uaccess.h> | 10 | #include <asm/uaccess.h> |
| 10 | #include <asm/semaphore.h> | 11 | #include <asm/semaphore.h> |
| 11 | 12 | ||
| @@ -57,6 +58,7 @@ struct sysfs_buffer { | |||
| 57 | struct sysfs_ops * ops; | 58 | struct sysfs_ops * ops; |
| 58 | struct semaphore sem; | 59 | struct semaphore sem; |
| 59 | int needs_read_fill; | 60 | int needs_read_fill; |
| 61 | int event; | ||
| 60 | }; | 62 | }; |
| 61 | 63 | ||
| 62 | 64 | ||
| @@ -72,6 +74,7 @@ struct sysfs_buffer { | |||
| 72 | */ | 74 | */ |
| 73 | static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer) | 75 | static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer) |
| 74 | { | 76 | { |
| 77 | struct sysfs_dirent * sd = dentry->d_fsdata; | ||
| 75 | struct attribute * attr = to_attr(dentry); | 78 | struct attribute * attr = to_attr(dentry); |
| 76 | struct kobject * kobj = to_kobj(dentry->d_parent); | 79 | struct kobject * kobj = to_kobj(dentry->d_parent); |
| 77 | struct sysfs_ops * ops = buffer->ops; | 80 | struct sysfs_ops * ops = buffer->ops; |
| @@ -83,6 +86,7 @@ static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer | |||
| 83 | if (!buffer->page) | 86 | if (!buffer->page) |
| 84 | return -ENOMEM; | 87 | return -ENOMEM; |
| 85 | 88 | ||
| 89 | buffer->event = atomic_read(&sd->s_event); | ||
| 86 | count = ops->show(kobj,attr,buffer->page); | 90 | count = ops->show(kobj,attr,buffer->page); |
| 87 | buffer->needs_read_fill = 0; | 91 | buffer->needs_read_fill = 0; |
| 88 | BUG_ON(count > (ssize_t)PAGE_SIZE); | 92 | BUG_ON(count > (ssize_t)PAGE_SIZE); |
| @@ -348,12 +352,84 @@ static int sysfs_release(struct inode * inode, struct file * filp) | |||
| 348 | return 0; | 352 | return 0; |
| 349 | } | 353 | } |
| 350 | 354 | ||
| 355 | /* Sysfs attribute files are pollable. The idea is that you read | ||
| 356 | * the content and then you use 'poll' or 'select' to wait for | ||
| 357 | * the content to change. When the content changes (assuming the | ||
| 358 | * manager for the kobject supports notification), poll will | ||
| 359 | * return POLLERR|POLLPRI, and select will return the fd whether | ||
| 360 | * it is waiting for read, write, or exceptions. | ||
| 361 | * Once poll/select indicates that the value has changed, you | ||
| 362 | * need to close and re-open the file, as simply seeking and reading | ||
| 363 | * again will not get new data, or reset the state of 'poll'. | ||
| 364 | * Reminder: this only works for attributes which actively support | ||
| 365 | * it, and it is not possible to test an attribute from userspace | ||
| 366 | * to see if it supports poll (Nether 'poll' or 'select' return | ||
| 367 | * an appropriate error code). When in doubt, set a suitable timeout value. | ||
| 368 | */ | ||
| 369 | static unsigned int sysfs_poll(struct file *filp, poll_table *wait) | ||
| 370 | { | ||
| 371 | struct sysfs_buffer * buffer = filp->private_data; | ||
| 372 | struct kobject * kobj = to_kobj(filp->f_dentry->d_parent); | ||
| 373 | struct sysfs_dirent * sd = filp->f_dentry->d_fsdata; | ||
| 374 | int res = 0; | ||
| 375 | |||
| 376 | poll_wait(filp, &kobj->poll, wait); | ||
| 377 | |||
| 378 | if (buffer->event != atomic_read(&sd->s_event)) { | ||
| 379 | res = POLLERR|POLLPRI; | ||
| 380 | buffer->needs_read_fill = 1; | ||
| 381 | } | ||
| 382 | |||
| 383 | return res; | ||
| 384 | } | ||
| 385 | |||
| 386 | |||
| 387 | static struct dentry *step_down(struct dentry *dir, const char * name) | ||
| 388 | { | ||
| 389 | struct dentry * de; | ||
| 390 | |||
| 391 | if (dir == NULL || dir->d_inode == NULL) | ||
| 392 | return NULL; | ||
| 393 | |||
| 394 | mutex_lock(&dir->d_inode->i_mutex); | ||
| 395 | de = lookup_one_len(name, dir, strlen(name)); | ||
| 396 | mutex_unlock(&dir->d_inode->i_mutex); | ||
| 397 | dput(dir); | ||
| 398 | if (IS_ERR(de)) | ||
| 399 | return NULL; | ||
| 400 | if (de->d_inode == NULL) { | ||
| 401 | dput(de); | ||
| 402 | return NULL; | ||
| 403 | } | ||
| 404 | return de; | ||
| 405 | } | ||
| 406 | |||
| 407 | void sysfs_notify(struct kobject * k, char *dir, char *attr) | ||
| 408 | { | ||
| 409 | struct dentry *de = k->dentry; | ||
| 410 | if (de) | ||
| 411 | dget(de); | ||
| 412 | if (de && dir) | ||
| 413 | de = step_down(de, dir); | ||
| 414 | if (de && attr) | ||
| 415 | de = step_down(de, attr); | ||
| 416 | if (de) { | ||
| 417 | struct sysfs_dirent * sd = de->d_fsdata; | ||
| 418 | if (sd) | ||
| 419 | atomic_inc(&sd->s_event); | ||
| 420 | wake_up_interruptible(&k->poll); | ||
| 421 | dput(de); | ||
| 422 | } | ||
| 423 | } | ||
| 424 | EXPORT_SYMBOL_GPL(sysfs_notify); | ||
| 425 | |||
| 351 | const struct file_operations sysfs_file_operations = { | 426 | const struct file_operations sysfs_file_operations = { |
| 352 | .read = sysfs_read_file, | 427 | .read = sysfs_read_file, |
| 353 | .write = sysfs_write_file, | 428 | .write = sysfs_write_file, |
| 354 | .llseek = generic_file_llseek, | 429 | .llseek = generic_file_llseek, |
| 355 | .open = sysfs_open_file, | 430 | .open = sysfs_open_file, |
| 356 | .release = sysfs_release, | 431 | .release = sysfs_release, |
| 432 | .poll = sysfs_poll, | ||
| 357 | }; | 433 | }; |
| 358 | 434 | ||
| 359 | 435 | ||
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 32958a7c50e9..3651ffb5ec09 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h | |||
| @@ -11,6 +11,7 @@ extern int sysfs_make_dirent(struct sysfs_dirent *, struct dentry *, void *, | |||
| 11 | 11 | ||
| 12 | extern int sysfs_add_file(struct dentry *, const struct attribute *, int); | 12 | extern int sysfs_add_file(struct dentry *, const struct attribute *, int); |
| 13 | extern void sysfs_hash_and_remove(struct dentry * dir, const char * name); | 13 | extern void sysfs_hash_and_remove(struct dentry * dir, const char * name); |
| 14 | extern struct sysfs_dirent *sysfs_find(struct sysfs_dirent *dir, const char * name); | ||
| 14 | 15 | ||
| 15 | extern int sysfs_create_subdir(struct kobject *, const char *, struct dentry **); | 16 | extern int sysfs_create_subdir(struct kobject *, const char *, struct dentry **); |
| 16 | extern void sysfs_remove_subdir(struct dentry *); | 17 | extern void sysfs_remove_subdir(struct dentry *); |
diff --git a/fs/xfs/linux-2.6/xfs_file.c b/fs/xfs/linux-2.6/xfs_file.c index 269721af02f3..c847416f6d10 100644 --- a/fs/xfs/linux-2.6/xfs_file.c +++ b/fs/xfs/linux-2.6/xfs_file.c | |||
| @@ -252,6 +252,7 @@ xfs_file_sendfile_invis( | |||
| 252 | STATIC ssize_t | 252 | STATIC ssize_t |
| 253 | xfs_file_splice_read( | 253 | xfs_file_splice_read( |
| 254 | struct file *infilp, | 254 | struct file *infilp, |
| 255 | loff_t *ppos, | ||
| 255 | struct pipe_inode_info *pipe, | 256 | struct pipe_inode_info *pipe, |
| 256 | size_t len, | 257 | size_t len, |
| 257 | unsigned int flags) | 258 | unsigned int flags) |
| @@ -259,13 +260,14 @@ xfs_file_splice_read( | |||
| 259 | vnode_t *vp = vn_from_inode(infilp->f_dentry->d_inode); | 260 | vnode_t *vp = vn_from_inode(infilp->f_dentry->d_inode); |
| 260 | ssize_t rval; | 261 | ssize_t rval; |
| 261 | 262 | ||
| 262 | VOP_SPLICE_READ(vp, infilp, pipe, len, flags, 0, NULL, rval); | 263 | VOP_SPLICE_READ(vp, infilp, ppos, pipe, len, flags, 0, NULL, rval); |
| 263 | return rval; | 264 | return rval; |
| 264 | } | 265 | } |
| 265 | 266 | ||
| 266 | STATIC ssize_t | 267 | STATIC ssize_t |
| 267 | xfs_file_splice_read_invis( | 268 | xfs_file_splice_read_invis( |
| 268 | struct file *infilp, | 269 | struct file *infilp, |
| 270 | loff_t *ppos, | ||
| 269 | struct pipe_inode_info *pipe, | 271 | struct pipe_inode_info *pipe, |
| 270 | size_t len, | 272 | size_t len, |
| 271 | unsigned int flags) | 273 | unsigned int flags) |
| @@ -273,7 +275,7 @@ xfs_file_splice_read_invis( | |||
| 273 | vnode_t *vp = vn_from_inode(infilp->f_dentry->d_inode); | 275 | vnode_t *vp = vn_from_inode(infilp->f_dentry->d_inode); |
| 274 | ssize_t rval; | 276 | ssize_t rval; |
| 275 | 277 | ||
| 276 | VOP_SPLICE_READ(vp, infilp, pipe, len, flags, IO_INVIS, NULL, rval); | 278 | VOP_SPLICE_READ(vp, infilp, ppos, pipe, len, flags, IO_INVIS, NULL, rval); |
| 277 | return rval; | 279 | return rval; |
| 278 | } | 280 | } |
| 279 | 281 | ||
| @@ -281,13 +283,14 @@ STATIC ssize_t | |||
| 281 | xfs_file_splice_write( | 283 | xfs_file_splice_write( |
| 282 | struct pipe_inode_info *pipe, | 284 | struct pipe_inode_info *pipe, |
| 283 | struct file *outfilp, | 285 | struct file *outfilp, |
| 286 | loff_t *ppos, | ||
| 284 | size_t len, | 287 | size_t len, |
| 285 | unsigned int flags) | 288 | unsigned int flags) |
| 286 | { | 289 | { |
| 287 | vnode_t *vp = vn_from_inode(outfilp->f_dentry->d_inode); | 290 | vnode_t *vp = vn_from_inode(outfilp->f_dentry->d_inode); |
| 288 | ssize_t rval; | 291 | ssize_t rval; |
| 289 | 292 | ||
| 290 | VOP_SPLICE_WRITE(vp, pipe, outfilp, len, flags, 0, NULL, rval); | 293 | VOP_SPLICE_WRITE(vp, pipe, outfilp, ppos, len, flags, 0, NULL, rval); |
| 291 | return rval; | 294 | return rval; |
| 292 | } | 295 | } |
| 293 | 296 | ||
| @@ -295,13 +298,14 @@ STATIC ssize_t | |||
| 295 | xfs_file_splice_write_invis( | 298 | xfs_file_splice_write_invis( |
| 296 | struct pipe_inode_info *pipe, | 299 | struct pipe_inode_info *pipe, |
| 297 | struct file *outfilp, | 300 | struct file *outfilp, |
| 301 | loff_t *ppos, | ||
| 298 | size_t len, | 302 | size_t len, |
| 299 | unsigned int flags) | 303 | unsigned int flags) |
| 300 | { | 304 | { |
| 301 | vnode_t *vp = vn_from_inode(outfilp->f_dentry->d_inode); | 305 | vnode_t *vp = vn_from_inode(outfilp->f_dentry->d_inode); |
| 302 | ssize_t rval; | 306 | ssize_t rval; |
| 303 | 307 | ||
| 304 | VOP_SPLICE_WRITE(vp, pipe, outfilp, len, flags, IO_INVIS, NULL, rval); | 308 | VOP_SPLICE_WRITE(vp, pipe, outfilp, ppos, len, flags, IO_INVIS, NULL, rval); |
| 305 | return rval; | 309 | return rval; |
| 306 | } | 310 | } |
| 307 | 311 | ||
diff --git a/fs/xfs/linux-2.6/xfs_lrw.c b/fs/xfs/linux-2.6/xfs_lrw.c index 74a52937f208..67efe3308980 100644 --- a/fs/xfs/linux-2.6/xfs_lrw.c +++ b/fs/xfs/linux-2.6/xfs_lrw.c | |||
| @@ -338,6 +338,7 @@ ssize_t | |||
| 338 | xfs_splice_read( | 338 | xfs_splice_read( |
| 339 | bhv_desc_t *bdp, | 339 | bhv_desc_t *bdp, |
| 340 | struct file *infilp, | 340 | struct file *infilp, |
| 341 | loff_t *ppos, | ||
| 341 | struct pipe_inode_info *pipe, | 342 | struct pipe_inode_info *pipe, |
| 342 | size_t count, | 343 | size_t count, |
| 343 | int flags, | 344 | int flags, |
| @@ -360,7 +361,7 @@ xfs_splice_read( | |||
| 360 | int error; | 361 | int error; |
| 361 | 362 | ||
| 362 | error = XFS_SEND_DATA(mp, DM_EVENT_READ, BHV_TO_VNODE(bdp), | 363 | error = XFS_SEND_DATA(mp, DM_EVENT_READ, BHV_TO_VNODE(bdp), |
| 363 | infilp->f_pos, count, | 364 | *ppos, count, |
| 364 | FILP_DELAY_FLAG(infilp), &locktype); | 365 | FILP_DELAY_FLAG(infilp), &locktype); |
| 365 | if (error) { | 366 | if (error) { |
| 366 | xfs_iunlock(ip, XFS_IOLOCK_SHARED); | 367 | xfs_iunlock(ip, XFS_IOLOCK_SHARED); |
| @@ -368,8 +369,8 @@ xfs_splice_read( | |||
| 368 | } | 369 | } |
| 369 | } | 370 | } |
| 370 | xfs_rw_enter_trace(XFS_SPLICE_READ_ENTER, &ip->i_iocore, | 371 | xfs_rw_enter_trace(XFS_SPLICE_READ_ENTER, &ip->i_iocore, |
| 371 | pipe, count, infilp->f_pos, ioflags); | 372 | pipe, count, *ppos, ioflags); |
| 372 | ret = generic_file_splice_read(infilp, pipe, count, flags); | 373 | ret = generic_file_splice_read(infilp, ppos, pipe, count, flags); |
| 373 | if (ret > 0) | 374 | if (ret > 0) |
| 374 | XFS_STATS_ADD(xs_read_bytes, ret); | 375 | XFS_STATS_ADD(xs_read_bytes, ret); |
| 375 | 376 | ||
| @@ -382,6 +383,7 @@ xfs_splice_write( | |||
| 382 | bhv_desc_t *bdp, | 383 | bhv_desc_t *bdp, |
| 383 | struct pipe_inode_info *pipe, | 384 | struct pipe_inode_info *pipe, |
| 384 | struct file *outfilp, | 385 | struct file *outfilp, |
| 386 | loff_t *ppos, | ||
| 385 | size_t count, | 387 | size_t count, |
| 386 | int flags, | 388 | int flags, |
| 387 | int ioflags, | 389 | int ioflags, |
| @@ -403,7 +405,7 @@ xfs_splice_write( | |||
| 403 | int error; | 405 | int error; |
| 404 | 406 | ||
| 405 | error = XFS_SEND_DATA(mp, DM_EVENT_WRITE, BHV_TO_VNODE(bdp), | 407 | error = XFS_SEND_DATA(mp, DM_EVENT_WRITE, BHV_TO_VNODE(bdp), |
| 406 | outfilp->f_pos, count, | 408 | *ppos, count, |
| 407 | FILP_DELAY_FLAG(outfilp), &locktype); | 409 | FILP_DELAY_FLAG(outfilp), &locktype); |
| 408 | if (error) { | 410 | if (error) { |
| 409 | xfs_iunlock(ip, XFS_IOLOCK_EXCL); | 411 | xfs_iunlock(ip, XFS_IOLOCK_EXCL); |
| @@ -411,8 +413,8 @@ xfs_splice_write( | |||
| 411 | } | 413 | } |
| 412 | } | 414 | } |
| 413 | xfs_rw_enter_trace(XFS_SPLICE_WRITE_ENTER, &ip->i_iocore, | 415 | xfs_rw_enter_trace(XFS_SPLICE_WRITE_ENTER, &ip->i_iocore, |
| 414 | pipe, count, outfilp->f_pos, ioflags); | 416 | pipe, count, *ppos, ioflags); |
| 415 | ret = generic_file_splice_write(pipe, outfilp, count, flags); | 417 | ret = generic_file_splice_write(pipe, outfilp, ppos, count, flags); |
| 416 | if (ret > 0) | 418 | if (ret > 0) |
| 417 | XFS_STATS_ADD(xs_write_bytes, ret); | 419 | XFS_STATS_ADD(xs_write_bytes, ret); |
| 418 | 420 | ||
diff --git a/fs/xfs/linux-2.6/xfs_lrw.h b/fs/xfs/linux-2.6/xfs_lrw.h index 55c689a86ad2..8f4539952350 100644 --- a/fs/xfs/linux-2.6/xfs_lrw.h +++ b/fs/xfs/linux-2.6/xfs_lrw.h | |||
| @@ -93,11 +93,11 @@ extern ssize_t xfs_write(struct bhv_desc *, struct kiocb *, | |||
| 93 | extern ssize_t xfs_sendfile(struct bhv_desc *, struct file *, | 93 | extern ssize_t xfs_sendfile(struct bhv_desc *, struct file *, |
| 94 | loff_t *, int, size_t, read_actor_t, | 94 | loff_t *, int, size_t, read_actor_t, |
| 95 | void *, struct cred *); | 95 | void *, struct cred *); |
| 96 | extern ssize_t xfs_splice_read(struct bhv_desc *, struct file *, | 96 | extern ssize_t xfs_splice_read(struct bhv_desc *, struct file *, loff_t *, |
| 97 | struct pipe_inode_info *, size_t, int, int, | 97 | struct pipe_inode_info *, size_t, int, int, |
| 98 | struct cred *); | 98 | struct cred *); |
| 99 | extern ssize_t xfs_splice_write(struct bhv_desc *, struct pipe_inode_info *, | 99 | extern ssize_t xfs_splice_write(struct bhv_desc *, struct pipe_inode_info *, |
| 100 | struct file *, size_t, int, int, | 100 | struct file *, loff_t *, size_t, int, int, |
| 101 | struct cred *); | 101 | struct cred *); |
| 102 | 102 | ||
| 103 | #endif /* __XFS_LRW_H__ */ | 103 | #endif /* __XFS_LRW_H__ */ |
diff --git a/fs/xfs/linux-2.6/xfs_vnode.h b/fs/xfs/linux-2.6/xfs_vnode.h index 88b09f186289..2a8e16c22353 100644 --- a/fs/xfs/linux-2.6/xfs_vnode.h +++ b/fs/xfs/linux-2.6/xfs_vnode.h | |||
| @@ -173,11 +173,11 @@ typedef ssize_t (*vop_write_t)(bhv_desc_t *, struct kiocb *, | |||
| 173 | typedef ssize_t (*vop_sendfile_t)(bhv_desc_t *, struct file *, | 173 | typedef ssize_t (*vop_sendfile_t)(bhv_desc_t *, struct file *, |
| 174 | loff_t *, int, size_t, read_actor_t, | 174 | loff_t *, int, size_t, read_actor_t, |
| 175 | void *, struct cred *); | 175 | void *, struct cred *); |
| 176 | typedef ssize_t (*vop_splice_read_t)(bhv_desc_t *, struct file *, | 176 | typedef ssize_t (*vop_splice_read_t)(bhv_desc_t *, struct file *, loff_t *, |
| 177 | struct pipe_inode_info *, size_t, int, int, | 177 | struct pipe_inode_info *, size_t, int, int, |
| 178 | struct cred *); | 178 | struct cred *); |
| 179 | typedef ssize_t (*vop_splice_write_t)(bhv_desc_t *, struct pipe_inode_info *, | 179 | typedef ssize_t (*vop_splice_write_t)(bhv_desc_t *, struct pipe_inode_info *, |
| 180 | struct file *, size_t, int, int, | 180 | struct file *, loff_t *, size_t, int, int, |
| 181 | struct cred *); | 181 | struct cred *); |
| 182 | typedef int (*vop_ioctl_t)(bhv_desc_t *, struct inode *, struct file *, | 182 | typedef int (*vop_ioctl_t)(bhv_desc_t *, struct inode *, struct file *, |
| 183 | int, unsigned int, void __user *); | 183 | int, unsigned int, void __user *); |
| @@ -284,10 +284,10 @@ typedef struct vnodeops { | |||
| 284 | rv = _VOP_(vop_write, vp)((vp)->v_fbhv,file,iov,segs,offset,ioflags,cr) | 284 | rv = _VOP_(vop_write, vp)((vp)->v_fbhv,file,iov,segs,offset,ioflags,cr) |
| 285 | #define VOP_SENDFILE(vp,f,off,ioflags,cnt,act,targ,cr,rv) \ | 285 | #define VOP_SENDFILE(vp,f,off,ioflags,cnt,act,targ,cr,rv) \ |
| 286 | rv = _VOP_(vop_sendfile, vp)((vp)->v_fbhv,f,off,ioflags,cnt,act,targ,cr) | 286 | rv = _VOP_(vop_sendfile, vp)((vp)->v_fbhv,f,off,ioflags,cnt,act,targ,cr) |
| 287 | #define VOP_SPLICE_READ(vp,f,pipe,cnt,fl,iofl,cr,rv) \ | 287 | #define VOP_SPLICE_READ(vp,f,o,pipe,cnt,fl,iofl,cr,rv) \ |
| 288 | rv = _VOP_(vop_splice_read, vp)((vp)->v_fbhv,f,pipe,cnt,fl,iofl,cr) | 288 | rv = _VOP_(vop_splice_read, vp)((vp)->v_fbhv,f,o,pipe,cnt,fl,iofl,cr) |
| 289 | #define VOP_SPLICE_WRITE(vp,f,pipe,cnt,fl,iofl,cr,rv) \ | 289 | #define VOP_SPLICE_WRITE(vp,f,o,pipe,cnt,fl,iofl,cr,rv) \ |
| 290 | rv = _VOP_(vop_splice_write, vp)((vp)->v_fbhv,f,pipe,cnt,fl,iofl,cr) | 290 | rv = _VOP_(vop_splice_write, vp)((vp)->v_fbhv,f,o,pipe,cnt,fl,iofl,cr) |
| 291 | #define VOP_BMAP(vp,of,sz,rw,b,n,rv) \ | 291 | #define VOP_BMAP(vp,of,sz,rw,b,n,rv) \ |
| 292 | rv = _VOP_(vop_bmap, vp)((vp)->v_fbhv,of,sz,rw,b,n) | 292 | rv = _VOP_(vop_bmap, vp)((vp)->v_fbhv,of,sz,rw,b,n) |
| 293 | #define VOP_OPEN(vp, cr, rv) \ | 293 | #define VOP_OPEN(vp, cr, rv) \ |
