diff options
Diffstat (limited to 'fs')
37 files changed, 330 insertions, 214 deletions
| @@ -75,6 +75,7 @@ static struct kmem_cache *bio_find_or_create_slab(unsigned int extra_size) | |||
| 75 | unsigned int sz = sizeof(struct bio) + extra_size; | 75 | unsigned int sz = sizeof(struct bio) + extra_size; |
| 76 | struct kmem_cache *slab = NULL; | 76 | struct kmem_cache *slab = NULL; |
| 77 | struct bio_slab *bslab, *new_bio_slabs; | 77 | struct bio_slab *bslab, *new_bio_slabs; |
| 78 | unsigned int new_bio_slab_max; | ||
| 78 | unsigned int i, entry = -1; | 79 | unsigned int i, entry = -1; |
| 79 | 80 | ||
| 80 | mutex_lock(&bio_slab_lock); | 81 | mutex_lock(&bio_slab_lock); |
| @@ -97,12 +98,13 @@ static struct kmem_cache *bio_find_or_create_slab(unsigned int extra_size) | |||
| 97 | goto out_unlock; | 98 | goto out_unlock; |
| 98 | 99 | ||
| 99 | if (bio_slab_nr == bio_slab_max && entry == -1) { | 100 | if (bio_slab_nr == bio_slab_max && entry == -1) { |
| 100 | bio_slab_max <<= 1; | 101 | new_bio_slab_max = bio_slab_max << 1; |
| 101 | new_bio_slabs = krealloc(bio_slabs, | 102 | new_bio_slabs = krealloc(bio_slabs, |
| 102 | bio_slab_max * sizeof(struct bio_slab), | 103 | new_bio_slab_max * sizeof(struct bio_slab), |
| 103 | GFP_KERNEL); | 104 | GFP_KERNEL); |
| 104 | if (!new_bio_slabs) | 105 | if (!new_bio_slabs) |
| 105 | goto out_unlock; | 106 | goto out_unlock; |
| 107 | bio_slab_max = new_bio_slab_max; | ||
| 106 | bio_slabs = new_bio_slabs; | 108 | bio_slabs = new_bio_slabs; |
| 107 | } | 109 | } |
| 108 | if (entry == -1) | 110 | if (entry == -1) |
diff --git a/fs/ceph/export.c b/fs/ceph/export.c index 02ce90972d81..9349bb37a2fe 100644 --- a/fs/ceph/export.c +++ b/fs/ceph/export.c | |||
| @@ -90,6 +90,8 @@ static int ceph_encode_fh(struct inode *inode, u32 *rawfh, int *max_len, | |||
| 90 | *max_len = handle_length; | 90 | *max_len = handle_length; |
| 91 | type = 255; | 91 | type = 255; |
| 92 | } | 92 | } |
| 93 | if (dentry) | ||
| 94 | dput(dentry); | ||
| 93 | return type; | 95 | return type; |
| 94 | } | 96 | } |
| 95 | 97 | ||
diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index fc783e264420..0fb15bbbe43c 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c | |||
| @@ -225,6 +225,13 @@ sid_to_str(struct cifs_sid *sidptr, char *sidstr) | |||
| 225 | } | 225 | } |
| 226 | 226 | ||
| 227 | static void | 227 | static void |
| 228 | cifs_copy_sid(struct cifs_sid *dst, const struct cifs_sid *src) | ||
| 229 | { | ||
| 230 | memcpy(dst, src, sizeof(*dst)); | ||
| 231 | dst->num_subauth = min_t(u8, src->num_subauth, NUM_SUBAUTHS); | ||
| 232 | } | ||
| 233 | |||
| 234 | static void | ||
| 228 | id_rb_insert(struct rb_root *root, struct cifs_sid *sidptr, | 235 | id_rb_insert(struct rb_root *root, struct cifs_sid *sidptr, |
| 229 | struct cifs_sid_id **psidid, char *typestr) | 236 | struct cifs_sid_id **psidid, char *typestr) |
| 230 | { | 237 | { |
| @@ -248,7 +255,7 @@ id_rb_insert(struct rb_root *root, struct cifs_sid *sidptr, | |||
| 248 | } | 255 | } |
| 249 | } | 256 | } |
| 250 | 257 | ||
| 251 | memcpy(&(*psidid)->sid, sidptr, sizeof(struct cifs_sid)); | 258 | cifs_copy_sid(&(*psidid)->sid, sidptr); |
| 252 | (*psidid)->time = jiffies - (SID_MAP_RETRY + 1); | 259 | (*psidid)->time = jiffies - (SID_MAP_RETRY + 1); |
| 253 | (*psidid)->refcount = 0; | 260 | (*psidid)->refcount = 0; |
| 254 | 261 | ||
| @@ -354,7 +361,7 @@ id_to_sid(unsigned long cid, uint sidtype, struct cifs_sid *ssid) | |||
| 354 | * any fields of the node after a reference is put . | 361 | * any fields of the node after a reference is put . |
| 355 | */ | 362 | */ |
| 356 | if (test_bit(SID_ID_MAPPED, &psidid->state)) { | 363 | if (test_bit(SID_ID_MAPPED, &psidid->state)) { |
| 357 | memcpy(ssid, &psidid->sid, sizeof(struct cifs_sid)); | 364 | cifs_copy_sid(ssid, &psidid->sid); |
| 358 | psidid->time = jiffies; /* update ts for accessing */ | 365 | psidid->time = jiffies; /* update ts for accessing */ |
| 359 | goto id_sid_out; | 366 | goto id_sid_out; |
| 360 | } | 367 | } |
| @@ -370,14 +377,14 @@ id_to_sid(unsigned long cid, uint sidtype, struct cifs_sid *ssid) | |||
| 370 | if (IS_ERR(sidkey)) { | 377 | if (IS_ERR(sidkey)) { |
| 371 | rc = -EINVAL; | 378 | rc = -EINVAL; |
| 372 | cFYI(1, "%s: Can't map and id to a SID", __func__); | 379 | cFYI(1, "%s: Can't map and id to a SID", __func__); |
| 380 | } else if (sidkey->datalen < sizeof(struct cifs_sid)) { | ||
| 381 | rc = -EIO; | ||
| 382 | cFYI(1, "%s: Downcall contained malformed key " | ||
| 383 | "(datalen=%hu)", __func__, sidkey->datalen); | ||
| 373 | } else { | 384 | } else { |
| 374 | lsid = (struct cifs_sid *)sidkey->payload.data; | 385 | lsid = (struct cifs_sid *)sidkey->payload.data; |
| 375 | memcpy(&psidid->sid, lsid, | 386 | cifs_copy_sid(&psidid->sid, lsid); |
| 376 | sidkey->datalen < sizeof(struct cifs_sid) ? | 387 | cifs_copy_sid(ssid, &psidid->sid); |
| 377 | sidkey->datalen : sizeof(struct cifs_sid)); | ||
| 378 | memcpy(ssid, &psidid->sid, | ||
| 379 | sidkey->datalen < sizeof(struct cifs_sid) ? | ||
| 380 | sidkey->datalen : sizeof(struct cifs_sid)); | ||
| 381 | set_bit(SID_ID_MAPPED, &psidid->state); | 388 | set_bit(SID_ID_MAPPED, &psidid->state); |
| 382 | key_put(sidkey); | 389 | key_put(sidkey); |
| 383 | kfree(psidid->sidstr); | 390 | kfree(psidid->sidstr); |
| @@ -396,7 +403,7 @@ id_to_sid(unsigned long cid, uint sidtype, struct cifs_sid *ssid) | |||
| 396 | return rc; | 403 | return rc; |
| 397 | } | 404 | } |
| 398 | if (test_bit(SID_ID_MAPPED, &psidid->state)) | 405 | if (test_bit(SID_ID_MAPPED, &psidid->state)) |
| 399 | memcpy(ssid, &psidid->sid, sizeof(struct cifs_sid)); | 406 | cifs_copy_sid(ssid, &psidid->sid); |
| 400 | else | 407 | else |
| 401 | rc = -EINVAL; | 408 | rc = -EINVAL; |
| 402 | } | 409 | } |
| @@ -675,8 +682,6 @@ int compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid) | |||
| 675 | static void copy_sec_desc(const struct cifs_ntsd *pntsd, | 682 | static void copy_sec_desc(const struct cifs_ntsd *pntsd, |
| 676 | struct cifs_ntsd *pnntsd, __u32 sidsoffset) | 683 | struct cifs_ntsd *pnntsd, __u32 sidsoffset) |
| 677 | { | 684 | { |
| 678 | int i; | ||
| 679 | |||
| 680 | struct cifs_sid *owner_sid_ptr, *group_sid_ptr; | 685 | struct cifs_sid *owner_sid_ptr, *group_sid_ptr; |
| 681 | struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr; | 686 | struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr; |
| 682 | 687 | ||
| @@ -692,26 +697,14 @@ static void copy_sec_desc(const struct cifs_ntsd *pntsd, | |||
| 692 | owner_sid_ptr = (struct cifs_sid *)((char *)pntsd + | 697 | owner_sid_ptr = (struct cifs_sid *)((char *)pntsd + |
| 693 | le32_to_cpu(pntsd->osidoffset)); | 698 | le32_to_cpu(pntsd->osidoffset)); |
| 694 | nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset); | 699 | nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset); |
| 695 | 700 | cifs_copy_sid(nowner_sid_ptr, owner_sid_ptr); | |
| 696 | nowner_sid_ptr->revision = owner_sid_ptr->revision; | ||
| 697 | nowner_sid_ptr->num_subauth = owner_sid_ptr->num_subauth; | ||
| 698 | for (i = 0; i < 6; i++) | ||
| 699 | nowner_sid_ptr->authority[i] = owner_sid_ptr->authority[i]; | ||
| 700 | for (i = 0; i < 5; i++) | ||
| 701 | nowner_sid_ptr->sub_auth[i] = owner_sid_ptr->sub_auth[i]; | ||
| 702 | 701 | ||
| 703 | /* copy group sid */ | 702 | /* copy group sid */ |
| 704 | group_sid_ptr = (struct cifs_sid *)((char *)pntsd + | 703 | group_sid_ptr = (struct cifs_sid *)((char *)pntsd + |
| 705 | le32_to_cpu(pntsd->gsidoffset)); | 704 | le32_to_cpu(pntsd->gsidoffset)); |
| 706 | ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset + | 705 | ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset + |
| 707 | sizeof(struct cifs_sid)); | 706 | sizeof(struct cifs_sid)); |
| 708 | 707 | cifs_copy_sid(ngroup_sid_ptr, group_sid_ptr); | |
| 709 | ngroup_sid_ptr->revision = group_sid_ptr->revision; | ||
| 710 | ngroup_sid_ptr->num_subauth = group_sid_ptr->num_subauth; | ||
| 711 | for (i = 0; i < 6; i++) | ||
| 712 | ngroup_sid_ptr->authority[i] = group_sid_ptr->authority[i]; | ||
| 713 | for (i = 0; i < 5; i++) | ||
| 714 | ngroup_sid_ptr->sub_auth[i] = group_sid_ptr->sub_auth[i]; | ||
| 715 | 708 | ||
| 716 | return; | 709 | return; |
| 717 | } | 710 | } |
| @@ -1120,8 +1113,7 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd, | |||
| 1120 | kfree(nowner_sid_ptr); | 1113 | kfree(nowner_sid_ptr); |
| 1121 | return rc; | 1114 | return rc; |
| 1122 | } | 1115 | } |
| 1123 | memcpy(owner_sid_ptr, nowner_sid_ptr, | 1116 | cifs_copy_sid(owner_sid_ptr, nowner_sid_ptr); |
| 1124 | sizeof(struct cifs_sid)); | ||
| 1125 | kfree(nowner_sid_ptr); | 1117 | kfree(nowner_sid_ptr); |
| 1126 | *aclflag = CIFS_ACL_OWNER; | 1118 | *aclflag = CIFS_ACL_OWNER; |
| 1127 | } | 1119 | } |
| @@ -1139,8 +1131,7 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd, | |||
| 1139 | kfree(ngroup_sid_ptr); | 1131 | kfree(ngroup_sid_ptr); |
| 1140 | return rc; | 1132 | return rc; |
| 1141 | } | 1133 | } |
| 1142 | memcpy(group_sid_ptr, ngroup_sid_ptr, | 1134 | cifs_copy_sid(group_sid_ptr, ngroup_sid_ptr); |
| 1143 | sizeof(struct cifs_sid)); | ||
| 1144 | kfree(ngroup_sid_ptr); | 1135 | kfree(ngroup_sid_ptr); |
| 1145 | *aclflag = CIFS_ACL_GROUP; | 1136 | *aclflag = CIFS_ACL_GROUP; |
| 1146 | } | 1137 | } |
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 7c0a81283645..d3671f2acb29 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c | |||
| @@ -398,7 +398,16 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry, | |||
| 398 | * in network traffic in the other paths. | 398 | * in network traffic in the other paths. |
| 399 | */ | 399 | */ |
| 400 | if (!(oflags & O_CREAT)) { | 400 | if (!(oflags & O_CREAT)) { |
| 401 | struct dentry *res = cifs_lookup(inode, direntry, 0); | 401 | struct dentry *res; |
| 402 | |||
| 403 | /* | ||
| 404 | * Check for hashed negative dentry. We have already revalidated | ||
| 405 | * the dentry and it is fine. No need to perform another lookup. | ||
| 406 | */ | ||
| 407 | if (!d_unhashed(direntry)) | ||
| 408 | return -ENOENT; | ||
| 409 | |||
| 410 | res = cifs_lookup(inode, direntry, 0); | ||
| 402 | if (IS_ERR(res)) | 411 | if (IS_ERR(res)) |
| 403 | return PTR_ERR(res); | 412 | return PTR_ERR(res); |
| 404 | 413 | ||
diff --git a/fs/eventpoll.c b/fs/eventpoll.c index da72250ddc1c..cd96649bfe62 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c | |||
| @@ -346,7 +346,7 @@ static inline struct epitem *ep_item_from_epqueue(poll_table *p) | |||
| 346 | /* Tells if the epoll_ctl(2) operation needs an event copy from userspace */ | 346 | /* Tells if the epoll_ctl(2) operation needs an event copy from userspace */ |
| 347 | static inline int ep_op_has_event(int op) | 347 | static inline int ep_op_has_event(int op) |
| 348 | { | 348 | { |
| 349 | return op == EPOLL_CTL_ADD || op == EPOLL_CTL_MOD; | 349 | return op != EPOLL_CTL_DEL; |
| 350 | } | 350 | } |
| 351 | 351 | ||
| 352 | /* Initialize the poll safe wake up structure */ | 352 | /* Initialize the poll safe wake up structure */ |
| @@ -676,34 +676,6 @@ static int ep_remove(struct eventpoll *ep, struct epitem *epi) | |||
| 676 | return 0; | 676 | return 0; |
| 677 | } | 677 | } |
| 678 | 678 | ||
| 679 | /* | ||
| 680 | * Disables a "struct epitem" in the eventpoll set. Returns -EBUSY if the item | ||
| 681 | * had no event flags set, indicating that another thread may be currently | ||
| 682 | * handling that item's events (in the case that EPOLLONESHOT was being | ||
| 683 | * used). Otherwise a zero result indicates that the item has been disabled | ||
| 684 | * from receiving events. A disabled item may be re-enabled via | ||
| 685 | * EPOLL_CTL_MOD. Must be called with "mtx" held. | ||
| 686 | */ | ||
| 687 | static int ep_disable(struct eventpoll *ep, struct epitem *epi) | ||
| 688 | { | ||
| 689 | int result = 0; | ||
| 690 | unsigned long flags; | ||
| 691 | |||
| 692 | spin_lock_irqsave(&ep->lock, flags); | ||
| 693 | if (epi->event.events & ~EP_PRIVATE_BITS) { | ||
| 694 | if (ep_is_linked(&epi->rdllink)) | ||
| 695 | list_del_init(&epi->rdllink); | ||
| 696 | /* Ensure ep_poll_callback will not add epi back onto ready | ||
| 697 | list: */ | ||
| 698 | epi->event.events &= EP_PRIVATE_BITS; | ||
| 699 | } | ||
| 700 | else | ||
| 701 | result = -EBUSY; | ||
| 702 | spin_unlock_irqrestore(&ep->lock, flags); | ||
| 703 | |||
| 704 | return result; | ||
| 705 | } | ||
| 706 | |||
| 707 | static void ep_free(struct eventpoll *ep) | 679 | static void ep_free(struct eventpoll *ep) |
| 708 | { | 680 | { |
| 709 | struct rb_node *rbp; | 681 | struct rb_node *rbp; |
| @@ -1048,6 +1020,8 @@ static void ep_rbtree_insert(struct eventpoll *ep, struct epitem *epi) | |||
| 1048 | rb_insert_color(&epi->rbn, &ep->rbr); | 1020 | rb_insert_color(&epi->rbn, &ep->rbr); |
| 1049 | } | 1021 | } |
| 1050 | 1022 | ||
| 1023 | |||
| 1024 | |||
| 1051 | #define PATH_ARR_SIZE 5 | 1025 | #define PATH_ARR_SIZE 5 |
| 1052 | /* | 1026 | /* |
| 1053 | * These are the number paths of length 1 to 5, that we are allowing to emanate | 1027 | * These are the number paths of length 1 to 5, that we are allowing to emanate |
| @@ -1813,12 +1787,6 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd, | |||
| 1813 | } else | 1787 | } else |
| 1814 | error = -ENOENT; | 1788 | error = -ENOENT; |
| 1815 | break; | 1789 | break; |
| 1816 | case EPOLL_CTL_DISABLE: | ||
| 1817 | if (epi) | ||
| 1818 | error = ep_disable(ep, epi); | ||
| 1819 | else | ||
| 1820 | error = -ENOENT; | ||
| 1821 | break; | ||
| 1822 | } | 1790 | } |
| 1823 | mutex_unlock(&ep->mtx); | 1791 | mutex_unlock(&ep->mtx); |
| 1824 | 1792 | ||
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index 4facdd29a350..3a100e7a62a8 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c | |||
| @@ -725,6 +725,10 @@ repeat_in_this_group: | |||
| 725 | "inode=%lu", ino + 1); | 725 | "inode=%lu", ino + 1); |
| 726 | continue; | 726 | continue; |
| 727 | } | 727 | } |
| 728 | BUFFER_TRACE(inode_bitmap_bh, "get_write_access"); | ||
| 729 | err = ext4_journal_get_write_access(handle, inode_bitmap_bh); | ||
| 730 | if (err) | ||
| 731 | goto fail; | ||
| 728 | ext4_lock_group(sb, group); | 732 | ext4_lock_group(sb, group); |
| 729 | ret2 = ext4_test_and_set_bit(ino, inode_bitmap_bh->b_data); | 733 | ret2 = ext4_test_and_set_bit(ino, inode_bitmap_bh->b_data); |
| 730 | ext4_unlock_group(sb, group); | 734 | ext4_unlock_group(sb, group); |
| @@ -738,6 +742,11 @@ repeat_in_this_group: | |||
| 738 | goto out; | 742 | goto out; |
| 739 | 743 | ||
| 740 | got: | 744 | got: |
| 745 | BUFFER_TRACE(inode_bitmap_bh, "call ext4_handle_dirty_metadata"); | ||
| 746 | err = ext4_handle_dirty_metadata(handle, NULL, inode_bitmap_bh); | ||
| 747 | if (err) | ||
| 748 | goto fail; | ||
| 749 | |||
| 741 | /* We may have to initialize the block bitmap if it isn't already */ | 750 | /* We may have to initialize the block bitmap if it isn't already */ |
| 742 | if (ext4_has_group_desc_csum(sb) && | 751 | if (ext4_has_group_desc_csum(sb) && |
| 743 | gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) { | 752 | gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) { |
| @@ -771,11 +780,6 @@ got: | |||
| 771 | goto fail; | 780 | goto fail; |
| 772 | } | 781 | } |
| 773 | 782 | ||
| 774 | BUFFER_TRACE(inode_bitmap_bh, "get_write_access"); | ||
| 775 | err = ext4_journal_get_write_access(handle, inode_bitmap_bh); | ||
| 776 | if (err) | ||
| 777 | goto fail; | ||
| 778 | |||
| 779 | BUFFER_TRACE(group_desc_bh, "get_write_access"); | 783 | BUFFER_TRACE(group_desc_bh, "get_write_access"); |
| 780 | err = ext4_journal_get_write_access(handle, group_desc_bh); | 784 | err = ext4_journal_get_write_access(handle, group_desc_bh); |
| 781 | if (err) | 785 | if (err) |
| @@ -823,11 +827,6 @@ got: | |||
| 823 | } | 827 | } |
| 824 | ext4_unlock_group(sb, group); | 828 | ext4_unlock_group(sb, group); |
| 825 | 829 | ||
| 826 | BUFFER_TRACE(inode_bitmap_bh, "call ext4_handle_dirty_metadata"); | ||
| 827 | err = ext4_handle_dirty_metadata(handle, NULL, inode_bitmap_bh); | ||
| 828 | if (err) | ||
| 829 | goto fail; | ||
| 830 | |||
| 831 | BUFFER_TRACE(group_desc_bh, "call ext4_handle_dirty_metadata"); | 830 | BUFFER_TRACE(group_desc_bh, "call ext4_handle_dirty_metadata"); |
| 832 | err = ext4_handle_dirty_metadata(handle, NULL, group_desc_bh); | 831 | err = ext4_handle_dirty_metadata(handle, NULL, group_desc_bh); |
| 833 | if (err) | 832 | if (err) |
| @@ -900,7 +900,7 @@ int replace_fd(unsigned fd, struct file *file, unsigned flags) | |||
| 900 | return __close_fd(files, fd); | 900 | return __close_fd(files, fd); |
| 901 | 901 | ||
| 902 | if (fd >= rlimit(RLIMIT_NOFILE)) | 902 | if (fd >= rlimit(RLIMIT_NOFILE)) |
| 903 | return -EMFILE; | 903 | return -EBADF; |
| 904 | 904 | ||
| 905 | spin_lock(&files->file_lock); | 905 | spin_lock(&files->file_lock); |
| 906 | err = expand_files(files, fd); | 906 | err = expand_files(files, fd); |
| @@ -926,7 +926,7 @@ SYSCALL_DEFINE3(dup3, unsigned int, oldfd, unsigned int, newfd, int, flags) | |||
| 926 | return -EINVAL; | 926 | return -EINVAL; |
| 927 | 927 | ||
| 928 | if (newfd >= rlimit(RLIMIT_NOFILE)) | 928 | if (newfd >= rlimit(RLIMIT_NOFILE)) |
| 929 | return -EMFILE; | 929 | return -EBADF; |
| 930 | 930 | ||
| 931 | spin_lock(&files->file_lock); | 931 | spin_lock(&files->file_lock); |
| 932 | err = expand_files(files, newfd); | 932 | err = expand_files(files, newfd); |
diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c index 0def0504afc1..e056b4ce4877 100644 --- a/fs/gfs2/file.c +++ b/fs/gfs2/file.c | |||
| @@ -516,15 +516,13 @@ static int gfs2_mmap(struct file *file, struct vm_area_struct *vma) | |||
| 516 | struct gfs2_holder i_gh; | 516 | struct gfs2_holder i_gh; |
| 517 | int error; | 517 | int error; |
| 518 | 518 | ||
| 519 | gfs2_holder_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh); | 519 | error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, |
| 520 | error = gfs2_glock_nq(&i_gh); | 520 | &i_gh); |
| 521 | if (error == 0) { | ||
| 522 | file_accessed(file); | ||
| 523 | gfs2_glock_dq(&i_gh); | ||
| 524 | } | ||
| 525 | gfs2_holder_uninit(&i_gh); | ||
| 526 | if (error) | 521 | if (error) |
| 527 | return error; | 522 | return error; |
| 523 | /* grab lock to update inode */ | ||
| 524 | gfs2_glock_dq_uninit(&i_gh); | ||
| 525 | file_accessed(file); | ||
| 528 | } | 526 | } |
| 529 | vma->vm_ops = &gfs2_vm_ops; | 527 | vma->vm_ops = &gfs2_vm_ops; |
| 530 | 528 | ||
| @@ -677,10 +675,8 @@ static ssize_t gfs2_file_aio_write(struct kiocb *iocb, const struct iovec *iov, | |||
| 677 | size_t writesize = iov_length(iov, nr_segs); | 675 | size_t writesize = iov_length(iov, nr_segs); |
| 678 | struct dentry *dentry = file->f_dentry; | 676 | struct dentry *dentry = file->f_dentry; |
| 679 | struct gfs2_inode *ip = GFS2_I(dentry->d_inode); | 677 | struct gfs2_inode *ip = GFS2_I(dentry->d_inode); |
| 680 | struct gfs2_sbd *sdp; | ||
| 681 | int ret; | 678 | int ret; |
| 682 | 679 | ||
| 683 | sdp = GFS2_SB(file->f_mapping->host); | ||
| 684 | ret = gfs2_rs_alloc(ip); | 680 | ret = gfs2_rs_alloc(ip); |
| 685 | if (ret) | 681 | if (ret) |
| 686 | return ret; | 682 | return ret; |
diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index 8ff95a2d54ee..9ceccb1595a3 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c | |||
| @@ -393,12 +393,10 @@ static void buf_lo_add(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd) | |||
| 393 | struct gfs2_meta_header *mh; | 393 | struct gfs2_meta_header *mh; |
| 394 | struct gfs2_trans *tr; | 394 | struct gfs2_trans *tr; |
| 395 | 395 | ||
| 396 | lock_buffer(bd->bd_bh); | ||
| 397 | gfs2_log_lock(sdp); | ||
| 398 | tr = current->journal_info; | 396 | tr = current->journal_info; |
| 399 | tr->tr_touched = 1; | 397 | tr->tr_touched = 1; |
| 400 | if (!list_empty(&bd->bd_list)) | 398 | if (!list_empty(&bd->bd_list)) |
| 401 | goto out; | 399 | return; |
| 402 | set_bit(GLF_LFLUSH, &bd->bd_gl->gl_flags); | 400 | set_bit(GLF_LFLUSH, &bd->bd_gl->gl_flags); |
| 403 | set_bit(GLF_DIRTY, &bd->bd_gl->gl_flags); | 401 | set_bit(GLF_DIRTY, &bd->bd_gl->gl_flags); |
| 404 | mh = (struct gfs2_meta_header *)bd->bd_bh->b_data; | 402 | mh = (struct gfs2_meta_header *)bd->bd_bh->b_data; |
| @@ -414,9 +412,6 @@ static void buf_lo_add(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd) | |||
| 414 | sdp->sd_log_num_buf++; | 412 | sdp->sd_log_num_buf++; |
| 415 | list_add(&bd->bd_list, &sdp->sd_log_le_buf); | 413 | list_add(&bd->bd_list, &sdp->sd_log_le_buf); |
| 416 | tr->tr_num_buf_new++; | 414 | tr->tr_num_buf_new++; |
| 417 | out: | ||
| 418 | gfs2_log_unlock(sdp); | ||
| 419 | unlock_buffer(bd->bd_bh); | ||
| 420 | } | 415 | } |
| 421 | 416 | ||
| 422 | static void gfs2_check_magic(struct buffer_head *bh) | 417 | static void gfs2_check_magic(struct buffer_head *bh) |
| @@ -621,7 +616,6 @@ static void revoke_lo_add(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd) | |||
| 621 | 616 | ||
| 622 | static void revoke_lo_before_commit(struct gfs2_sbd *sdp) | 617 | static void revoke_lo_before_commit(struct gfs2_sbd *sdp) |
| 623 | { | 618 | { |
| 624 | struct gfs2_log_descriptor *ld; | ||
| 625 | struct gfs2_meta_header *mh; | 619 | struct gfs2_meta_header *mh; |
| 626 | unsigned int offset; | 620 | unsigned int offset; |
| 627 | struct list_head *head = &sdp->sd_log_le_revoke; | 621 | struct list_head *head = &sdp->sd_log_le_revoke; |
| @@ -634,7 +628,6 @@ static void revoke_lo_before_commit(struct gfs2_sbd *sdp) | |||
| 634 | 628 | ||
| 635 | length = gfs2_struct2blk(sdp, sdp->sd_log_num_revoke, sizeof(u64)); | 629 | length = gfs2_struct2blk(sdp, sdp->sd_log_num_revoke, sizeof(u64)); |
| 636 | page = gfs2_get_log_desc(sdp, GFS2_LOG_DESC_REVOKE, length, sdp->sd_log_num_revoke); | 630 | page = gfs2_get_log_desc(sdp, GFS2_LOG_DESC_REVOKE, length, sdp->sd_log_num_revoke); |
| 637 | ld = page_address(page); | ||
| 638 | offset = sizeof(struct gfs2_log_descriptor); | 631 | offset = sizeof(struct gfs2_log_descriptor); |
| 639 | 632 | ||
| 640 | list_for_each_entry(bd, head, bd_list) { | 633 | list_for_each_entry(bd, head, bd_list) { |
| @@ -777,12 +770,10 @@ static void databuf_lo_add(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd) | |||
| 777 | struct address_space *mapping = bd->bd_bh->b_page->mapping; | 770 | struct address_space *mapping = bd->bd_bh->b_page->mapping; |
| 778 | struct gfs2_inode *ip = GFS2_I(mapping->host); | 771 | struct gfs2_inode *ip = GFS2_I(mapping->host); |
| 779 | 772 | ||
| 780 | lock_buffer(bd->bd_bh); | ||
| 781 | gfs2_log_lock(sdp); | ||
| 782 | if (tr) | 773 | if (tr) |
| 783 | tr->tr_touched = 1; | 774 | tr->tr_touched = 1; |
| 784 | if (!list_empty(&bd->bd_list)) | 775 | if (!list_empty(&bd->bd_list)) |
| 785 | goto out; | 776 | return; |
| 786 | set_bit(GLF_LFLUSH, &bd->bd_gl->gl_flags); | 777 | set_bit(GLF_LFLUSH, &bd->bd_gl->gl_flags); |
| 787 | set_bit(GLF_DIRTY, &bd->bd_gl->gl_flags); | 778 | set_bit(GLF_DIRTY, &bd->bd_gl->gl_flags); |
| 788 | if (gfs2_is_jdata(ip)) { | 779 | if (gfs2_is_jdata(ip)) { |
| @@ -793,9 +784,6 @@ static void databuf_lo_add(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd) | |||
| 793 | } else { | 784 | } else { |
| 794 | list_add_tail(&bd->bd_list, &sdp->sd_log_le_ordered); | 785 | list_add_tail(&bd->bd_list, &sdp->sd_log_le_ordered); |
| 795 | } | 786 | } |
| 796 | out: | ||
| 797 | gfs2_log_unlock(sdp); | ||
| 798 | unlock_buffer(bd->bd_bh); | ||
| 799 | } | 787 | } |
| 800 | 788 | ||
| 801 | /** | 789 | /** |
diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index 40c4b0d42fa8..c5af8e18f27a 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c | |||
| @@ -497,8 +497,11 @@ int gfs2_quota_hold(struct gfs2_inode *ip, u32 uid, u32 gid) | |||
| 497 | struct gfs2_quota_data **qd; | 497 | struct gfs2_quota_data **qd; |
| 498 | int error; | 498 | int error; |
| 499 | 499 | ||
| 500 | if (ip->i_res == NULL) | 500 | if (ip->i_res == NULL) { |
| 501 | gfs2_rs_alloc(ip); | 501 | error = gfs2_rs_alloc(ip); |
| 502 | if (error) | ||
| 503 | return error; | ||
| 504 | } | ||
| 502 | 505 | ||
| 503 | qd = ip->i_res->rs_qa_qd; | 506 | qd = ip->i_res->rs_qa_qd; |
| 504 | 507 | ||
diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 3cc402ce6fea..38fe18f2f055 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c | |||
| @@ -553,7 +553,6 @@ void gfs2_free_clones(struct gfs2_rgrpd *rgd) | |||
| 553 | */ | 553 | */ |
| 554 | int gfs2_rs_alloc(struct gfs2_inode *ip) | 554 | int gfs2_rs_alloc(struct gfs2_inode *ip) |
| 555 | { | 555 | { |
| 556 | int error = 0; | ||
| 557 | struct gfs2_blkreserv *res; | 556 | struct gfs2_blkreserv *res; |
| 558 | 557 | ||
| 559 | if (ip->i_res) | 558 | if (ip->i_res) |
| @@ -561,7 +560,7 @@ int gfs2_rs_alloc(struct gfs2_inode *ip) | |||
| 561 | 560 | ||
| 562 | res = kmem_cache_zalloc(gfs2_rsrv_cachep, GFP_NOFS); | 561 | res = kmem_cache_zalloc(gfs2_rsrv_cachep, GFP_NOFS); |
| 563 | if (!res) | 562 | if (!res) |
| 564 | error = -ENOMEM; | 563 | return -ENOMEM; |
| 565 | 564 | ||
| 566 | RB_CLEAR_NODE(&res->rs_node); | 565 | RB_CLEAR_NODE(&res->rs_node); |
| 567 | 566 | ||
| @@ -571,7 +570,7 @@ int gfs2_rs_alloc(struct gfs2_inode *ip) | |||
| 571 | else | 570 | else |
| 572 | ip->i_res = res; | 571 | ip->i_res = res; |
| 573 | up_write(&ip->i_rw_mutex); | 572 | up_write(&ip->i_rw_mutex); |
| 574 | return error; | 573 | return 0; |
| 575 | } | 574 | } |
| 576 | 575 | ||
| 577 | static void dump_rs(struct seq_file *seq, const struct gfs2_blkreserv *rs) | 576 | static void dump_rs(struct seq_file *seq, const struct gfs2_blkreserv *rs) |
| @@ -1263,7 +1262,9 @@ int gfs2_fitrim(struct file *filp, void __user *argp) | |||
| 1263 | int ret = 0; | 1262 | int ret = 0; |
| 1264 | u64 amt; | 1263 | u64 amt; |
| 1265 | u64 trimmed = 0; | 1264 | u64 trimmed = 0; |
| 1265 | u64 start, end, minlen; | ||
| 1266 | unsigned int x; | 1266 | unsigned int x; |
| 1267 | unsigned bs_shift = sdp->sd_sb.sb_bsize_shift; | ||
| 1267 | 1268 | ||
| 1268 | if (!capable(CAP_SYS_ADMIN)) | 1269 | if (!capable(CAP_SYS_ADMIN)) |
| 1269 | return -EPERM; | 1270 | return -EPERM; |
| @@ -1271,19 +1272,25 @@ int gfs2_fitrim(struct file *filp, void __user *argp) | |||
| 1271 | if (!blk_queue_discard(q)) | 1272 | if (!blk_queue_discard(q)) |
| 1272 | return -EOPNOTSUPP; | 1273 | return -EOPNOTSUPP; |
| 1273 | 1274 | ||
| 1274 | if (argp == NULL) { | 1275 | if (copy_from_user(&r, argp, sizeof(r))) |
| 1275 | r.start = 0; | ||
| 1276 | r.len = ULLONG_MAX; | ||
| 1277 | r.minlen = 0; | ||
| 1278 | } else if (copy_from_user(&r, argp, sizeof(r))) | ||
| 1279 | return -EFAULT; | 1276 | return -EFAULT; |
| 1280 | 1277 | ||
| 1281 | ret = gfs2_rindex_update(sdp); | 1278 | ret = gfs2_rindex_update(sdp); |
| 1282 | if (ret) | 1279 | if (ret) |
| 1283 | return ret; | 1280 | return ret; |
| 1284 | 1281 | ||
| 1285 | rgd = gfs2_blk2rgrpd(sdp, r.start, 0); | 1282 | start = r.start >> bs_shift; |
| 1286 | rgd_end = gfs2_blk2rgrpd(sdp, r.start + r.len, 0); | 1283 | end = start + (r.len >> bs_shift); |
| 1284 | minlen = max_t(u64, r.minlen, | ||
| 1285 | q->limits.discard_granularity) >> bs_shift; | ||
| 1286 | |||
| 1287 | rgd = gfs2_blk2rgrpd(sdp, start, 0); | ||
| 1288 | rgd_end = gfs2_blk2rgrpd(sdp, end - 1, 0); | ||
| 1289 | |||
| 1290 | if (end <= start || | ||
| 1291 | minlen > sdp->sd_max_rg_data || | ||
| 1292 | start > rgd_end->rd_data0 + rgd_end->rd_data) | ||
| 1293 | return -EINVAL; | ||
| 1287 | 1294 | ||
| 1288 | while (1) { | 1295 | while (1) { |
| 1289 | 1296 | ||
| @@ -1295,7 +1302,9 @@ int gfs2_fitrim(struct file *filp, void __user *argp) | |||
| 1295 | /* Trim each bitmap in the rgrp */ | 1302 | /* Trim each bitmap in the rgrp */ |
| 1296 | for (x = 0; x < rgd->rd_length; x++) { | 1303 | for (x = 0; x < rgd->rd_length; x++) { |
| 1297 | struct gfs2_bitmap *bi = rgd->rd_bits + x; | 1304 | struct gfs2_bitmap *bi = rgd->rd_bits + x; |
| 1298 | ret = gfs2_rgrp_send_discards(sdp, rgd->rd_data0, NULL, bi, r.minlen, &amt); | 1305 | ret = gfs2_rgrp_send_discards(sdp, |
| 1306 | rgd->rd_data0, NULL, bi, minlen, | ||
| 1307 | &amt); | ||
| 1299 | if (ret) { | 1308 | if (ret) { |
| 1300 | gfs2_glock_dq_uninit(&gh); | 1309 | gfs2_glock_dq_uninit(&gh); |
| 1301 | goto out; | 1310 | goto out; |
| @@ -1324,7 +1333,7 @@ int gfs2_fitrim(struct file *filp, void __user *argp) | |||
| 1324 | 1333 | ||
| 1325 | out: | 1334 | out: |
| 1326 | r.len = trimmed << 9; | 1335 | r.len = trimmed << 9; |
| 1327 | if (argp && copy_to_user(argp, &r, sizeof(r))) | 1336 | if (copy_to_user(argp, &r, sizeof(r))) |
| 1328 | return -EFAULT; | 1337 | return -EFAULT; |
| 1329 | 1338 | ||
| 1330 | return ret; | 1339 | return ret; |
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index bc737261f234..d6488674d916 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c | |||
| @@ -810,7 +810,8 @@ static void gfs2_dirty_inode(struct inode *inode, int flags) | |||
| 810 | return; | 810 | return; |
| 811 | } | 811 | } |
| 812 | need_unlock = 1; | 812 | need_unlock = 1; |
| 813 | } | 813 | } else if (WARN_ON_ONCE(ip->i_gl->gl_state != LM_ST_EXCLUSIVE)) |
| 814 | return; | ||
| 814 | 815 | ||
| 815 | if (current->journal_info == NULL) { | 816 | if (current->journal_info == NULL) { |
| 816 | ret = gfs2_trans_begin(sdp, RES_DINODE, 0); | 817 | ret = gfs2_trans_begin(sdp, RES_DINODE, 0); |
diff --git a/fs/gfs2/trans.c b/fs/gfs2/trans.c index adbd27875ef9..413627072f36 100644 --- a/fs/gfs2/trans.c +++ b/fs/gfs2/trans.c | |||
| @@ -155,14 +155,22 @@ void gfs2_trans_add_bh(struct gfs2_glock *gl, struct buffer_head *bh, int meta) | |||
| 155 | struct gfs2_sbd *sdp = gl->gl_sbd; | 155 | struct gfs2_sbd *sdp = gl->gl_sbd; |
| 156 | struct gfs2_bufdata *bd; | 156 | struct gfs2_bufdata *bd; |
| 157 | 157 | ||
| 158 | lock_buffer(bh); | ||
| 159 | gfs2_log_lock(sdp); | ||
| 158 | bd = bh->b_private; | 160 | bd = bh->b_private; |
| 159 | if (bd) | 161 | if (bd) |
| 160 | gfs2_assert(sdp, bd->bd_gl == gl); | 162 | gfs2_assert(sdp, bd->bd_gl == gl); |
| 161 | else { | 163 | else { |
| 164 | gfs2_log_unlock(sdp); | ||
| 165 | unlock_buffer(bh); | ||
| 162 | gfs2_attach_bufdata(gl, bh, meta); | 166 | gfs2_attach_bufdata(gl, bh, meta); |
| 163 | bd = bh->b_private; | 167 | bd = bh->b_private; |
| 168 | lock_buffer(bh); | ||
| 169 | gfs2_log_lock(sdp); | ||
| 164 | } | 170 | } |
| 165 | lops_add(sdp, bd); | 171 | lops_add(sdp, bd); |
| 172 | gfs2_log_unlock(sdp); | ||
| 173 | unlock_buffer(bh); | ||
| 166 | } | 174 | } |
| 167 | 175 | ||
| 168 | void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd) | 176 | void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd) |
diff --git a/fs/nfs/dns_resolve.c b/fs/nfs/dns_resolve.c index 31c26c4dcc23..ca4b11ec87a2 100644 --- a/fs/nfs/dns_resolve.c +++ b/fs/nfs/dns_resolve.c | |||
| @@ -217,7 +217,7 @@ static int nfs_dns_parse(struct cache_detail *cd, char *buf, int buflen) | |||
| 217 | { | 217 | { |
| 218 | char buf1[NFS_DNS_HOSTNAME_MAXLEN+1]; | 218 | char buf1[NFS_DNS_HOSTNAME_MAXLEN+1]; |
| 219 | struct nfs_dns_ent key, *item; | 219 | struct nfs_dns_ent key, *item; |
| 220 | unsigned long ttl; | 220 | unsigned int ttl; |
| 221 | ssize_t len; | 221 | ssize_t len; |
| 222 | int ret = -EINVAL; | 222 | int ret = -EINVAL; |
| 223 | 223 | ||
| @@ -240,7 +240,8 @@ static int nfs_dns_parse(struct cache_detail *cd, char *buf, int buflen) | |||
| 240 | key.namelen = len; | 240 | key.namelen = len; |
| 241 | memset(&key.h, 0, sizeof(key.h)); | 241 | memset(&key.h, 0, sizeof(key.h)); |
| 242 | 242 | ||
| 243 | ttl = get_expiry(&buf); | 243 | if (get_uint(&buf, &ttl) < 0) |
| 244 | goto out; | ||
| 244 | if (ttl == 0) | 245 | if (ttl == 0) |
| 245 | goto out; | 246 | goto out; |
| 246 | key.h.expiry_time = ttl + seconds_since_boot(); | 247 | key.h.expiry_time = ttl + seconds_since_boot(); |
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 5c7325c5c5e6..6fa01aea2488 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
| @@ -685,7 +685,10 @@ static void __put_nfs_open_context(struct nfs_open_context *ctx, int is_sync) | |||
| 685 | if (ctx->cred != NULL) | 685 | if (ctx->cred != NULL) |
| 686 | put_rpccred(ctx->cred); | 686 | put_rpccred(ctx->cred); |
| 687 | dput(ctx->dentry); | 687 | dput(ctx->dentry); |
| 688 | nfs_sb_deactive(sb); | 688 | if (is_sync) |
| 689 | nfs_sb_deactive(sb); | ||
| 690 | else | ||
| 691 | nfs_sb_deactive_async(sb); | ||
| 689 | kfree(ctx->mdsthreshold); | 692 | kfree(ctx->mdsthreshold); |
| 690 | kfree(ctx); | 693 | kfree(ctx); |
| 691 | } | 694 | } |
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 59b133c5d652..05521cadac2e 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
| @@ -351,10 +351,12 @@ extern int __init register_nfs_fs(void); | |||
| 351 | extern void __exit unregister_nfs_fs(void); | 351 | extern void __exit unregister_nfs_fs(void); |
| 352 | extern void nfs_sb_active(struct super_block *sb); | 352 | extern void nfs_sb_active(struct super_block *sb); |
| 353 | extern void nfs_sb_deactive(struct super_block *sb); | 353 | extern void nfs_sb_deactive(struct super_block *sb); |
| 354 | extern void nfs_sb_deactive_async(struct super_block *sb); | ||
| 354 | 355 | ||
| 355 | /* namespace.c */ | 356 | /* namespace.c */ |
| 357 | #define NFS_PATH_CANONICAL 1 | ||
| 356 | extern char *nfs_path(char **p, struct dentry *dentry, | 358 | extern char *nfs_path(char **p, struct dentry *dentry, |
| 357 | char *buffer, ssize_t buflen); | 359 | char *buffer, ssize_t buflen, unsigned flags); |
| 358 | extern struct vfsmount *nfs_d_automount(struct path *path); | 360 | extern struct vfsmount *nfs_d_automount(struct path *path); |
| 359 | struct vfsmount *nfs_submount(struct nfs_server *, struct dentry *, | 361 | struct vfsmount *nfs_submount(struct nfs_server *, struct dentry *, |
| 360 | struct nfs_fh *, struct nfs_fattr *); | 362 | struct nfs_fh *, struct nfs_fattr *); |
| @@ -498,7 +500,7 @@ static inline char *nfs_devname(struct dentry *dentry, | |||
| 498 | char *buffer, ssize_t buflen) | 500 | char *buffer, ssize_t buflen) |
| 499 | { | 501 | { |
| 500 | char *dummy; | 502 | char *dummy; |
| 501 | return nfs_path(&dummy, dentry, buffer, buflen); | 503 | return nfs_path(&dummy, dentry, buffer, buflen, NFS_PATH_CANONICAL); |
| 502 | } | 504 | } |
| 503 | 505 | ||
| 504 | /* | 506 | /* |
diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c index 8e65c7f1f87c..015f71f8f62c 100644 --- a/fs/nfs/mount_clnt.c +++ b/fs/nfs/mount_clnt.c | |||
| @@ -181,7 +181,7 @@ int nfs_mount(struct nfs_mount_request *info) | |||
| 181 | else | 181 | else |
| 182 | msg.rpc_proc = &mnt_clnt->cl_procinfo[MOUNTPROC_MNT]; | 182 | msg.rpc_proc = &mnt_clnt->cl_procinfo[MOUNTPROC_MNT]; |
| 183 | 183 | ||
| 184 | status = rpc_call_sync(mnt_clnt, &msg, 0); | 184 | status = rpc_call_sync(mnt_clnt, &msg, RPC_TASK_SOFT|RPC_TASK_TIMEOUT); |
| 185 | rpc_shutdown_client(mnt_clnt); | 185 | rpc_shutdown_client(mnt_clnt); |
| 186 | 186 | ||
| 187 | if (status < 0) | 187 | if (status < 0) |
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c index 655925373b91..dd057bc6b65b 100644 --- a/fs/nfs/namespace.c +++ b/fs/nfs/namespace.c | |||
| @@ -33,6 +33,7 @@ int nfs_mountpoint_expiry_timeout = 500 * HZ; | |||
| 33 | * @dentry - pointer to dentry | 33 | * @dentry - pointer to dentry |
| 34 | * @buffer - result buffer | 34 | * @buffer - result buffer |
| 35 | * @buflen - length of buffer | 35 | * @buflen - length of buffer |
| 36 | * @flags - options (see below) | ||
| 36 | * | 37 | * |
| 37 | * Helper function for constructing the server pathname | 38 | * Helper function for constructing the server pathname |
| 38 | * by arbitrary hashed dentry. | 39 | * by arbitrary hashed dentry. |
| @@ -40,8 +41,14 @@ int nfs_mountpoint_expiry_timeout = 500 * HZ; | |||
| 40 | * This is mainly for use in figuring out the path on the | 41 | * This is mainly for use in figuring out the path on the |
| 41 | * server side when automounting on top of an existing partition | 42 | * server side when automounting on top of an existing partition |
| 42 | * and in generating /proc/mounts and friends. | 43 | * and in generating /proc/mounts and friends. |
| 44 | * | ||
| 45 | * Supported flags: | ||
| 46 | * NFS_PATH_CANONICAL: ensure there is exactly one slash after | ||
| 47 | * the original device (export) name | ||
| 48 | * (if unset, the original name is returned verbatim) | ||
| 43 | */ | 49 | */ |
| 44 | char *nfs_path(char **p, struct dentry *dentry, char *buffer, ssize_t buflen) | 50 | char *nfs_path(char **p, struct dentry *dentry, char *buffer, ssize_t buflen, |
| 51 | unsigned flags) | ||
| 45 | { | 52 | { |
| 46 | char *end; | 53 | char *end; |
| 47 | int namelen; | 54 | int namelen; |
| @@ -74,7 +81,7 @@ rename_retry: | |||
| 74 | rcu_read_unlock(); | 81 | rcu_read_unlock(); |
| 75 | goto rename_retry; | 82 | goto rename_retry; |
| 76 | } | 83 | } |
| 77 | if (*end != '/') { | 84 | if ((flags & NFS_PATH_CANONICAL) && *end != '/') { |
| 78 | if (--buflen < 0) { | 85 | if (--buflen < 0) { |
| 79 | spin_unlock(&dentry->d_lock); | 86 | spin_unlock(&dentry->d_lock); |
| 80 | rcu_read_unlock(); | 87 | rcu_read_unlock(); |
| @@ -91,9 +98,11 @@ rename_retry: | |||
| 91 | return end; | 98 | return end; |
| 92 | } | 99 | } |
| 93 | namelen = strlen(base); | 100 | namelen = strlen(base); |
| 94 | /* Strip off excess slashes in base string */ | 101 | if (flags & NFS_PATH_CANONICAL) { |
| 95 | while (namelen > 0 && base[namelen - 1] == '/') | 102 | /* Strip off excess slashes in base string */ |
| 96 | namelen--; | 103 | while (namelen > 0 && base[namelen - 1] == '/') |
| 104 | namelen--; | ||
| 105 | } | ||
| 97 | buflen -= namelen; | 106 | buflen -= namelen; |
| 98 | if (buflen < 0) { | 107 | if (buflen < 0) { |
| 99 | spin_unlock(&dentry->d_lock); | 108 | spin_unlock(&dentry->d_lock); |
diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c index 79fbb61ce202..1e09eb78543b 100644 --- a/fs/nfs/nfs4namespace.c +++ b/fs/nfs/nfs4namespace.c | |||
| @@ -81,7 +81,8 @@ static char *nfs_path_component(const char *nfspath, const char *end) | |||
| 81 | static char *nfs4_path(struct dentry *dentry, char *buffer, ssize_t buflen) | 81 | static char *nfs4_path(struct dentry *dentry, char *buffer, ssize_t buflen) |
| 82 | { | 82 | { |
| 83 | char *limit; | 83 | char *limit; |
| 84 | char *path = nfs_path(&limit, dentry, buffer, buflen); | 84 | char *path = nfs_path(&limit, dentry, buffer, buflen, |
| 85 | NFS_PATH_CANONICAL); | ||
| 85 | if (!IS_ERR(path)) { | 86 | if (!IS_ERR(path)) { |
| 86 | char *path_component = nfs_path_component(path, limit); | 87 | char *path_component = nfs_path_component(path, limit); |
| 87 | if (path_component) | 88 | if (path_component) |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 68b21d81b7ac..5eec4429970c 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
| @@ -339,8 +339,7 @@ static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struc | |||
| 339 | dprintk("%s ERROR: %d Reset session\n", __func__, | 339 | dprintk("%s ERROR: %d Reset session\n", __func__, |
| 340 | errorcode); | 340 | errorcode); |
| 341 | nfs4_schedule_session_recovery(clp->cl_session, errorcode); | 341 | nfs4_schedule_session_recovery(clp->cl_session, errorcode); |
| 342 | exception->retry = 1; | 342 | goto wait_on_recovery; |
| 343 | break; | ||
| 344 | #endif /* defined(CONFIG_NFS_V4_1) */ | 343 | #endif /* defined(CONFIG_NFS_V4_1) */ |
| 345 | case -NFS4ERR_FILE_OPEN: | 344 | case -NFS4ERR_FILE_OPEN: |
| 346 | if (exception->timeout > HZ) { | 345 | if (exception->timeout > HZ) { |
| @@ -1572,9 +1571,11 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata) | |||
| 1572 | data->timestamp = jiffies; | 1571 | data->timestamp = jiffies; |
| 1573 | if (nfs4_setup_sequence(data->o_arg.server, | 1572 | if (nfs4_setup_sequence(data->o_arg.server, |
| 1574 | &data->o_arg.seq_args, | 1573 | &data->o_arg.seq_args, |
| 1575 | &data->o_res.seq_res, task)) | 1574 | &data->o_res.seq_res, |
| 1576 | return; | 1575 | task) != 0) |
| 1577 | rpc_call_start(task); | 1576 | nfs_release_seqid(data->o_arg.seqid); |
| 1577 | else | ||
| 1578 | rpc_call_start(task); | ||
| 1578 | return; | 1579 | return; |
| 1579 | unlock_no_action: | 1580 | unlock_no_action: |
| 1580 | rcu_read_unlock(); | 1581 | rcu_read_unlock(); |
| @@ -1748,7 +1749,7 @@ static int nfs4_opendata_access(struct rpc_cred *cred, | |||
| 1748 | 1749 | ||
| 1749 | /* even though OPEN succeeded, access is denied. Close the file */ | 1750 | /* even though OPEN succeeded, access is denied. Close the file */ |
| 1750 | nfs4_close_state(state, fmode); | 1751 | nfs4_close_state(state, fmode); |
| 1751 | return -NFS4ERR_ACCESS; | 1752 | return -EACCES; |
| 1752 | } | 1753 | } |
| 1753 | 1754 | ||
| 1754 | /* | 1755 | /* |
| @@ -2196,7 +2197,7 @@ static void nfs4_free_closedata(void *data) | |||
| 2196 | nfs4_put_open_state(calldata->state); | 2197 | nfs4_put_open_state(calldata->state); |
| 2197 | nfs_free_seqid(calldata->arg.seqid); | 2198 | nfs_free_seqid(calldata->arg.seqid); |
| 2198 | nfs4_put_state_owner(sp); | 2199 | nfs4_put_state_owner(sp); |
| 2199 | nfs_sb_deactive(sb); | 2200 | nfs_sb_deactive_async(sb); |
| 2200 | kfree(calldata); | 2201 | kfree(calldata); |
| 2201 | } | 2202 | } |
| 2202 | 2203 | ||
| @@ -2296,9 +2297,10 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) | |||
| 2296 | if (nfs4_setup_sequence(NFS_SERVER(inode), | 2297 | if (nfs4_setup_sequence(NFS_SERVER(inode), |
| 2297 | &calldata->arg.seq_args, | 2298 | &calldata->arg.seq_args, |
| 2298 | &calldata->res.seq_res, | 2299 | &calldata->res.seq_res, |
| 2299 | task)) | 2300 | task) != 0) |
| 2300 | goto out; | 2301 | nfs_release_seqid(calldata->arg.seqid); |
| 2301 | rpc_call_start(task); | 2302 | else |
| 2303 | rpc_call_start(task); | ||
| 2302 | out: | 2304 | out: |
| 2303 | dprintk("%s: done!\n", __func__); | 2305 | dprintk("%s: done!\n", __func__); |
| 2304 | } | 2306 | } |
| @@ -4529,6 +4531,7 @@ static void nfs4_locku_done(struct rpc_task *task, void *data) | |||
| 4529 | if (nfs4_async_handle_error(task, calldata->server, NULL) == -EAGAIN) | 4531 | if (nfs4_async_handle_error(task, calldata->server, NULL) == -EAGAIN) |
| 4530 | rpc_restart_call_prepare(task); | 4532 | rpc_restart_call_prepare(task); |
| 4531 | } | 4533 | } |
| 4534 | nfs_release_seqid(calldata->arg.seqid); | ||
| 4532 | } | 4535 | } |
| 4533 | 4536 | ||
| 4534 | static void nfs4_locku_prepare(struct rpc_task *task, void *data) | 4537 | static void nfs4_locku_prepare(struct rpc_task *task, void *data) |
| @@ -4545,9 +4548,11 @@ static void nfs4_locku_prepare(struct rpc_task *task, void *data) | |||
| 4545 | calldata->timestamp = jiffies; | 4548 | calldata->timestamp = jiffies; |
| 4546 | if (nfs4_setup_sequence(calldata->server, | 4549 | if (nfs4_setup_sequence(calldata->server, |
| 4547 | &calldata->arg.seq_args, | 4550 | &calldata->arg.seq_args, |
| 4548 | &calldata->res.seq_res, task)) | 4551 | &calldata->res.seq_res, |
| 4549 | return; | 4552 | task) != 0) |
| 4550 | rpc_call_start(task); | 4553 | nfs_release_seqid(calldata->arg.seqid); |
| 4554 | else | ||
| 4555 | rpc_call_start(task); | ||
| 4551 | } | 4556 | } |
| 4552 | 4557 | ||
| 4553 | static const struct rpc_call_ops nfs4_locku_ops = { | 4558 | static const struct rpc_call_ops nfs4_locku_ops = { |
| @@ -4692,7 +4697,7 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata) | |||
| 4692 | /* Do we need to do an open_to_lock_owner? */ | 4697 | /* Do we need to do an open_to_lock_owner? */ |
| 4693 | if (!(data->arg.lock_seqid->sequence->flags & NFS_SEQID_CONFIRMED)) { | 4698 | if (!(data->arg.lock_seqid->sequence->flags & NFS_SEQID_CONFIRMED)) { |
| 4694 | if (nfs_wait_on_sequence(data->arg.open_seqid, task) != 0) | 4699 | if (nfs_wait_on_sequence(data->arg.open_seqid, task) != 0) |
| 4695 | return; | 4700 | goto out_release_lock_seqid; |
| 4696 | data->arg.open_stateid = &state->stateid; | 4701 | data->arg.open_stateid = &state->stateid; |
| 4697 | data->arg.new_lock_owner = 1; | 4702 | data->arg.new_lock_owner = 1; |
| 4698 | data->res.open_seqid = data->arg.open_seqid; | 4703 | data->res.open_seqid = data->arg.open_seqid; |
| @@ -4701,10 +4706,15 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata) | |||
| 4701 | data->timestamp = jiffies; | 4706 | data->timestamp = jiffies; |
| 4702 | if (nfs4_setup_sequence(data->server, | 4707 | if (nfs4_setup_sequence(data->server, |
| 4703 | &data->arg.seq_args, | 4708 | &data->arg.seq_args, |
| 4704 | &data->res.seq_res, task)) | 4709 | &data->res.seq_res, |
| 4710 | task) == 0) { | ||
| 4711 | rpc_call_start(task); | ||
| 4705 | return; | 4712 | return; |
| 4706 | rpc_call_start(task); | 4713 | } |
| 4707 | dprintk("%s: done!, ret = %d\n", __func__, data->rpc_status); | 4714 | nfs_release_seqid(data->arg.open_seqid); |
| 4715 | out_release_lock_seqid: | ||
| 4716 | nfs_release_seqid(data->arg.lock_seqid); | ||
| 4717 | dprintk("%s: done!, ret = %d\n", __func__, task->tk_status); | ||
| 4708 | } | 4718 | } |
| 4709 | 4719 | ||
| 4710 | static void nfs4_recover_lock_prepare(struct rpc_task *task, void *calldata) | 4720 | static void nfs4_recover_lock_prepare(struct rpc_task *task, void *calldata) |
| @@ -5667,7 +5677,7 @@ static void nfs4_add_and_init_slots(struct nfs4_slot_table *tbl, | |||
| 5667 | tbl->slots = new; | 5677 | tbl->slots = new; |
| 5668 | tbl->max_slots = max_slots; | 5678 | tbl->max_slots = max_slots; |
| 5669 | } | 5679 | } |
| 5670 | tbl->highest_used_slotid = -1; /* no slot is currently used */ | 5680 | tbl->highest_used_slotid = NFS4_NO_SLOT; |
| 5671 | for (i = 0; i < tbl->max_slots; i++) | 5681 | for (i = 0; i < tbl->max_slots; i++) |
| 5672 | tbl->slots[i].seq_nr = ivalue; | 5682 | tbl->slots[i].seq_nr = ivalue; |
| 5673 | spin_unlock(&tbl->slot_tbl_lock); | 5683 | spin_unlock(&tbl->slot_tbl_lock); |
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index fe624c91bd00..2878f97bd78d 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c | |||
| @@ -925,8 +925,8 @@ pnfs_find_alloc_layout(struct inode *ino, | |||
| 925 | if (likely(nfsi->layout == NULL)) { /* Won the race? */ | 925 | if (likely(nfsi->layout == NULL)) { /* Won the race? */ |
| 926 | nfsi->layout = new; | 926 | nfsi->layout = new; |
| 927 | return new; | 927 | return new; |
| 928 | } | 928 | } else if (new != NULL) |
| 929 | pnfs_free_layout_hdr(new); | 929 | pnfs_free_layout_hdr(new); |
| 930 | out_existing: | 930 | out_existing: |
| 931 | pnfs_get_layout_hdr(nfsi->layout); | 931 | pnfs_get_layout_hdr(nfsi->layout); |
| 932 | return nfsi->layout; | 932 | return nfsi->layout; |
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index e831bce49766..652d3f7176a9 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
| @@ -54,6 +54,7 @@ | |||
| 54 | #include <linux/parser.h> | 54 | #include <linux/parser.h> |
| 55 | #include <linux/nsproxy.h> | 55 | #include <linux/nsproxy.h> |
| 56 | #include <linux/rcupdate.h> | 56 | #include <linux/rcupdate.h> |
| 57 | #include <linux/kthread.h> | ||
| 57 | 58 | ||
| 58 | #include <asm/uaccess.h> | 59 | #include <asm/uaccess.h> |
| 59 | 60 | ||
| @@ -415,6 +416,54 @@ void nfs_sb_deactive(struct super_block *sb) | |||
| 415 | } | 416 | } |
| 416 | EXPORT_SYMBOL_GPL(nfs_sb_deactive); | 417 | EXPORT_SYMBOL_GPL(nfs_sb_deactive); |
| 417 | 418 | ||
| 419 | static int nfs_deactivate_super_async_work(void *ptr) | ||
| 420 | { | ||
| 421 | struct super_block *sb = ptr; | ||
| 422 | |||
| 423 | deactivate_super(sb); | ||
| 424 | module_put_and_exit(0); | ||
| 425 | return 0; | ||
| 426 | } | ||
| 427 | |||
| 428 | /* | ||
| 429 | * same effect as deactivate_super, but will do final unmount in kthread | ||
| 430 | * context | ||
| 431 | */ | ||
| 432 | static void nfs_deactivate_super_async(struct super_block *sb) | ||
| 433 | { | ||
| 434 | struct task_struct *task; | ||
| 435 | char buf[INET6_ADDRSTRLEN + 1]; | ||
| 436 | struct nfs_server *server = NFS_SB(sb); | ||
| 437 | struct nfs_client *clp = server->nfs_client; | ||
| 438 | |||
| 439 | if (!atomic_add_unless(&sb->s_active, -1, 1)) { | ||
| 440 | rcu_read_lock(); | ||
| 441 | snprintf(buf, sizeof(buf), | ||
| 442 | rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_ADDR)); | ||
| 443 | rcu_read_unlock(); | ||
| 444 | |||
| 445 | __module_get(THIS_MODULE); | ||
| 446 | task = kthread_run(nfs_deactivate_super_async_work, sb, | ||
| 447 | "%s-deactivate-super", buf); | ||
| 448 | if (IS_ERR(task)) { | ||
| 449 | pr_err("%s: kthread_run: %ld\n", | ||
| 450 | __func__, PTR_ERR(task)); | ||
| 451 | /* make synchronous call and hope for the best */ | ||
| 452 | deactivate_super(sb); | ||
| 453 | module_put(THIS_MODULE); | ||
| 454 | } | ||
| 455 | } | ||
| 456 | } | ||
| 457 | |||
| 458 | void nfs_sb_deactive_async(struct super_block *sb) | ||
| 459 | { | ||
| 460 | struct nfs_server *server = NFS_SB(sb); | ||
| 461 | |||
| 462 | if (atomic_dec_and_test(&server->active)) | ||
| 463 | nfs_deactivate_super_async(sb); | ||
| 464 | } | ||
| 465 | EXPORT_SYMBOL_GPL(nfs_sb_deactive_async); | ||
| 466 | |||
| 418 | /* | 467 | /* |
| 419 | * Deliver file system statistics to userspace | 468 | * Deliver file system statistics to userspace |
| 420 | */ | 469 | */ |
| @@ -771,7 +820,7 @@ int nfs_show_devname(struct seq_file *m, struct dentry *root) | |||
| 771 | int err = 0; | 820 | int err = 0; |
| 772 | if (!page) | 821 | if (!page) |
| 773 | return -ENOMEM; | 822 | return -ENOMEM; |
| 774 | devname = nfs_path(&dummy, root, page, PAGE_SIZE); | 823 | devname = nfs_path(&dummy, root, page, PAGE_SIZE, 0); |
| 775 | if (IS_ERR(devname)) | 824 | if (IS_ERR(devname)) |
| 776 | err = PTR_ERR(devname); | 825 | err = PTR_ERR(devname); |
| 777 | else | 826 | else |
diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c index 13cea637eff8..3f79c77153b8 100644 --- a/fs/nfs/unlink.c +++ b/fs/nfs/unlink.c | |||
| @@ -95,7 +95,7 @@ static void nfs_async_unlink_release(void *calldata) | |||
| 95 | 95 | ||
| 96 | nfs_dec_sillycount(data->dir); | 96 | nfs_dec_sillycount(data->dir); |
| 97 | nfs_free_unlinkdata(data); | 97 | nfs_free_unlinkdata(data); |
| 98 | nfs_sb_deactive(sb); | 98 | nfs_sb_deactive_async(sb); |
| 99 | } | 99 | } |
| 100 | 100 | ||
| 101 | static void nfs_unlink_prepare(struct rpc_task *task, void *calldata) | 101 | static void nfs_unlink_prepare(struct rpc_task *task, void *calldata) |
diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c index f35794b97e8e..a50636025364 100644 --- a/fs/notify/fanotify/fanotify.c +++ b/fs/notify/fanotify/fanotify.c | |||
| @@ -21,6 +21,7 @@ static bool should_merge(struct fsnotify_event *old, struct fsnotify_event *new) | |||
| 21 | if ((old->path.mnt == new->path.mnt) && | 21 | if ((old->path.mnt == new->path.mnt) && |
| 22 | (old->path.dentry == new->path.dentry)) | 22 | (old->path.dentry == new->path.dentry)) |
| 23 | return true; | 23 | return true; |
| 24 | break; | ||
| 24 | case (FSNOTIFY_EVENT_NONE): | 25 | case (FSNOTIFY_EVENT_NONE): |
| 25 | return true; | 26 | return true; |
| 26 | default: | 27 | default: |
diff --git a/fs/xfs/xfs_alloc.c b/fs/xfs/xfs_alloc.c index 4f33c32affe3..335206a9c698 100644 --- a/fs/xfs/xfs_alloc.c +++ b/fs/xfs/xfs_alloc.c | |||
| @@ -1866,6 +1866,7 @@ xfs_alloc_fix_freelist( | |||
| 1866 | /* | 1866 | /* |
| 1867 | * Initialize the args structure. | 1867 | * Initialize the args structure. |
| 1868 | */ | 1868 | */ |
| 1869 | memset(&targs, 0, sizeof(targs)); | ||
| 1869 | targs.tp = tp; | 1870 | targs.tp = tp; |
| 1870 | targs.mp = mp; | 1871 | targs.mp = mp; |
| 1871 | targs.agbp = agbp; | 1872 | targs.agbp = agbp; |
| @@ -2207,7 +2208,7 @@ xfs_alloc_read_agf( | |||
| 2207 | * group or loop over the allocation groups to find the result. | 2208 | * group or loop over the allocation groups to find the result. |
| 2208 | */ | 2209 | */ |
| 2209 | int /* error */ | 2210 | int /* error */ |
| 2210 | __xfs_alloc_vextent( | 2211 | xfs_alloc_vextent( |
| 2211 | xfs_alloc_arg_t *args) /* allocation argument structure */ | 2212 | xfs_alloc_arg_t *args) /* allocation argument structure */ |
| 2212 | { | 2213 | { |
| 2213 | xfs_agblock_t agsize; /* allocation group size */ | 2214 | xfs_agblock_t agsize; /* allocation group size */ |
| @@ -2417,46 +2418,6 @@ error0: | |||
| 2417 | return error; | 2418 | return error; |
| 2418 | } | 2419 | } |
| 2419 | 2420 | ||
| 2420 | static void | ||
| 2421 | xfs_alloc_vextent_worker( | ||
| 2422 | struct work_struct *work) | ||
| 2423 | { | ||
| 2424 | struct xfs_alloc_arg *args = container_of(work, | ||
| 2425 | struct xfs_alloc_arg, work); | ||
| 2426 | unsigned long pflags; | ||
| 2427 | |||
| 2428 | /* we are in a transaction context here */ | ||
| 2429 | current_set_flags_nested(&pflags, PF_FSTRANS); | ||
| 2430 | |||
| 2431 | args->result = __xfs_alloc_vextent(args); | ||
| 2432 | complete(args->done); | ||
| 2433 | |||
| 2434 | current_restore_flags_nested(&pflags, PF_FSTRANS); | ||
| 2435 | } | ||
| 2436 | |||
| 2437 | /* | ||
| 2438 | * Data allocation requests often come in with little stack to work on. Push | ||
| 2439 | * them off to a worker thread so there is lots of stack to use. Metadata | ||
| 2440 | * requests, OTOH, are generally from low stack usage paths, so avoid the | ||
| 2441 | * context switch overhead here. | ||
| 2442 | */ | ||
| 2443 | int | ||
| 2444 | xfs_alloc_vextent( | ||
| 2445 | struct xfs_alloc_arg *args) | ||
| 2446 | { | ||
| 2447 | DECLARE_COMPLETION_ONSTACK(done); | ||
| 2448 | |||
| 2449 | if (!args->userdata) | ||
| 2450 | return __xfs_alloc_vextent(args); | ||
| 2451 | |||
| 2452 | |||
| 2453 | args->done = &done; | ||
| 2454 | INIT_WORK_ONSTACK(&args->work, xfs_alloc_vextent_worker); | ||
| 2455 | queue_work(xfs_alloc_wq, &args->work); | ||
| 2456 | wait_for_completion(&done); | ||
| 2457 | return args->result; | ||
| 2458 | } | ||
| 2459 | |||
| 2460 | /* | 2421 | /* |
| 2461 | * Free an extent. | 2422 | * Free an extent. |
| 2462 | * Just break up the extent address and hand off to xfs_free_ag_extent | 2423 | * Just break up the extent address and hand off to xfs_free_ag_extent |
diff --git a/fs/xfs/xfs_alloc.h b/fs/xfs/xfs_alloc.h index 93be4a667ca1..feacb061bab7 100644 --- a/fs/xfs/xfs_alloc.h +++ b/fs/xfs/xfs_alloc.h | |||
| @@ -120,9 +120,6 @@ typedef struct xfs_alloc_arg { | |||
| 120 | char isfl; /* set if is freelist blocks - !acctg */ | 120 | char isfl; /* set if is freelist blocks - !acctg */ |
| 121 | char userdata; /* set if this is user data */ | 121 | char userdata; /* set if this is user data */ |
| 122 | xfs_fsblock_t firstblock; /* io first block allocated */ | 122 | xfs_fsblock_t firstblock; /* io first block allocated */ |
| 123 | struct completion *done; | ||
| 124 | struct work_struct work; | ||
| 125 | int result; | ||
| 126 | } xfs_alloc_arg_t; | 123 | } xfs_alloc_arg_t; |
| 127 | 124 | ||
| 128 | /* | 125 | /* |
diff --git a/fs/xfs/xfs_alloc_btree.c b/fs/xfs/xfs_alloc_btree.c index f1647caace8f..f7876c6d6165 100644 --- a/fs/xfs/xfs_alloc_btree.c +++ b/fs/xfs/xfs_alloc_btree.c | |||
| @@ -121,6 +121,8 @@ xfs_allocbt_free_block( | |||
| 121 | xfs_extent_busy_insert(cur->bc_tp, be32_to_cpu(agf->agf_seqno), bno, 1, | 121 | xfs_extent_busy_insert(cur->bc_tp, be32_to_cpu(agf->agf_seqno), bno, 1, |
| 122 | XFS_EXTENT_BUSY_SKIP_DISCARD); | 122 | XFS_EXTENT_BUSY_SKIP_DISCARD); |
| 123 | xfs_trans_agbtree_delta(cur->bc_tp, -1); | 123 | xfs_trans_agbtree_delta(cur->bc_tp, -1); |
| 124 | |||
| 125 | xfs_trans_binval(cur->bc_tp, bp); | ||
| 124 | return 0; | 126 | return 0; |
| 125 | } | 127 | } |
| 126 | 128 | ||
diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c index 848ffa77707b..83d0cf3df930 100644 --- a/fs/xfs/xfs_bmap.c +++ b/fs/xfs/xfs_bmap.c | |||
| @@ -2437,6 +2437,7 @@ xfs_bmap_btalloc( | |||
| 2437 | * Normal allocation, done through xfs_alloc_vextent. | 2437 | * Normal allocation, done through xfs_alloc_vextent. |
| 2438 | */ | 2438 | */ |
| 2439 | tryagain = isaligned = 0; | 2439 | tryagain = isaligned = 0; |
| 2440 | memset(&args, 0, sizeof(args)); | ||
| 2440 | args.tp = ap->tp; | 2441 | args.tp = ap->tp; |
| 2441 | args.mp = mp; | 2442 | args.mp = mp; |
| 2442 | args.fsbno = ap->blkno; | 2443 | args.fsbno = ap->blkno; |
| @@ -3082,6 +3083,7 @@ xfs_bmap_extents_to_btree( | |||
| 3082 | * Convert to a btree with two levels, one record in root. | 3083 | * Convert to a btree with two levels, one record in root. |
| 3083 | */ | 3084 | */ |
| 3084 | XFS_IFORK_FMT_SET(ip, whichfork, XFS_DINODE_FMT_BTREE); | 3085 | XFS_IFORK_FMT_SET(ip, whichfork, XFS_DINODE_FMT_BTREE); |
| 3086 | memset(&args, 0, sizeof(args)); | ||
| 3085 | args.tp = tp; | 3087 | args.tp = tp; |
| 3086 | args.mp = mp; | 3088 | args.mp = mp; |
| 3087 | args.firstblock = *firstblock; | 3089 | args.firstblock = *firstblock; |
| @@ -3237,6 +3239,7 @@ xfs_bmap_local_to_extents( | |||
| 3237 | xfs_buf_t *bp; /* buffer for extent block */ | 3239 | xfs_buf_t *bp; /* buffer for extent block */ |
| 3238 | xfs_bmbt_rec_host_t *ep;/* extent record pointer */ | 3240 | xfs_bmbt_rec_host_t *ep;/* extent record pointer */ |
| 3239 | 3241 | ||
| 3242 | memset(&args, 0, sizeof(args)); | ||
| 3240 | args.tp = tp; | 3243 | args.tp = tp; |
| 3241 | args.mp = ip->i_mount; | 3244 | args.mp = ip->i_mount; |
| 3242 | args.firstblock = *firstblock; | 3245 | args.firstblock = *firstblock; |
| @@ -4616,12 +4619,11 @@ xfs_bmapi_delay( | |||
| 4616 | 4619 | ||
| 4617 | 4620 | ||
| 4618 | STATIC int | 4621 | STATIC int |
| 4619 | xfs_bmapi_allocate( | 4622 | __xfs_bmapi_allocate( |
| 4620 | struct xfs_bmalloca *bma, | 4623 | struct xfs_bmalloca *bma) |
| 4621 | int flags) | ||
| 4622 | { | 4624 | { |
| 4623 | struct xfs_mount *mp = bma->ip->i_mount; | 4625 | struct xfs_mount *mp = bma->ip->i_mount; |
| 4624 | int whichfork = (flags & XFS_BMAPI_ATTRFORK) ? | 4626 | int whichfork = (bma->flags & XFS_BMAPI_ATTRFORK) ? |
| 4625 | XFS_ATTR_FORK : XFS_DATA_FORK; | 4627 | XFS_ATTR_FORK : XFS_DATA_FORK; |
| 4626 | struct xfs_ifork *ifp = XFS_IFORK_PTR(bma->ip, whichfork); | 4628 | struct xfs_ifork *ifp = XFS_IFORK_PTR(bma->ip, whichfork); |
| 4627 | int tmp_logflags = 0; | 4629 | int tmp_logflags = 0; |
| @@ -4654,24 +4656,27 @@ xfs_bmapi_allocate( | |||
| 4654 | * Indicate if this is the first user data in the file, or just any | 4656 | * Indicate if this is the first user data in the file, or just any |
| 4655 | * user data. | 4657 | * user data. |
| 4656 | */ | 4658 | */ |
| 4657 | if (!(flags & XFS_BMAPI_METADATA)) { | 4659 | if (!(bma->flags & XFS_BMAPI_METADATA)) { |
| 4658 | bma->userdata = (bma->offset == 0) ? | 4660 | bma->userdata = (bma->offset == 0) ? |
| 4659 | XFS_ALLOC_INITIAL_USER_DATA : XFS_ALLOC_USERDATA; | 4661 | XFS_ALLOC_INITIAL_USER_DATA : XFS_ALLOC_USERDATA; |
| 4660 | } | 4662 | } |
| 4661 | 4663 | ||
| 4662 | bma->minlen = (flags & XFS_BMAPI_CONTIG) ? bma->length : 1; | 4664 | bma->minlen = (bma->flags & XFS_BMAPI_CONTIG) ? bma->length : 1; |
| 4663 | 4665 | ||
| 4664 | /* | 4666 | /* |
| 4665 | * Only want to do the alignment at the eof if it is userdata and | 4667 | * Only want to do the alignment at the eof if it is userdata and |
| 4666 | * allocation length is larger than a stripe unit. | 4668 | * allocation length is larger than a stripe unit. |
| 4667 | */ | 4669 | */ |
| 4668 | if (mp->m_dalign && bma->length >= mp->m_dalign && | 4670 | if (mp->m_dalign && bma->length >= mp->m_dalign && |
| 4669 | !(flags & XFS_BMAPI_METADATA) && whichfork == XFS_DATA_FORK) { | 4671 | !(bma->flags & XFS_BMAPI_METADATA) && whichfork == XFS_DATA_FORK) { |
| 4670 | error = xfs_bmap_isaeof(bma, whichfork); | 4672 | error = xfs_bmap_isaeof(bma, whichfork); |
| 4671 | if (error) | 4673 | if (error) |
| 4672 | return error; | 4674 | return error; |
| 4673 | } | 4675 | } |
| 4674 | 4676 | ||
| 4677 | if (bma->flags & XFS_BMAPI_STACK_SWITCH) | ||
| 4678 | bma->stack_switch = 1; | ||
| 4679 | |||
| 4675 | error = xfs_bmap_alloc(bma); | 4680 | error = xfs_bmap_alloc(bma); |
| 4676 | if (error) | 4681 | if (error) |
| 4677 | return error; | 4682 | return error; |
| @@ -4706,7 +4711,7 @@ xfs_bmapi_allocate( | |||
| 4706 | * A wasdelay extent has been initialized, so shouldn't be flagged | 4711 | * A wasdelay extent has been initialized, so shouldn't be flagged |
| 4707 | * as unwritten. | 4712 | * as unwritten. |
| 4708 | */ | 4713 | */ |
| 4709 | if (!bma->wasdel && (flags & XFS_BMAPI_PREALLOC) && | 4714 | if (!bma->wasdel && (bma->flags & XFS_BMAPI_PREALLOC) && |
| 4710 | xfs_sb_version_hasextflgbit(&mp->m_sb)) | 4715 | xfs_sb_version_hasextflgbit(&mp->m_sb)) |
| 4711 | bma->got.br_state = XFS_EXT_UNWRITTEN; | 4716 | bma->got.br_state = XFS_EXT_UNWRITTEN; |
| 4712 | 4717 | ||
| @@ -4734,6 +4739,45 @@ xfs_bmapi_allocate( | |||
| 4734 | return 0; | 4739 | return 0; |
| 4735 | } | 4740 | } |
| 4736 | 4741 | ||
| 4742 | static void | ||
| 4743 | xfs_bmapi_allocate_worker( | ||
| 4744 | struct work_struct *work) | ||
| 4745 | { | ||
| 4746 | struct xfs_bmalloca *args = container_of(work, | ||
| 4747 | struct xfs_bmalloca, work); | ||
| 4748 | unsigned long pflags; | ||
| 4749 | |||
| 4750 | /* we are in a transaction context here */ | ||
| 4751 | current_set_flags_nested(&pflags, PF_FSTRANS); | ||
| 4752 | |||
| 4753 | args->result = __xfs_bmapi_allocate(args); | ||
| 4754 | complete(args->done); | ||
| 4755 | |||
| 4756 | current_restore_flags_nested(&pflags, PF_FSTRANS); | ||
| 4757 | } | ||
| 4758 | |||
| 4759 | /* | ||
| 4760 | * Some allocation requests often come in with little stack to work on. Push | ||
| 4761 | * them off to a worker thread so there is lots of stack to use. Otherwise just | ||
| 4762 | * call directly to avoid the context switch overhead here. | ||
| 4763 | */ | ||
| 4764 | int | ||
| 4765 | xfs_bmapi_allocate( | ||
| 4766 | struct xfs_bmalloca *args) | ||
| 4767 | { | ||
| 4768 | DECLARE_COMPLETION_ONSTACK(done); | ||
| 4769 | |||
| 4770 | if (!args->stack_switch) | ||
| 4771 | return __xfs_bmapi_allocate(args); | ||
| 4772 | |||
| 4773 | |||
| 4774 | args->done = &done; | ||
| 4775 | INIT_WORK_ONSTACK(&args->work, xfs_bmapi_allocate_worker); | ||
| 4776 | queue_work(xfs_alloc_wq, &args->work); | ||
| 4777 | wait_for_completion(&done); | ||
| 4778 | return args->result; | ||
| 4779 | } | ||
| 4780 | |||
| 4737 | STATIC int | 4781 | STATIC int |
| 4738 | xfs_bmapi_convert_unwritten( | 4782 | xfs_bmapi_convert_unwritten( |
| 4739 | struct xfs_bmalloca *bma, | 4783 | struct xfs_bmalloca *bma, |
| @@ -4919,6 +4963,7 @@ xfs_bmapi_write( | |||
| 4919 | bma.conv = !!(flags & XFS_BMAPI_CONVERT); | 4963 | bma.conv = !!(flags & XFS_BMAPI_CONVERT); |
| 4920 | bma.wasdel = wasdelay; | 4964 | bma.wasdel = wasdelay; |
| 4921 | bma.offset = bno; | 4965 | bma.offset = bno; |
| 4966 | bma.flags = flags; | ||
| 4922 | 4967 | ||
| 4923 | /* | 4968 | /* |
| 4924 | * There's a 32/64 bit type mismatch between the | 4969 | * There's a 32/64 bit type mismatch between the |
| @@ -4934,7 +4979,7 @@ xfs_bmapi_write( | |||
| 4934 | 4979 | ||
| 4935 | ASSERT(len > 0); | 4980 | ASSERT(len > 0); |
| 4936 | ASSERT(bma.length > 0); | 4981 | ASSERT(bma.length > 0); |
| 4937 | error = xfs_bmapi_allocate(&bma, flags); | 4982 | error = xfs_bmapi_allocate(&bma); |
| 4938 | if (error) | 4983 | if (error) |
| 4939 | goto error0; | 4984 | goto error0; |
| 4940 | if (bma.blkno == NULLFSBLOCK) | 4985 | if (bma.blkno == NULLFSBLOCK) |
diff --git a/fs/xfs/xfs_bmap.h b/fs/xfs/xfs_bmap.h index 803b56d7ce16..5f469c3516eb 100644 --- a/fs/xfs/xfs_bmap.h +++ b/fs/xfs/xfs_bmap.h | |||
| @@ -77,6 +77,7 @@ typedef struct xfs_bmap_free | |||
| 77 | * from written to unwritten, otherwise convert from unwritten to written. | 77 | * from written to unwritten, otherwise convert from unwritten to written. |
| 78 | */ | 78 | */ |
| 79 | #define XFS_BMAPI_CONVERT 0x040 | 79 | #define XFS_BMAPI_CONVERT 0x040 |
| 80 | #define XFS_BMAPI_STACK_SWITCH 0x080 | ||
| 80 | 81 | ||
| 81 | #define XFS_BMAPI_FLAGS \ | 82 | #define XFS_BMAPI_FLAGS \ |
| 82 | { XFS_BMAPI_ENTIRE, "ENTIRE" }, \ | 83 | { XFS_BMAPI_ENTIRE, "ENTIRE" }, \ |
| @@ -85,7 +86,8 @@ typedef struct xfs_bmap_free | |||
| 85 | { XFS_BMAPI_PREALLOC, "PREALLOC" }, \ | 86 | { XFS_BMAPI_PREALLOC, "PREALLOC" }, \ |
| 86 | { XFS_BMAPI_IGSTATE, "IGSTATE" }, \ | 87 | { XFS_BMAPI_IGSTATE, "IGSTATE" }, \ |
| 87 | { XFS_BMAPI_CONTIG, "CONTIG" }, \ | 88 | { XFS_BMAPI_CONTIG, "CONTIG" }, \ |
| 88 | { XFS_BMAPI_CONVERT, "CONVERT" } | 89 | { XFS_BMAPI_CONVERT, "CONVERT" }, \ |
| 90 | { XFS_BMAPI_STACK_SWITCH, "STACK_SWITCH" } | ||
| 89 | 91 | ||
| 90 | 92 | ||
| 91 | static inline int xfs_bmapi_aflag(int w) | 93 | static inline int xfs_bmapi_aflag(int w) |
| @@ -133,6 +135,11 @@ typedef struct xfs_bmalloca { | |||
| 133 | char userdata;/* set if is user data */ | 135 | char userdata;/* set if is user data */ |
| 134 | char aeof; /* allocated space at eof */ | 136 | char aeof; /* allocated space at eof */ |
| 135 | char conv; /* overwriting unwritten extents */ | 137 | char conv; /* overwriting unwritten extents */ |
| 138 | char stack_switch; | ||
| 139 | int flags; | ||
| 140 | struct completion *done; | ||
| 141 | struct work_struct work; | ||
| 142 | int result; | ||
| 136 | } xfs_bmalloca_t; | 143 | } xfs_bmalloca_t; |
| 137 | 144 | ||
| 138 | /* | 145 | /* |
diff --git a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c index a8d0ed911196..becf4a97efc6 100644 --- a/fs/xfs/xfs_buf_item.c +++ b/fs/xfs/xfs_buf_item.c | |||
| @@ -526,7 +526,25 @@ xfs_buf_item_unpin( | |||
| 526 | } | 526 | } |
| 527 | xfs_buf_relse(bp); | 527 | xfs_buf_relse(bp); |
| 528 | } else if (freed && remove) { | 528 | } else if (freed && remove) { |
| 529 | /* | ||
| 530 | * There are currently two references to the buffer - the active | ||
| 531 | * LRU reference and the buf log item. What we are about to do | ||
| 532 | * here - simulate a failed IO completion - requires 3 | ||
| 533 | * references. | ||
| 534 | * | ||
| 535 | * The LRU reference is removed by the xfs_buf_stale() call. The | ||
| 536 | * buf item reference is removed by the xfs_buf_iodone() | ||
| 537 | * callback that is run by xfs_buf_do_callbacks() during ioend | ||
| 538 | * processing (via the bp->b_iodone callback), and then finally | ||
| 539 | * the ioend processing will drop the IO reference if the buffer | ||
| 540 | * is marked XBF_ASYNC. | ||
| 541 | * | ||
| 542 | * Hence we need to take an additional reference here so that IO | ||
| 543 | * completion processing doesn't free the buffer prematurely. | ||
| 544 | */ | ||
| 529 | xfs_buf_lock(bp); | 545 | xfs_buf_lock(bp); |
| 546 | xfs_buf_hold(bp); | ||
| 547 | bp->b_flags |= XBF_ASYNC; | ||
| 530 | xfs_buf_ioerror(bp, EIO); | 548 | xfs_buf_ioerror(bp, EIO); |
| 531 | XFS_BUF_UNDONE(bp); | 549 | XFS_BUF_UNDONE(bp); |
| 532 | xfs_buf_stale(bp); | 550 | xfs_buf_stale(bp); |
diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c index c25b094efbf7..4beaede43277 100644 --- a/fs/xfs/xfs_fsops.c +++ b/fs/xfs/xfs_fsops.c | |||
| @@ -399,9 +399,26 @@ xfs_growfs_data_private( | |||
| 399 | 399 | ||
| 400 | /* update secondary superblocks. */ | 400 | /* update secondary superblocks. */ |
| 401 | for (agno = 1; agno < nagcount; agno++) { | 401 | for (agno = 1; agno < nagcount; agno++) { |
| 402 | error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp, | 402 | error = 0; |
| 403 | /* | ||
| 404 | * new secondary superblocks need to be zeroed, not read from | ||
| 405 | * disk as the contents of the new area we are growing into is | ||
| 406 | * completely unknown. | ||
| 407 | */ | ||
| 408 | if (agno < oagcount) { | ||
| 409 | error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp, | ||
| 403 | XFS_AGB_TO_DADDR(mp, agno, XFS_SB_BLOCK(mp)), | 410 | XFS_AGB_TO_DADDR(mp, agno, XFS_SB_BLOCK(mp)), |
| 404 | XFS_FSS_TO_BB(mp, 1), 0, &bp); | 411 | XFS_FSS_TO_BB(mp, 1), 0, &bp); |
| 412 | } else { | ||
| 413 | bp = xfs_trans_get_buf(NULL, mp->m_ddev_targp, | ||
| 414 | XFS_AGB_TO_DADDR(mp, agno, XFS_SB_BLOCK(mp)), | ||
| 415 | XFS_FSS_TO_BB(mp, 1), 0); | ||
| 416 | if (bp) | ||
| 417 | xfs_buf_zero(bp, 0, BBTOB(bp->b_length)); | ||
| 418 | else | ||
| 419 | error = ENOMEM; | ||
| 420 | } | ||
| 421 | |||
| 405 | if (error) { | 422 | if (error) { |
| 406 | xfs_warn(mp, | 423 | xfs_warn(mp, |
| 407 | "error %d reading secondary superblock for ag %d", | 424 | "error %d reading secondary superblock for ag %d", |
| @@ -423,7 +440,7 @@ xfs_growfs_data_private( | |||
| 423 | break; /* no point in continuing */ | 440 | break; /* no point in continuing */ |
| 424 | } | 441 | } |
| 425 | } | 442 | } |
| 426 | return 0; | 443 | return error; |
| 427 | 444 | ||
| 428 | error0: | 445 | error0: |
| 429 | xfs_trans_cancel(tp, XFS_TRANS_ABORT); | 446 | xfs_trans_cancel(tp, XFS_TRANS_ABORT); |
diff --git a/fs/xfs/xfs_ialloc.c b/fs/xfs/xfs_ialloc.c index 445bf1aef31c..c5c4ef4f2bdb 100644 --- a/fs/xfs/xfs_ialloc.c +++ b/fs/xfs/xfs_ialloc.c | |||
| @@ -250,6 +250,7 @@ xfs_ialloc_ag_alloc( | |||
| 250 | /* boundary */ | 250 | /* boundary */ |
| 251 | struct xfs_perag *pag; | 251 | struct xfs_perag *pag; |
| 252 | 252 | ||
| 253 | memset(&args, 0, sizeof(args)); | ||
| 253 | args.tp = tp; | 254 | args.tp = tp; |
| 254 | args.mp = tp->t_mountp; | 255 | args.mp = tp->t_mountp; |
| 255 | 256 | ||
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 2778258fcfa2..1938b41ee9f5 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c | |||
| @@ -1509,7 +1509,8 @@ xfs_ifree_cluster( | |||
| 1509 | * to mark all the active inodes on the buffer stale. | 1509 | * to mark all the active inodes on the buffer stale. |
| 1510 | */ | 1510 | */ |
| 1511 | bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, blkno, | 1511 | bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, blkno, |
| 1512 | mp->m_bsize * blks_per_cluster, 0); | 1512 | mp->m_bsize * blks_per_cluster, |
| 1513 | XBF_UNMAPPED); | ||
| 1513 | 1514 | ||
| 1514 | if (!bp) | 1515 | if (!bp) |
| 1515 | return ENOMEM; | 1516 | return ENOMEM; |
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c index 8305f2ac6773..c1df3c623de2 100644 --- a/fs/xfs/xfs_ioctl.c +++ b/fs/xfs/xfs_ioctl.c | |||
| @@ -70,7 +70,7 @@ xfs_find_handle( | |||
| 70 | int hsize; | 70 | int hsize; |
| 71 | xfs_handle_t handle; | 71 | xfs_handle_t handle; |
| 72 | struct inode *inode; | 72 | struct inode *inode; |
| 73 | struct fd f; | 73 | struct fd f = {0}; |
| 74 | struct path path; | 74 | struct path path; |
| 75 | int error; | 75 | int error; |
| 76 | struct xfs_inode *ip; | 76 | struct xfs_inode *ip; |
diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c index 973dff6ad935..7f537663365b 100644 --- a/fs/xfs/xfs_iomap.c +++ b/fs/xfs/xfs_iomap.c | |||
| @@ -584,7 +584,9 @@ xfs_iomap_write_allocate( | |||
| 584 | * pointer that the caller gave to us. | 584 | * pointer that the caller gave to us. |
| 585 | */ | 585 | */ |
| 586 | error = xfs_bmapi_write(tp, ip, map_start_fsb, | 586 | error = xfs_bmapi_write(tp, ip, map_start_fsb, |
| 587 | count_fsb, 0, &first_block, 1, | 587 | count_fsb, |
| 588 | XFS_BMAPI_STACK_SWITCH, | ||
| 589 | &first_block, 1, | ||
| 588 | imap, &nimaps, &free_list); | 590 | imap, &nimaps, &free_list); |
| 589 | if (error) | 591 | if (error) |
| 590 | goto trans_cancel; | 592 | goto trans_cancel; |
diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c index 7f4f9370d0e7..4dad756962d0 100644 --- a/fs/xfs/xfs_log.c +++ b/fs/xfs/xfs_log.c | |||
| @@ -2387,14 +2387,27 @@ xlog_state_do_callback( | |||
| 2387 | 2387 | ||
| 2388 | 2388 | ||
| 2389 | /* | 2389 | /* |
| 2390 | * update the last_sync_lsn before we drop the | 2390 | * Completion of a iclog IO does not imply that |
| 2391 | * a transaction has completed, as transactions | ||
| 2392 | * can be large enough to span many iclogs. We | ||
| 2393 | * cannot change the tail of the log half way | ||
| 2394 | * through a transaction as this may be the only | ||
| 2395 | * transaction in the log and moving th etail to | ||
| 2396 | * point to the middle of it will prevent | ||
| 2397 | * recovery from finding the start of the | ||
| 2398 | * transaction. Hence we should only update the | ||
| 2399 | * last_sync_lsn if this iclog contains | ||
| 2400 | * transaction completion callbacks on it. | ||
| 2401 | * | ||
| 2402 | * We have to do this before we drop the | ||
| 2391 | * icloglock to ensure we are the only one that | 2403 | * icloglock to ensure we are the only one that |
| 2392 | * can update it. | 2404 | * can update it. |
| 2393 | */ | 2405 | */ |
| 2394 | ASSERT(XFS_LSN_CMP(atomic64_read(&log->l_last_sync_lsn), | 2406 | ASSERT(XFS_LSN_CMP(atomic64_read(&log->l_last_sync_lsn), |
| 2395 | be64_to_cpu(iclog->ic_header.h_lsn)) <= 0); | 2407 | be64_to_cpu(iclog->ic_header.h_lsn)) <= 0); |
| 2396 | atomic64_set(&log->l_last_sync_lsn, | 2408 | if (iclog->ic_callback) |
| 2397 | be64_to_cpu(iclog->ic_header.h_lsn)); | 2409 | atomic64_set(&log->l_last_sync_lsn, |
| 2410 | be64_to_cpu(iclog->ic_header.h_lsn)); | ||
| 2398 | 2411 | ||
| 2399 | } else | 2412 | } else |
| 2400 | ioerrors++; | 2413 | ioerrors++; |
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c index 5da3ace352bf..d308749fabf1 100644 --- a/fs/xfs/xfs_log_recover.c +++ b/fs/xfs/xfs_log_recover.c | |||
| @@ -3541,7 +3541,7 @@ xlog_do_recovery_pass( | |||
| 3541 | * - order is important. | 3541 | * - order is important. |
| 3542 | */ | 3542 | */ |
| 3543 | error = xlog_bread_offset(log, 0, | 3543 | error = xlog_bread_offset(log, 0, |
| 3544 | bblks - split_bblks, hbp, | 3544 | bblks - split_bblks, dbp, |
| 3545 | offset + BBTOB(split_bblks)); | 3545 | offset + BBTOB(split_bblks)); |
| 3546 | if (error) | 3546 | if (error) |
| 3547 | goto bread_err2; | 3547 | goto bread_err2; |
