diff options
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/btrfs/export.c | 2 | ||||
| -rw-r--r-- | fs/ceph/dir.c | 3 | ||||
| -rw-r--r-- | fs/ceph/file.c | 39 | ||||
| -rw-r--r-- | fs/logfs/journal.c | 2 | ||||
| -rw-r--r-- | fs/logfs/readwrite.c | 3 | ||||
| -rw-r--r-- | fs/namei.c | 3 | ||||
| -rw-r--r-- | fs/nilfs2/gcinode.c | 9 | ||||
| -rw-r--r-- | fs/nilfs2/ioctl.c | 12 | ||||
| -rw-r--r-- | fs/notify/fanotify/fanotify.c | 6 | ||||
| -rw-r--r-- | fs/notify/fanotify/fanotify_user.c | 81 | ||||
| -rw-r--r-- | fs/notify/inotify/inotify_user.c | 1 |
11 files changed, 102 insertions, 59 deletions
diff --git a/fs/btrfs/export.c b/fs/btrfs/export.c index 6f0444473594..659f532d26a0 100644 --- a/fs/btrfs/export.c +++ b/fs/btrfs/export.c | |||
| @@ -166,7 +166,7 @@ static struct dentry *btrfs_fh_to_dentry(struct super_block *sb, struct fid *fh, | |||
| 166 | static struct dentry *btrfs_get_parent(struct dentry *child) | 166 | static struct dentry *btrfs_get_parent(struct dentry *child) |
| 167 | { | 167 | { |
| 168 | struct inode *dir = child->d_inode; | 168 | struct inode *dir = child->d_inode; |
| 169 | static struct dentry *dentry; | 169 | struct dentry *dentry; |
| 170 | struct btrfs_root *root = BTRFS_I(dir)->root; | 170 | struct btrfs_root *root = BTRFS_I(dir)->root; |
| 171 | struct btrfs_path *path; | 171 | struct btrfs_path *path; |
| 172 | struct extent_buffer *leaf; | 172 | struct extent_buffer *leaf; |
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 158c700fdca5..d902948a90d8 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c | |||
| @@ -40,7 +40,8 @@ int ceph_init_dentry(struct dentry *dentry) | |||
| 40 | if (dentry->d_fsdata) | 40 | if (dentry->d_fsdata) |
| 41 | return 0; | 41 | return 0; |
| 42 | 42 | ||
| 43 | if (ceph_snap(dentry->d_parent->d_inode) == CEPH_NOSNAP) | 43 | if (dentry->d_parent == NULL || /* nfs fh_to_dentry */ |
| 44 | ceph_snap(dentry->d_parent->d_inode) == CEPH_NOSNAP) | ||
| 44 | dentry->d_op = &ceph_dentry_ops; | 45 | dentry->d_op = &ceph_dentry_ops; |
| 45 | else if (ceph_snap(dentry->d_parent->d_inode) == CEPH_SNAPDIR) | 46 | else if (ceph_snap(dentry->d_parent->d_inode) == CEPH_SNAPDIR) |
| 46 | dentry->d_op = &ceph_snapdir_dentry_ops; | 47 | dentry->d_op = &ceph_snapdir_dentry_ops; |
diff --git a/fs/ceph/file.c b/fs/ceph/file.c index 8d79b8912e31..7d0e4a82d898 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c | |||
| @@ -282,7 +282,8 @@ int ceph_release(struct inode *inode, struct file *file) | |||
| 282 | static int striped_read(struct inode *inode, | 282 | static int striped_read(struct inode *inode, |
| 283 | u64 off, u64 len, | 283 | u64 off, u64 len, |
| 284 | struct page **pages, int num_pages, | 284 | struct page **pages, int num_pages, |
| 285 | int *checkeof, bool align_to_pages) | 285 | int *checkeof, bool align_to_pages, |
| 286 | unsigned long buf_align) | ||
| 286 | { | 287 | { |
| 287 | struct ceph_fs_client *fsc = ceph_inode_to_client(inode); | 288 | struct ceph_fs_client *fsc = ceph_inode_to_client(inode); |
| 288 | struct ceph_inode_info *ci = ceph_inode(inode); | 289 | struct ceph_inode_info *ci = ceph_inode(inode); |
| @@ -307,7 +308,7 @@ static int striped_read(struct inode *inode, | |||
| 307 | 308 | ||
| 308 | more: | 309 | more: |
| 309 | if (align_to_pages) | 310 | if (align_to_pages) |
| 310 | page_align = (pos - io_align) & ~PAGE_MASK; | 311 | page_align = (pos - io_align + buf_align) & ~PAGE_MASK; |
| 311 | else | 312 | else |
| 312 | page_align = pos & ~PAGE_MASK; | 313 | page_align = pos & ~PAGE_MASK; |
| 313 | this_len = left; | 314 | this_len = left; |
| @@ -376,16 +377,18 @@ static ssize_t ceph_sync_read(struct file *file, char __user *data, | |||
| 376 | struct inode *inode = file->f_dentry->d_inode; | 377 | struct inode *inode = file->f_dentry->d_inode; |
| 377 | struct page **pages; | 378 | struct page **pages; |
| 378 | u64 off = *poff; | 379 | u64 off = *poff; |
| 379 | int num_pages = calc_pages_for(off, len); | 380 | int num_pages, ret; |
| 380 | int ret; | ||
| 381 | 381 | ||
| 382 | dout("sync_read on file %p %llu~%u %s\n", file, off, len, | 382 | dout("sync_read on file %p %llu~%u %s\n", file, off, len, |
| 383 | (file->f_flags & O_DIRECT) ? "O_DIRECT" : ""); | 383 | (file->f_flags & O_DIRECT) ? "O_DIRECT" : ""); |
| 384 | 384 | ||
| 385 | if (file->f_flags & O_DIRECT) | 385 | if (file->f_flags & O_DIRECT) { |
| 386 | pages = ceph_get_direct_page_vector(data, num_pages); | 386 | num_pages = calc_pages_for((unsigned long)data, len); |
| 387 | else | 387 | pages = ceph_get_direct_page_vector(data, num_pages, true); |
| 388 | } else { | ||
| 389 | num_pages = calc_pages_for(off, len); | ||
| 388 | pages = ceph_alloc_page_vector(num_pages, GFP_NOFS); | 390 | pages = ceph_alloc_page_vector(num_pages, GFP_NOFS); |
| 391 | } | ||
| 389 | if (IS_ERR(pages)) | 392 | if (IS_ERR(pages)) |
| 390 | return PTR_ERR(pages); | 393 | return PTR_ERR(pages); |
| 391 | 394 | ||
| @@ -400,7 +403,8 @@ static ssize_t ceph_sync_read(struct file *file, char __user *data, | |||
| 400 | goto done; | 403 | goto done; |
| 401 | 404 | ||
| 402 | ret = striped_read(inode, off, len, pages, num_pages, checkeof, | 405 | ret = striped_read(inode, off, len, pages, num_pages, checkeof, |
| 403 | file->f_flags & O_DIRECT); | 406 | file->f_flags & O_DIRECT, |
| 407 | (unsigned long)data & ~PAGE_MASK); | ||
| 404 | 408 | ||
| 405 | if (ret >= 0 && (file->f_flags & O_DIRECT) == 0) | 409 | if (ret >= 0 && (file->f_flags & O_DIRECT) == 0) |
| 406 | ret = ceph_copy_page_vector_to_user(pages, data, off, ret); | 410 | ret = ceph_copy_page_vector_to_user(pages, data, off, ret); |
| @@ -409,7 +413,7 @@ static ssize_t ceph_sync_read(struct file *file, char __user *data, | |||
| 409 | 413 | ||
| 410 | done: | 414 | done: |
| 411 | if (file->f_flags & O_DIRECT) | 415 | if (file->f_flags & O_DIRECT) |
| 412 | ceph_put_page_vector(pages, num_pages); | 416 | ceph_put_page_vector(pages, num_pages, true); |
| 413 | else | 417 | else |
| 414 | ceph_release_page_vector(pages, num_pages); | 418 | ceph_release_page_vector(pages, num_pages); |
| 415 | dout("sync_read result %d\n", ret); | 419 | dout("sync_read result %d\n", ret); |
| @@ -456,6 +460,7 @@ static ssize_t ceph_sync_write(struct file *file, const char __user *data, | |||
| 456 | int do_sync = 0; | 460 | int do_sync = 0; |
| 457 | int check_caps = 0; | 461 | int check_caps = 0; |
| 458 | int page_align, io_align; | 462 | int page_align, io_align; |
| 463 | unsigned long buf_align; | ||
| 459 | int ret; | 464 | int ret; |
| 460 | struct timespec mtime = CURRENT_TIME; | 465 | struct timespec mtime = CURRENT_TIME; |
| 461 | 466 | ||
| @@ -471,6 +476,7 @@ static ssize_t ceph_sync_write(struct file *file, const char __user *data, | |||
| 471 | pos = *offset; | 476 | pos = *offset; |
| 472 | 477 | ||
| 473 | io_align = pos & ~PAGE_MASK; | 478 | io_align = pos & ~PAGE_MASK; |
| 479 | buf_align = (unsigned long)data & ~PAGE_MASK; | ||
| 474 | 480 | ||
| 475 | ret = filemap_write_and_wait_range(inode->i_mapping, pos, pos + left); | 481 | ret = filemap_write_and_wait_range(inode->i_mapping, pos, pos + left); |
| 476 | if (ret < 0) | 482 | if (ret < 0) |
| @@ -496,12 +502,15 @@ static ssize_t ceph_sync_write(struct file *file, const char __user *data, | |||
| 496 | */ | 502 | */ |
| 497 | more: | 503 | more: |
| 498 | len = left; | 504 | len = left; |
| 499 | if (file->f_flags & O_DIRECT) | 505 | if (file->f_flags & O_DIRECT) { |
| 500 | /* write from beginning of first page, regardless of | 506 | /* write from beginning of first page, regardless of |
| 501 | io alignment */ | 507 | io alignment */ |
| 502 | page_align = (pos - io_align) & ~PAGE_MASK; | 508 | page_align = (pos - io_align + buf_align) & ~PAGE_MASK; |
| 503 | else | 509 | num_pages = calc_pages_for((unsigned long)data, len); |
| 510 | } else { | ||
| 504 | page_align = pos & ~PAGE_MASK; | 511 | page_align = pos & ~PAGE_MASK; |
| 512 | num_pages = calc_pages_for(pos, len); | ||
| 513 | } | ||
| 505 | req = ceph_osdc_new_request(&fsc->client->osdc, &ci->i_layout, | 514 | req = ceph_osdc_new_request(&fsc->client->osdc, &ci->i_layout, |
| 506 | ceph_vino(inode), pos, &len, | 515 | ceph_vino(inode), pos, &len, |
| 507 | CEPH_OSD_OP_WRITE, flags, | 516 | CEPH_OSD_OP_WRITE, flags, |
| @@ -512,10 +521,8 @@ more: | |||
| 512 | if (!req) | 521 | if (!req) |
| 513 | return -ENOMEM; | 522 | return -ENOMEM; |
| 514 | 523 | ||
| 515 | num_pages = calc_pages_for(pos, len); | ||
| 516 | |||
| 517 | if (file->f_flags & O_DIRECT) { | 524 | if (file->f_flags & O_DIRECT) { |
| 518 | pages = ceph_get_direct_page_vector(data, num_pages); | 525 | pages = ceph_get_direct_page_vector(data, num_pages, false); |
| 519 | if (IS_ERR(pages)) { | 526 | if (IS_ERR(pages)) { |
| 520 | ret = PTR_ERR(pages); | 527 | ret = PTR_ERR(pages); |
| 521 | goto out; | 528 | goto out; |
| @@ -565,7 +572,7 @@ more: | |||
| 565 | } | 572 | } |
| 566 | 573 | ||
| 567 | if (file->f_flags & O_DIRECT) | 574 | if (file->f_flags & O_DIRECT) |
| 568 | ceph_put_page_vector(pages, num_pages); | 575 | ceph_put_page_vector(pages, num_pages, false); |
| 569 | else if (file->f_flags & O_SYNC) | 576 | else if (file->f_flags & O_SYNC) |
| 570 | ceph_release_page_vector(pages, num_pages); | 577 | ceph_release_page_vector(pages, num_pages); |
| 571 | 578 | ||
diff --git a/fs/logfs/journal.c b/fs/logfs/journal.c index f46ee8b0e135..9da29706f91c 100644 --- a/fs/logfs/journal.c +++ b/fs/logfs/journal.c | |||
| @@ -828,7 +828,7 @@ void do_logfs_journal_wl_pass(struct super_block *sb) | |||
| 828 | super->s_journal_seg[i] = segno; | 828 | super->s_journal_seg[i] = segno; |
| 829 | super->s_journal_ec[i] = ec; | 829 | super->s_journal_ec[i] = ec; |
| 830 | logfs_set_segment_reserved(sb, segno); | 830 | logfs_set_segment_reserved(sb, segno); |
| 831 | err = btree_insert32(head, segno, (void *)1, GFP_KERNEL); | 831 | err = btree_insert32(head, segno, (void *)1, GFP_NOFS); |
| 832 | BUG_ON(err); /* mempool should prevent this */ | 832 | BUG_ON(err); /* mempool should prevent this */ |
| 833 | err = logfs_erase_segment(sb, segno, 1); | 833 | err = logfs_erase_segment(sb, segno, 1); |
| 834 | BUG_ON(err); /* FIXME: remount-ro would be nicer */ | 834 | BUG_ON(err); /* FIXME: remount-ro would be nicer */ |
diff --git a/fs/logfs/readwrite.c b/fs/logfs/readwrite.c index 6127baf0e188..ee99a9f5dfd3 100644 --- a/fs/logfs/readwrite.c +++ b/fs/logfs/readwrite.c | |||
| @@ -1994,6 +1994,9 @@ static int do_write_inode(struct inode *inode) | |||
| 1994 | 1994 | ||
| 1995 | /* FIXME: transaction is part of logfs_block now. Is that enough? */ | 1995 | /* FIXME: transaction is part of logfs_block now. Is that enough? */ |
| 1996 | err = logfs_write_buf(master_inode, page, 0); | 1996 | err = logfs_write_buf(master_inode, page, 0); |
| 1997 | if (err) | ||
| 1998 | move_page_to_inode(inode, page); | ||
| 1999 | |||
| 1997 | logfs_put_write_page(page); | 2000 | logfs_put_write_page(page); |
| 1998 | return err; | 2001 | return err; |
| 1999 | } | 2002 | } |
diff --git a/fs/namei.c b/fs/namei.c index 5362af9b7372..4ff7ca530533 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
| @@ -1748,6 +1748,9 @@ struct file *do_filp_open(int dfd, const char *pathname, | |||
| 1748 | if (!(open_flag & O_CREAT)) | 1748 | if (!(open_flag & O_CREAT)) |
| 1749 | mode = 0; | 1749 | mode = 0; |
| 1750 | 1750 | ||
| 1751 | /* Must never be set by userspace */ | ||
| 1752 | open_flag &= ~FMODE_NONOTIFY; | ||
| 1753 | |||
| 1751 | /* | 1754 | /* |
| 1752 | * O_SYNC is implemented as __O_SYNC|O_DSYNC. As many places only | 1755 | * O_SYNC is implemented as __O_SYNC|O_DSYNC. As many places only |
| 1753 | * check for O_DSYNC if the need any syncing at all we enforce it's | 1756 | * check for O_DSYNC if the need any syncing at all we enforce it's |
diff --git a/fs/nilfs2/gcinode.c b/fs/nilfs2/gcinode.c index 33ad25ddd5c4..caf9a6a3fb54 100644 --- a/fs/nilfs2/gcinode.c +++ b/fs/nilfs2/gcinode.c | |||
| @@ -176,7 +176,6 @@ int nilfs_gccache_wait_and_mark_dirty(struct buffer_head *bh) | |||
| 176 | int nilfs_init_gcinode(struct inode *inode) | 176 | int nilfs_init_gcinode(struct inode *inode) |
| 177 | { | 177 | { |
| 178 | struct nilfs_inode_info *ii = NILFS_I(inode); | 178 | struct nilfs_inode_info *ii = NILFS_I(inode); |
| 179 | struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs; | ||
| 180 | 179 | ||
| 181 | inode->i_mode = S_IFREG; | 180 | inode->i_mode = S_IFREG; |
| 182 | mapping_set_gfp_mask(inode->i_mapping, GFP_NOFS); | 181 | mapping_set_gfp_mask(inode->i_mapping, GFP_NOFS); |
| @@ -186,14 +185,6 @@ int nilfs_init_gcinode(struct inode *inode) | |||
| 186 | ii->i_flags = 0; | 185 | ii->i_flags = 0; |
| 187 | nilfs_bmap_init_gc(ii->i_bmap); | 186 | nilfs_bmap_init_gc(ii->i_bmap); |
| 188 | 187 | ||
| 189 | /* | ||
| 190 | * Add the inode to GC inode list. Garbage Collection | ||
| 191 | * is serialized and no two processes manipulate the | ||
| 192 | * list simultaneously. | ||
| 193 | */ | ||
| 194 | igrab(inode); | ||
| 195 | list_add(&NILFS_I(inode)->i_dirty, &nilfs->ns_gc_inodes); | ||
| 196 | |||
| 197 | return 0; | 188 | return 0; |
| 198 | } | 189 | } |
| 199 | 190 | ||
diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c index e00d9457c256..b185e937a335 100644 --- a/fs/nilfs2/ioctl.c +++ b/fs/nilfs2/ioctl.c | |||
| @@ -337,6 +337,7 @@ static int nilfs_ioctl_move_blocks(struct super_block *sb, | |||
| 337 | struct nilfs_argv *argv, void *buf) | 337 | struct nilfs_argv *argv, void *buf) |
| 338 | { | 338 | { |
| 339 | size_t nmembs = argv->v_nmembs; | 339 | size_t nmembs = argv->v_nmembs; |
| 340 | struct the_nilfs *nilfs = NILFS_SB(sb)->s_nilfs; | ||
| 340 | struct inode *inode; | 341 | struct inode *inode; |
| 341 | struct nilfs_vdesc *vdesc; | 342 | struct nilfs_vdesc *vdesc; |
| 342 | struct buffer_head *bh, *n; | 343 | struct buffer_head *bh, *n; |
| @@ -353,6 +354,17 @@ static int nilfs_ioctl_move_blocks(struct super_block *sb, | |||
| 353 | ret = PTR_ERR(inode); | 354 | ret = PTR_ERR(inode); |
| 354 | goto failed; | 355 | goto failed; |
| 355 | } | 356 | } |
| 357 | if (list_empty(&NILFS_I(inode)->i_dirty)) { | ||
| 358 | /* | ||
| 359 | * Add the inode to GC inode list. Garbage Collection | ||
| 360 | * is serialized and no two processes manipulate the | ||
| 361 | * list simultaneously. | ||
| 362 | */ | ||
| 363 | igrab(inode); | ||
| 364 | list_add(&NILFS_I(inode)->i_dirty, | ||
| 365 | &nilfs->ns_gc_inodes); | ||
| 366 | } | ||
| 367 | |||
| 356 | do { | 368 | do { |
| 357 | ret = nilfs_ioctl_move_inode_block(inode, vdesc, | 369 | ret = nilfs_ioctl_move_inode_block(inode, vdesc, |
| 358 | &buffers); | 370 | &buffers); |
diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c index b04f88eed09e..f35794b97e8e 100644 --- a/fs/notify/fanotify/fanotify.c +++ b/fs/notify/fanotify/fanotify.c | |||
| @@ -92,7 +92,11 @@ static int fanotify_get_response_from_access(struct fsnotify_group *group, | |||
| 92 | 92 | ||
| 93 | pr_debug("%s: group=%p event=%p\n", __func__, group, event); | 93 | pr_debug("%s: group=%p event=%p\n", __func__, group, event); |
| 94 | 94 | ||
| 95 | wait_event(group->fanotify_data.access_waitq, event->response); | 95 | wait_event(group->fanotify_data.access_waitq, event->response || |
| 96 | atomic_read(&group->fanotify_data.bypass_perm)); | ||
| 97 | |||
| 98 | if (!event->response) /* bypass_perm set */ | ||
| 99 | return 0; | ||
| 96 | 100 | ||
| 97 | /* userspace responded, convert to something usable */ | 101 | /* userspace responded, convert to something usable */ |
| 98 | spin_lock(&event->lock); | 102 | spin_lock(&event->lock); |
diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c index 063224812b7e..8b61220cffc5 100644 --- a/fs/notify/fanotify/fanotify_user.c +++ b/fs/notify/fanotify/fanotify_user.c | |||
| @@ -106,20 +106,29 @@ static int create_fd(struct fsnotify_group *group, struct fsnotify_event *event) | |||
| 106 | return client_fd; | 106 | return client_fd; |
| 107 | } | 107 | } |
| 108 | 108 | ||
| 109 | static ssize_t fill_event_metadata(struct fsnotify_group *group, | 109 | static int fill_event_metadata(struct fsnotify_group *group, |
| 110 | struct fanotify_event_metadata *metadata, | 110 | struct fanotify_event_metadata *metadata, |
| 111 | struct fsnotify_event *event) | 111 | struct fsnotify_event *event) |
| 112 | { | 112 | { |
| 113 | int ret = 0; | ||
| 114 | |||
| 113 | pr_debug("%s: group=%p metadata=%p event=%p\n", __func__, | 115 | pr_debug("%s: group=%p metadata=%p event=%p\n", __func__, |
| 114 | group, metadata, event); | 116 | group, metadata, event); |
| 115 | 117 | ||
| 116 | metadata->event_len = FAN_EVENT_METADATA_LEN; | 118 | metadata->event_len = FAN_EVENT_METADATA_LEN; |
| 119 | metadata->metadata_len = FAN_EVENT_METADATA_LEN; | ||
| 117 | metadata->vers = FANOTIFY_METADATA_VERSION; | 120 | metadata->vers = FANOTIFY_METADATA_VERSION; |
| 118 | metadata->mask = event->mask & FAN_ALL_OUTGOING_EVENTS; | 121 | metadata->mask = event->mask & FAN_ALL_OUTGOING_EVENTS; |
| 119 | metadata->pid = pid_vnr(event->tgid); | 122 | metadata->pid = pid_vnr(event->tgid); |
| 120 | metadata->fd = create_fd(group, event); | 123 | if (unlikely(event->mask & FAN_Q_OVERFLOW)) |
| 124 | metadata->fd = FAN_NOFD; | ||
| 125 | else { | ||
| 126 | metadata->fd = create_fd(group, event); | ||
| 127 | if (metadata->fd < 0) | ||
| 128 | ret = metadata->fd; | ||
| 129 | } | ||
| 121 | 130 | ||
| 122 | return metadata->fd; | 131 | return ret; |
| 123 | } | 132 | } |
| 124 | 133 | ||
| 125 | #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS | 134 | #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS |
| @@ -200,7 +209,7 @@ static int prepare_for_access_response(struct fsnotify_group *group, | |||
| 200 | 209 | ||
| 201 | mutex_lock(&group->fanotify_data.access_mutex); | 210 | mutex_lock(&group->fanotify_data.access_mutex); |
| 202 | 211 | ||
| 203 | if (group->fanotify_data.bypass_perm) { | 212 | if (atomic_read(&group->fanotify_data.bypass_perm)) { |
| 204 | mutex_unlock(&group->fanotify_data.access_mutex); | 213 | mutex_unlock(&group->fanotify_data.access_mutex); |
| 205 | kmem_cache_free(fanotify_response_event_cache, re); | 214 | kmem_cache_free(fanotify_response_event_cache, re); |
| 206 | event->response = FAN_ALLOW; | 215 | event->response = FAN_ALLOW; |
| @@ -257,24 +266,34 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group, | |||
| 257 | 266 | ||
| 258 | pr_debug("%s: group=%p event=%p\n", __func__, group, event); | 267 | pr_debug("%s: group=%p event=%p\n", __func__, group, event); |
| 259 | 268 | ||
| 260 | fd = fill_event_metadata(group, &fanotify_event_metadata, event); | 269 | ret = fill_event_metadata(group, &fanotify_event_metadata, event); |
| 261 | if (fd < 0) | 270 | if (ret < 0) |
| 262 | return fd; | 271 | goto out; |
| 263 | 272 | ||
| 273 | fd = fanotify_event_metadata.fd; | ||
| 264 | ret = prepare_for_access_response(group, event, fd); | 274 | ret = prepare_for_access_response(group, event, fd); |
| 265 | if (ret) | 275 | if (ret) |
| 266 | goto out_close_fd; | 276 | goto out_close_fd; |
| 267 | 277 | ||
| 268 | ret = -EFAULT; | 278 | ret = -EFAULT; |
| 269 | if (copy_to_user(buf, &fanotify_event_metadata, FAN_EVENT_METADATA_LEN)) | 279 | if (copy_to_user(buf, &fanotify_event_metadata, |
| 280 | fanotify_event_metadata.event_len)) | ||
| 270 | goto out_kill_access_response; | 281 | goto out_kill_access_response; |
| 271 | 282 | ||
| 272 | return FAN_EVENT_METADATA_LEN; | 283 | return fanotify_event_metadata.event_len; |
| 273 | 284 | ||
| 274 | out_kill_access_response: | 285 | out_kill_access_response: |
| 275 | remove_access_response(group, event, fd); | 286 | remove_access_response(group, event, fd); |
| 276 | out_close_fd: | 287 | out_close_fd: |
| 277 | sys_close(fd); | 288 | if (fd != FAN_NOFD) |
| 289 | sys_close(fd); | ||
| 290 | out: | ||
| 291 | #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS | ||
| 292 | if (event->mask & FAN_ALL_PERM_EVENTS) { | ||
| 293 | event->response = FAN_DENY; | ||
| 294 | wake_up(&group->fanotify_data.access_waitq); | ||
| 295 | } | ||
| 296 | #endif | ||
| 278 | return ret; | 297 | return ret; |
| 279 | } | 298 | } |
| 280 | 299 | ||
| @@ -382,7 +401,7 @@ static int fanotify_release(struct inode *ignored, struct file *file) | |||
| 382 | 401 | ||
| 383 | mutex_lock(&group->fanotify_data.access_mutex); | 402 | mutex_lock(&group->fanotify_data.access_mutex); |
| 384 | 403 | ||
| 385 | group->fanotify_data.bypass_perm = true; | 404 | atomic_inc(&group->fanotify_data.bypass_perm); |
| 386 | 405 | ||
| 387 | list_for_each_entry_safe(re, lre, &group->fanotify_data.access_list, list) { | 406 | list_for_each_entry_safe(re, lre, &group->fanotify_data.access_list, list) { |
| 388 | pr_debug("%s: found group=%p re=%p event=%p\n", __func__, group, | 407 | pr_debug("%s: found group=%p re=%p event=%p\n", __func__, group, |
| @@ -586,11 +605,10 @@ static int fanotify_add_vfsmount_mark(struct fsnotify_group *group, | |||
| 586 | { | 605 | { |
| 587 | struct fsnotify_mark *fsn_mark; | 606 | struct fsnotify_mark *fsn_mark; |
| 588 | __u32 added; | 607 | __u32 added; |
| 608 | int ret = 0; | ||
| 589 | 609 | ||
| 590 | fsn_mark = fsnotify_find_vfsmount_mark(group, mnt); | 610 | fsn_mark = fsnotify_find_vfsmount_mark(group, mnt); |
| 591 | if (!fsn_mark) { | 611 | if (!fsn_mark) { |
| 592 | int ret; | ||
| 593 | |||
| 594 | if (atomic_read(&group->num_marks) > group->fanotify_data.max_marks) | 612 | if (atomic_read(&group->num_marks) > group->fanotify_data.max_marks) |
| 595 | return -ENOSPC; | 613 | return -ENOSPC; |
| 596 | 614 | ||
| @@ -600,17 +618,16 @@ static int fanotify_add_vfsmount_mark(struct fsnotify_group *group, | |||
| 600 | 618 | ||
| 601 | fsnotify_init_mark(fsn_mark, fanotify_free_mark); | 619 | fsnotify_init_mark(fsn_mark, fanotify_free_mark); |
| 602 | ret = fsnotify_add_mark(fsn_mark, group, NULL, mnt, 0); | 620 | ret = fsnotify_add_mark(fsn_mark, group, NULL, mnt, 0); |
| 603 | if (ret) { | 621 | if (ret) |
| 604 | fanotify_free_mark(fsn_mark); | 622 | goto err; |
| 605 | return ret; | ||
| 606 | } | ||
| 607 | } | 623 | } |
| 608 | added = fanotify_mark_add_to_mask(fsn_mark, mask, flags); | 624 | added = fanotify_mark_add_to_mask(fsn_mark, mask, flags); |
| 609 | fsnotify_put_mark(fsn_mark); | 625 | |
| 610 | if (added & ~mnt->mnt_fsnotify_mask) | 626 | if (added & ~mnt->mnt_fsnotify_mask) |
| 611 | fsnotify_recalc_vfsmount_mask(mnt); | 627 | fsnotify_recalc_vfsmount_mask(mnt); |
| 612 | 628 | err: | |
| 613 | return 0; | 629 | fsnotify_put_mark(fsn_mark); |
| 630 | return ret; | ||
| 614 | } | 631 | } |
| 615 | 632 | ||
| 616 | static int fanotify_add_inode_mark(struct fsnotify_group *group, | 633 | static int fanotify_add_inode_mark(struct fsnotify_group *group, |
| @@ -619,6 +636,7 @@ static int fanotify_add_inode_mark(struct fsnotify_group *group, | |||
| 619 | { | 636 | { |
| 620 | struct fsnotify_mark *fsn_mark; | 637 | struct fsnotify_mark *fsn_mark; |
| 621 | __u32 added; | 638 | __u32 added; |
| 639 | int ret = 0; | ||
| 622 | 640 | ||
| 623 | pr_debug("%s: group=%p inode=%p\n", __func__, group, inode); | 641 | pr_debug("%s: group=%p inode=%p\n", __func__, group, inode); |
| 624 | 642 | ||
| @@ -634,8 +652,6 @@ static int fanotify_add_inode_mark(struct fsnotify_group *group, | |||
| 634 | 652 | ||
| 635 | fsn_mark = fsnotify_find_inode_mark(group, inode); | 653 | fsn_mark = fsnotify_find_inode_mark(group, inode); |
| 636 | if (!fsn_mark) { | 654 | if (!fsn_mark) { |
| 637 | int ret; | ||
| 638 | |||
| 639 | if (atomic_read(&group->num_marks) > group->fanotify_data.max_marks) | 655 | if (atomic_read(&group->num_marks) > group->fanotify_data.max_marks) |
| 640 | return -ENOSPC; | 656 | return -ENOSPC; |
| 641 | 657 | ||
| @@ -645,16 +661,16 @@ static int fanotify_add_inode_mark(struct fsnotify_group *group, | |||
| 645 | 661 | ||
| 646 | fsnotify_init_mark(fsn_mark, fanotify_free_mark); | 662 | fsnotify_init_mark(fsn_mark, fanotify_free_mark); |
| 647 | ret = fsnotify_add_mark(fsn_mark, group, inode, NULL, 0); | 663 | ret = fsnotify_add_mark(fsn_mark, group, inode, NULL, 0); |
| 648 | if (ret) { | 664 | if (ret) |
| 649 | fanotify_free_mark(fsn_mark); | 665 | goto err; |
| 650 | return ret; | ||
| 651 | } | ||
| 652 | } | 666 | } |
| 653 | added = fanotify_mark_add_to_mask(fsn_mark, mask, flags); | 667 | added = fanotify_mark_add_to_mask(fsn_mark, mask, flags); |
| 654 | fsnotify_put_mark(fsn_mark); | 668 | |
| 655 | if (added & ~inode->i_fsnotify_mask) | 669 | if (added & ~inode->i_fsnotify_mask) |
| 656 | fsnotify_recalc_inode_mask(inode); | 670 | fsnotify_recalc_inode_mask(inode); |
| 657 | return 0; | 671 | err: |
| 672 | fsnotify_put_mark(fsn_mark); | ||
| 673 | return ret; | ||
| 658 | } | 674 | } |
| 659 | 675 | ||
| 660 | /* fanotify syscalls */ | 676 | /* fanotify syscalls */ |
| @@ -687,8 +703,10 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags) | |||
| 687 | 703 | ||
| 688 | /* fsnotify_alloc_group takes a ref. Dropped in fanotify_release */ | 704 | /* fsnotify_alloc_group takes a ref. Dropped in fanotify_release */ |
| 689 | group = fsnotify_alloc_group(&fanotify_fsnotify_ops); | 705 | group = fsnotify_alloc_group(&fanotify_fsnotify_ops); |
| 690 | if (IS_ERR(group)) | 706 | if (IS_ERR(group)) { |
| 707 | free_uid(user); | ||
| 691 | return PTR_ERR(group); | 708 | return PTR_ERR(group); |
| 709 | } | ||
| 692 | 710 | ||
| 693 | group->fanotify_data.user = user; | 711 | group->fanotify_data.user = user; |
| 694 | atomic_inc(&user->fanotify_listeners); | 712 | atomic_inc(&user->fanotify_listeners); |
| @@ -698,6 +716,7 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags) | |||
| 698 | mutex_init(&group->fanotify_data.access_mutex); | 716 | mutex_init(&group->fanotify_data.access_mutex); |
| 699 | init_waitqueue_head(&group->fanotify_data.access_waitq); | 717 | init_waitqueue_head(&group->fanotify_data.access_waitq); |
| 700 | INIT_LIST_HEAD(&group->fanotify_data.access_list); | 718 | INIT_LIST_HEAD(&group->fanotify_data.access_list); |
| 719 | atomic_set(&group->fanotify_data.bypass_perm, 0); | ||
| 701 | #endif | 720 | #endif |
| 702 | switch (flags & FAN_ALL_CLASS_BITS) { | 721 | switch (flags & FAN_ALL_CLASS_BITS) { |
| 703 | case FAN_CLASS_NOTIF: | 722 | case FAN_CLASS_NOTIF: |
| @@ -764,8 +783,10 @@ SYSCALL_DEFINE(fanotify_mark)(int fanotify_fd, unsigned int flags, | |||
| 764 | if (flags & ~FAN_ALL_MARK_FLAGS) | 783 | if (flags & ~FAN_ALL_MARK_FLAGS) |
| 765 | return -EINVAL; | 784 | return -EINVAL; |
| 766 | switch (flags & (FAN_MARK_ADD | FAN_MARK_REMOVE | FAN_MARK_FLUSH)) { | 785 | switch (flags & (FAN_MARK_ADD | FAN_MARK_REMOVE | FAN_MARK_FLUSH)) { |
| 767 | case FAN_MARK_ADD: | 786 | case FAN_MARK_ADD: /* fallthrough */ |
| 768 | case FAN_MARK_REMOVE: | 787 | case FAN_MARK_REMOVE: |
| 788 | if (!mask) | ||
| 789 | return -EINVAL; | ||
| 769 | case FAN_MARK_FLUSH: | 790 | case FAN_MARK_FLUSH: |
| 770 | break; | 791 | break; |
| 771 | default: | 792 | default: |
diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c index 444c305a468c..4cd5d5d78f9f 100644 --- a/fs/notify/inotify/inotify_user.c +++ b/fs/notify/inotify/inotify_user.c | |||
| @@ -752,6 +752,7 @@ SYSCALL_DEFINE1(inotify_init1, int, flags) | |||
| 752 | if (ret >= 0) | 752 | if (ret >= 0) |
| 753 | return ret; | 753 | return ret; |
| 754 | 754 | ||
| 755 | fsnotify_put_group(group); | ||
| 755 | atomic_dec(&user->inotify_devs); | 756 | atomic_dec(&user->inotify_devs); |
| 756 | out_free_uid: | 757 | out_free_uid: |
| 757 | free_uid(user); | 758 | free_uid(user); |
