diff options
| author | Patrick McHardy <kaber@trash.net> | 2010-05-10 12:39:28 -0400 |
|---|---|---|
| committer | Patrick McHardy <kaber@trash.net> | 2010-05-10 12:39:28 -0400 |
| commit | 1e4b1057121bc756b91758a434b504d2010f6088 (patch) | |
| tree | b016cf2c728289c7e36d9e4e488f30ab0bd0ae6e /fs | |
| parent | 3b254c54ec46eb022cb26ee6ab37fae23f5f7d6a (diff) | |
| parent | 3ee943728fff536edaf8f59faa58aaa1aa7366e3 (diff) | |
Merge branch 'master' of /repos/git/net-next-2.6
Conflicts:
net/bridge/br_device.c
net/bridge/br_forward.c
Signed-off-by: Patrick McHardy <kaber@trash.net>
Diffstat (limited to 'fs')
37 files changed, 506 insertions, 325 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 9e23ffea7f54..b34d32fdaaec 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
| @@ -3235,7 +3235,8 @@ int btrfs_check_data_free_space(struct btrfs_root *root, struct inode *inode, | |||
| 3235 | u64 bytes) | 3235 | u64 bytes) |
| 3236 | { | 3236 | { |
| 3237 | struct btrfs_space_info *data_sinfo; | 3237 | struct btrfs_space_info *data_sinfo; |
| 3238 | int ret = 0, committed = 0; | 3238 | u64 used; |
| 3239 | int ret = 0, committed = 0, flushed = 0; | ||
| 3239 | 3240 | ||
| 3240 | /* make sure bytes are sectorsize aligned */ | 3241 | /* make sure bytes are sectorsize aligned */ |
| 3241 | bytes = (bytes + root->sectorsize - 1) & ~((u64)root->sectorsize - 1); | 3242 | bytes = (bytes + root->sectorsize - 1) & ~((u64)root->sectorsize - 1); |
| @@ -3247,12 +3248,21 @@ int btrfs_check_data_free_space(struct btrfs_root *root, struct inode *inode, | |||
| 3247 | again: | 3248 | again: |
| 3248 | /* make sure we have enough space to handle the data first */ | 3249 | /* make sure we have enough space to handle the data first */ |
| 3249 | spin_lock(&data_sinfo->lock); | 3250 | spin_lock(&data_sinfo->lock); |
| 3250 | if (data_sinfo->total_bytes - data_sinfo->bytes_used - | 3251 | used = data_sinfo->bytes_used + data_sinfo->bytes_delalloc + |
| 3251 | data_sinfo->bytes_delalloc - data_sinfo->bytes_reserved - | 3252 | data_sinfo->bytes_reserved + data_sinfo->bytes_pinned + |
| 3252 | data_sinfo->bytes_pinned - data_sinfo->bytes_readonly - | 3253 | data_sinfo->bytes_readonly + data_sinfo->bytes_may_use + |
| 3253 | data_sinfo->bytes_may_use - data_sinfo->bytes_super < bytes) { | 3254 | data_sinfo->bytes_super; |
| 3255 | |||
| 3256 | if (used + bytes > data_sinfo->total_bytes) { | ||
| 3254 | struct btrfs_trans_handle *trans; | 3257 | struct btrfs_trans_handle *trans; |
| 3255 | 3258 | ||
| 3259 | if (!flushed) { | ||
| 3260 | spin_unlock(&data_sinfo->lock); | ||
| 3261 | flush_delalloc(root, data_sinfo); | ||
| 3262 | flushed = 1; | ||
| 3263 | goto again; | ||
| 3264 | } | ||
| 3265 | |||
| 3256 | /* | 3266 | /* |
| 3257 | * if we don't have enough free bytes in this space then we need | 3267 | * if we don't have enough free bytes in this space then we need |
| 3258 | * to alloc a new chunk. | 3268 | * to alloc a new chunk. |
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index aa7dc36dac78..8db7b14bbae8 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c | |||
| @@ -2250,6 +2250,12 @@ again: | |||
| 2250 | if (!looped) | 2250 | if (!looped) |
| 2251 | calc_size = max_t(u64, min_stripe_size, calc_size); | 2251 | calc_size = max_t(u64, min_stripe_size, calc_size); |
| 2252 | 2252 | ||
| 2253 | /* | ||
| 2254 | * we're about to do_div by the stripe_len so lets make sure | ||
| 2255 | * we end up with something bigger than a stripe | ||
| 2256 | */ | ||
| 2257 | calc_size = max_t(u64, calc_size, stripe_len * 4); | ||
| 2258 | |||
| 2253 | do_div(calc_size, stripe_len); | 2259 | do_div(calc_size, stripe_len); |
| 2254 | calc_size *= stripe_len; | 2260 | calc_size *= stripe_len; |
| 2255 | 2261 | ||
diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index aa3cd7cc3e40..412593703d1e 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c | |||
| @@ -337,16 +337,15 @@ out: | |||
| 337 | /* | 337 | /* |
| 338 | * Get ref for the oldest snapc for an inode with dirty data... that is, the | 338 | * Get ref for the oldest snapc for an inode with dirty data... that is, the |
| 339 | * only snap context we are allowed to write back. | 339 | * only snap context we are allowed to write back. |
| 340 | * | ||
| 341 | * Caller holds i_lock. | ||
| 342 | */ | 340 | */ |
| 343 | static struct ceph_snap_context *__get_oldest_context(struct inode *inode, | 341 | static struct ceph_snap_context *get_oldest_context(struct inode *inode, |
| 344 | u64 *snap_size) | 342 | u64 *snap_size) |
| 345 | { | 343 | { |
| 346 | struct ceph_inode_info *ci = ceph_inode(inode); | 344 | struct ceph_inode_info *ci = ceph_inode(inode); |
| 347 | struct ceph_snap_context *snapc = NULL; | 345 | struct ceph_snap_context *snapc = NULL; |
| 348 | struct ceph_cap_snap *capsnap = NULL; | 346 | struct ceph_cap_snap *capsnap = NULL; |
| 349 | 347 | ||
| 348 | spin_lock(&inode->i_lock); | ||
| 350 | list_for_each_entry(capsnap, &ci->i_cap_snaps, ci_item) { | 349 | list_for_each_entry(capsnap, &ci->i_cap_snaps, ci_item) { |
| 351 | dout(" cap_snap %p snapc %p has %d dirty pages\n", capsnap, | 350 | dout(" cap_snap %p snapc %p has %d dirty pages\n", capsnap, |
| 352 | capsnap->context, capsnap->dirty_pages); | 351 | capsnap->context, capsnap->dirty_pages); |
| @@ -357,21 +356,11 @@ static struct ceph_snap_context *__get_oldest_context(struct inode *inode, | |||
| 357 | break; | 356 | break; |
| 358 | } | 357 | } |
| 359 | } | 358 | } |
| 360 | if (!snapc && ci->i_snap_realm) { | 359 | if (!snapc && ci->i_head_snapc) { |
| 361 | snapc = ceph_get_snap_context(ci->i_snap_realm->cached_context); | 360 | snapc = ceph_get_snap_context(ci->i_head_snapc); |
| 362 | dout(" head snapc %p has %d dirty pages\n", | 361 | dout(" head snapc %p has %d dirty pages\n", |
| 363 | snapc, ci->i_wrbuffer_ref_head); | 362 | snapc, ci->i_wrbuffer_ref_head); |
| 364 | } | 363 | } |
| 365 | return snapc; | ||
| 366 | } | ||
| 367 | |||
| 368 | static struct ceph_snap_context *get_oldest_context(struct inode *inode, | ||
| 369 | u64 *snap_size) | ||
| 370 | { | ||
| 371 | struct ceph_snap_context *snapc = NULL; | ||
| 372 | |||
| 373 | spin_lock(&inode->i_lock); | ||
| 374 | snapc = __get_oldest_context(inode, snap_size); | ||
| 375 | spin_unlock(&inode->i_lock); | 364 | spin_unlock(&inode->i_lock); |
| 376 | return snapc; | 365 | return snapc; |
| 377 | } | 366 | } |
| @@ -392,7 +381,7 @@ static int writepage_nounlock(struct page *page, struct writeback_control *wbc) | |||
| 392 | int len = PAGE_CACHE_SIZE; | 381 | int len = PAGE_CACHE_SIZE; |
| 393 | loff_t i_size; | 382 | loff_t i_size; |
| 394 | int err = 0; | 383 | int err = 0; |
| 395 | struct ceph_snap_context *snapc; | 384 | struct ceph_snap_context *snapc, *oldest; |
| 396 | u64 snap_size = 0; | 385 | u64 snap_size = 0; |
| 397 | long writeback_stat; | 386 | long writeback_stat; |
| 398 | 387 | ||
| @@ -413,13 +402,16 @@ static int writepage_nounlock(struct page *page, struct writeback_control *wbc) | |||
| 413 | dout("writepage %p page %p not dirty?\n", inode, page); | 402 | dout("writepage %p page %p not dirty?\n", inode, page); |
| 414 | goto out; | 403 | goto out; |
| 415 | } | 404 | } |
| 416 | if (snapc != get_oldest_context(inode, &snap_size)) { | 405 | oldest = get_oldest_context(inode, &snap_size); |
| 406 | if (snapc->seq > oldest->seq) { | ||
| 417 | dout("writepage %p page %p snapc %p not writeable - noop\n", | 407 | dout("writepage %p page %p snapc %p not writeable - noop\n", |
| 418 | inode, page, (void *)page->private); | 408 | inode, page, (void *)page->private); |
| 419 | /* we should only noop if called by kswapd */ | 409 | /* we should only noop if called by kswapd */ |
| 420 | WARN_ON((current->flags & PF_MEMALLOC) == 0); | 410 | WARN_ON((current->flags & PF_MEMALLOC) == 0); |
| 411 | ceph_put_snap_context(oldest); | ||
| 421 | goto out; | 412 | goto out; |
| 422 | } | 413 | } |
| 414 | ceph_put_snap_context(oldest); | ||
| 423 | 415 | ||
| 424 | /* is this a partial page at end of file? */ | 416 | /* is this a partial page at end of file? */ |
| 425 | if (snap_size) | 417 | if (snap_size) |
| @@ -458,7 +450,7 @@ static int writepage_nounlock(struct page *page, struct writeback_control *wbc) | |||
| 458 | ClearPagePrivate(page); | 450 | ClearPagePrivate(page); |
| 459 | end_page_writeback(page); | 451 | end_page_writeback(page); |
| 460 | ceph_put_wrbuffer_cap_refs(ci, 1, snapc); | 452 | ceph_put_wrbuffer_cap_refs(ci, 1, snapc); |
| 461 | ceph_put_snap_context(snapc); | 453 | ceph_put_snap_context(snapc); /* page's reference */ |
| 462 | out: | 454 | out: |
| 463 | return err; | 455 | return err; |
| 464 | } | 456 | } |
| @@ -558,9 +550,9 @@ static void writepages_finish(struct ceph_osd_request *req, | |||
| 558 | dout("inode %p skipping page %p\n", inode, page); | 550 | dout("inode %p skipping page %p\n", inode, page); |
| 559 | wbc->pages_skipped++; | 551 | wbc->pages_skipped++; |
| 560 | } | 552 | } |
| 553 | ceph_put_snap_context((void *)page->private); | ||
| 561 | page->private = 0; | 554 | page->private = 0; |
| 562 | ClearPagePrivate(page); | 555 | ClearPagePrivate(page); |
| 563 | ceph_put_snap_context(snapc); | ||
| 564 | dout("unlocking %d %p\n", i, page); | 556 | dout("unlocking %d %p\n", i, page); |
| 565 | end_page_writeback(page); | 557 | end_page_writeback(page); |
| 566 | 558 | ||
| @@ -618,7 +610,7 @@ static int ceph_writepages_start(struct address_space *mapping, | |||
| 618 | int range_whole = 0; | 610 | int range_whole = 0; |
| 619 | int should_loop = 1; | 611 | int should_loop = 1; |
| 620 | pgoff_t max_pages = 0, max_pages_ever = 0; | 612 | pgoff_t max_pages = 0, max_pages_ever = 0; |
| 621 | struct ceph_snap_context *snapc = NULL, *last_snapc = NULL; | 613 | struct ceph_snap_context *snapc = NULL, *last_snapc = NULL, *pgsnapc; |
| 622 | struct pagevec pvec; | 614 | struct pagevec pvec; |
| 623 | int done = 0; | 615 | int done = 0; |
| 624 | int rc = 0; | 616 | int rc = 0; |
| @@ -770,9 +762,10 @@ get_more_pages: | |||
| 770 | } | 762 | } |
| 771 | 763 | ||
| 772 | /* only if matching snap context */ | 764 | /* only if matching snap context */ |
| 773 | if (snapc != (void *)page->private) { | 765 | pgsnapc = (void *)page->private; |
| 774 | dout("page snapc %p != oldest %p\n", | 766 | if (pgsnapc->seq > snapc->seq) { |
| 775 | (void *)page->private, snapc); | 767 | dout("page snapc %p %lld > oldest %p %lld\n", |
| 768 | pgsnapc, pgsnapc->seq, snapc, snapc->seq); | ||
| 776 | unlock_page(page); | 769 | unlock_page(page); |
| 777 | if (!locked_pages) | 770 | if (!locked_pages) |
| 778 | continue; /* keep looking for snap */ | 771 | continue; /* keep looking for snap */ |
| @@ -914,7 +907,10 @@ static int context_is_writeable_or_written(struct inode *inode, | |||
| 914 | struct ceph_snap_context *snapc) | 907 | struct ceph_snap_context *snapc) |
| 915 | { | 908 | { |
| 916 | struct ceph_snap_context *oldest = get_oldest_context(inode, NULL); | 909 | struct ceph_snap_context *oldest = get_oldest_context(inode, NULL); |
| 917 | return !oldest || snapc->seq <= oldest->seq; | 910 | int ret = !oldest || snapc->seq <= oldest->seq; |
| 911 | |||
| 912 | ceph_put_snap_context(oldest); | ||
| 913 | return ret; | ||
| 918 | } | 914 | } |
| 919 | 915 | ||
| 920 | /* | 916 | /* |
| @@ -936,8 +932,8 @@ static int ceph_update_writeable_page(struct file *file, | |||
| 936 | int pos_in_page = pos & ~PAGE_CACHE_MASK; | 932 | int pos_in_page = pos & ~PAGE_CACHE_MASK; |
| 937 | int end_in_page = pos_in_page + len; | 933 | int end_in_page = pos_in_page + len; |
| 938 | loff_t i_size; | 934 | loff_t i_size; |
| 939 | struct ceph_snap_context *snapc; | ||
| 940 | int r; | 935 | int r; |
| 936 | struct ceph_snap_context *snapc, *oldest; | ||
| 941 | 937 | ||
| 942 | retry_locked: | 938 | retry_locked: |
| 943 | /* writepages currently holds page lock, but if we change that later, */ | 939 | /* writepages currently holds page lock, but if we change that later, */ |
| @@ -947,23 +943,24 @@ retry_locked: | |||
| 947 | BUG_ON(!ci->i_snap_realm); | 943 | BUG_ON(!ci->i_snap_realm); |
| 948 | down_read(&mdsc->snap_rwsem); | 944 | down_read(&mdsc->snap_rwsem); |
| 949 | BUG_ON(!ci->i_snap_realm->cached_context); | 945 | BUG_ON(!ci->i_snap_realm->cached_context); |
| 950 | if (page->private && | 946 | snapc = (void *)page->private; |
| 951 | (void *)page->private != ci->i_snap_realm->cached_context) { | 947 | if (snapc && snapc != ci->i_head_snapc) { |
| 952 | /* | 948 | /* |
| 953 | * this page is already dirty in another (older) snap | 949 | * this page is already dirty in another (older) snap |
| 954 | * context! is it writeable now? | 950 | * context! is it writeable now? |
| 955 | */ | 951 | */ |
| 956 | snapc = get_oldest_context(inode, NULL); | 952 | oldest = get_oldest_context(inode, NULL); |
| 957 | up_read(&mdsc->snap_rwsem); | 953 | up_read(&mdsc->snap_rwsem); |
| 958 | 954 | ||
| 959 | if (snapc != (void *)page->private) { | 955 | if (snapc->seq > oldest->seq) { |
| 956 | ceph_put_snap_context(oldest); | ||
| 960 | dout(" page %p snapc %p not current or oldest\n", | 957 | dout(" page %p snapc %p not current or oldest\n", |
| 961 | page, (void *)page->private); | 958 | page, snapc); |
| 962 | /* | 959 | /* |
| 963 | * queue for writeback, and wait for snapc to | 960 | * queue for writeback, and wait for snapc to |
| 964 | * be writeable or written | 961 | * be writeable or written |
| 965 | */ | 962 | */ |
| 966 | snapc = ceph_get_snap_context((void *)page->private); | 963 | snapc = ceph_get_snap_context(snapc); |
| 967 | unlock_page(page); | 964 | unlock_page(page); |
| 968 | ceph_queue_writeback(inode); | 965 | ceph_queue_writeback(inode); |
| 969 | r = wait_event_interruptible(ci->i_cap_wq, | 966 | r = wait_event_interruptible(ci->i_cap_wq, |
| @@ -973,6 +970,7 @@ retry_locked: | |||
| 973 | return r; | 970 | return r; |
| 974 | return -EAGAIN; | 971 | return -EAGAIN; |
| 975 | } | 972 | } |
| 973 | ceph_put_snap_context(oldest); | ||
| 976 | 974 | ||
| 977 | /* yay, writeable, do it now (without dropping page lock) */ | 975 | /* yay, writeable, do it now (without dropping page lock) */ |
| 978 | dout(" page %p snapc %p not current, but oldest\n", | 976 | dout(" page %p snapc %p not current, but oldest\n", |
diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index 3710e077a857..aa2239fa9a3b 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c | |||
| @@ -1205,6 +1205,12 @@ retry: | |||
| 1205 | if (capsnap->dirty_pages || capsnap->writing) | 1205 | if (capsnap->dirty_pages || capsnap->writing) |
| 1206 | continue; | 1206 | continue; |
| 1207 | 1207 | ||
| 1208 | /* | ||
| 1209 | * if cap writeback already occurred, we should have dropped | ||
| 1210 | * the capsnap in ceph_put_wrbuffer_cap_refs. | ||
| 1211 | */ | ||
| 1212 | BUG_ON(capsnap->dirty == 0); | ||
| 1213 | |||
| 1208 | /* pick mds, take s_mutex */ | 1214 | /* pick mds, take s_mutex */ |
| 1209 | mds = __ceph_get_cap_mds(ci, &mseq); | 1215 | mds = __ceph_get_cap_mds(ci, &mseq); |
| 1210 | if (session && session->s_mds != mds) { | 1216 | if (session && session->s_mds != mds) { |
| @@ -2118,8 +2124,8 @@ void ceph_put_cap_refs(struct ceph_inode_info *ci, int had) | |||
| 2118 | } | 2124 | } |
| 2119 | spin_unlock(&inode->i_lock); | 2125 | spin_unlock(&inode->i_lock); |
| 2120 | 2126 | ||
| 2121 | dout("put_cap_refs %p had %s %s\n", inode, ceph_cap_string(had), | 2127 | dout("put_cap_refs %p had %s%s%s\n", inode, ceph_cap_string(had), |
| 2122 | last ? "last" : ""); | 2128 | last ? " last" : "", put ? " put" : ""); |
| 2123 | 2129 | ||
| 2124 | if (last && !flushsnaps) | 2130 | if (last && !flushsnaps) |
| 2125 | ceph_check_caps(ci, 0, NULL); | 2131 | ceph_check_caps(ci, 0, NULL); |
| @@ -2143,7 +2149,8 @@ void ceph_put_wrbuffer_cap_refs(struct ceph_inode_info *ci, int nr, | |||
| 2143 | { | 2149 | { |
| 2144 | struct inode *inode = &ci->vfs_inode; | 2150 | struct inode *inode = &ci->vfs_inode; |
| 2145 | int last = 0; | 2151 | int last = 0; |
| 2146 | int last_snap = 0; | 2152 | int complete_capsnap = 0; |
| 2153 | int drop_capsnap = 0; | ||
| 2147 | int found = 0; | 2154 | int found = 0; |
| 2148 | struct ceph_cap_snap *capsnap = NULL; | 2155 | struct ceph_cap_snap *capsnap = NULL; |
| 2149 | 2156 | ||
| @@ -2166,19 +2173,32 @@ void ceph_put_wrbuffer_cap_refs(struct ceph_inode_info *ci, int nr, | |||
| 2166 | list_for_each_entry(capsnap, &ci->i_cap_snaps, ci_item) { | 2173 | list_for_each_entry(capsnap, &ci->i_cap_snaps, ci_item) { |
| 2167 | if (capsnap->context == snapc) { | 2174 | if (capsnap->context == snapc) { |
| 2168 | found = 1; | 2175 | found = 1; |
| 2169 | capsnap->dirty_pages -= nr; | ||
| 2170 | last_snap = !capsnap->dirty_pages; | ||
| 2171 | break; | 2176 | break; |
| 2172 | } | 2177 | } |
| 2173 | } | 2178 | } |
| 2174 | BUG_ON(!found); | 2179 | BUG_ON(!found); |
| 2180 | capsnap->dirty_pages -= nr; | ||
| 2181 | if (capsnap->dirty_pages == 0) { | ||
| 2182 | complete_capsnap = 1; | ||
| 2183 | if (capsnap->dirty == 0) | ||
| 2184 | /* cap writeback completed before we created | ||
| 2185 | * the cap_snap; no FLUSHSNAP is needed */ | ||
| 2186 | drop_capsnap = 1; | ||
| 2187 | } | ||
| 2175 | dout("put_wrbuffer_cap_refs on %p cap_snap %p " | 2188 | dout("put_wrbuffer_cap_refs on %p cap_snap %p " |
| 2176 | " snap %lld %d/%d -> %d/%d %s%s\n", | 2189 | " snap %lld %d/%d -> %d/%d %s%s%s\n", |
| 2177 | inode, capsnap, capsnap->context->seq, | 2190 | inode, capsnap, capsnap->context->seq, |
| 2178 | ci->i_wrbuffer_ref+nr, capsnap->dirty_pages + nr, | 2191 | ci->i_wrbuffer_ref+nr, capsnap->dirty_pages + nr, |
| 2179 | ci->i_wrbuffer_ref, capsnap->dirty_pages, | 2192 | ci->i_wrbuffer_ref, capsnap->dirty_pages, |
| 2180 | last ? " (wrbuffer last)" : "", | 2193 | last ? " (wrbuffer last)" : "", |
| 2181 | last_snap ? " (capsnap last)" : ""); | 2194 | complete_capsnap ? " (complete capsnap)" : "", |
| 2195 | drop_capsnap ? " (drop capsnap)" : ""); | ||
| 2196 | if (drop_capsnap) { | ||
| 2197 | ceph_put_snap_context(capsnap->context); | ||
| 2198 | list_del(&capsnap->ci_item); | ||
| 2199 | list_del(&capsnap->flushing_item); | ||
| 2200 | ceph_put_cap_snap(capsnap); | ||
| 2201 | } | ||
| 2182 | } | 2202 | } |
| 2183 | 2203 | ||
| 2184 | spin_unlock(&inode->i_lock); | 2204 | spin_unlock(&inode->i_lock); |
| @@ -2186,10 +2206,12 @@ void ceph_put_wrbuffer_cap_refs(struct ceph_inode_info *ci, int nr, | |||
| 2186 | if (last) { | 2206 | if (last) { |
| 2187 | ceph_check_caps(ci, CHECK_CAPS_AUTHONLY, NULL); | 2207 | ceph_check_caps(ci, CHECK_CAPS_AUTHONLY, NULL); |
| 2188 | iput(inode); | 2208 | iput(inode); |
| 2189 | } else if (last_snap) { | 2209 | } else if (complete_capsnap) { |
| 2190 | ceph_flush_snaps(ci); | 2210 | ceph_flush_snaps(ci); |
| 2191 | wake_up(&ci->i_cap_wq); | 2211 | wake_up(&ci->i_cap_wq); |
| 2192 | } | 2212 | } |
| 2213 | if (drop_capsnap) | ||
| 2214 | iput(inode); | ||
| 2193 | } | 2215 | } |
| 2194 | 2216 | ||
| 2195 | /* | 2217 | /* |
| @@ -2465,8 +2487,8 @@ static void handle_cap_flushsnap_ack(struct inode *inode, u64 flush_tid, | |||
| 2465 | break; | 2487 | break; |
| 2466 | } | 2488 | } |
| 2467 | WARN_ON(capsnap->dirty_pages || capsnap->writing); | 2489 | WARN_ON(capsnap->dirty_pages || capsnap->writing); |
| 2468 | dout(" removing cap_snap %p follows %lld\n", | 2490 | dout(" removing %p cap_snap %p follows %lld\n", |
| 2469 | capsnap, follows); | 2491 | inode, capsnap, follows); |
| 2470 | ceph_put_snap_context(capsnap->context); | 2492 | ceph_put_snap_context(capsnap->context); |
| 2471 | list_del(&capsnap->ci_item); | 2493 | list_del(&capsnap->ci_item); |
| 2472 | list_del(&capsnap->flushing_item); | 2494 | list_del(&capsnap->flushing_item); |
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 7261dc6c2ead..ea8ee2e526aa 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c | |||
| @@ -171,11 +171,11 @@ more: | |||
| 171 | spin_lock(&inode->i_lock); | 171 | spin_lock(&inode->i_lock); |
| 172 | spin_lock(&dcache_lock); | 172 | spin_lock(&dcache_lock); |
| 173 | 173 | ||
| 174 | last = dentry; | ||
| 175 | |||
| 174 | if (err < 0) | 176 | if (err < 0) |
| 175 | goto out_unlock; | 177 | goto out_unlock; |
| 176 | 178 | ||
| 177 | last = dentry; | ||
| 178 | |||
| 179 | p = p->prev; | 179 | p = p->prev; |
| 180 | filp->f_pos++; | 180 | filp->f_pos++; |
| 181 | 181 | ||
| @@ -312,7 +312,7 @@ more: | |||
| 312 | req->r_readdir_offset = fi->next_offset; | 312 | req->r_readdir_offset = fi->next_offset; |
| 313 | req->r_args.readdir.frag = cpu_to_le32(frag); | 313 | req->r_args.readdir.frag = cpu_to_le32(frag); |
| 314 | req->r_args.readdir.max_entries = cpu_to_le32(max_entries); | 314 | req->r_args.readdir.max_entries = cpu_to_le32(max_entries); |
| 315 | req->r_num_caps = max_entries; | 315 | req->r_num_caps = max_entries + 1; |
| 316 | err = ceph_mdsc_do_request(mdsc, NULL, req); | 316 | err = ceph_mdsc_do_request(mdsc, NULL, req); |
| 317 | if (err < 0) { | 317 | if (err < 0) { |
| 318 | ceph_mdsc_put_request(req); | 318 | ceph_mdsc_put_request(req); |
| @@ -489,6 +489,7 @@ struct dentry *ceph_finish_lookup(struct ceph_mds_request *req, | |||
| 489 | struct inode *inode = ceph_get_snapdir(parent); | 489 | struct inode *inode = ceph_get_snapdir(parent); |
| 490 | dout("ENOENT on snapdir %p '%.*s', linking to snapdir %p\n", | 490 | dout("ENOENT on snapdir %p '%.*s', linking to snapdir %p\n", |
| 491 | dentry, dentry->d_name.len, dentry->d_name.name, inode); | 491 | dentry, dentry->d_name.len, dentry->d_name.name, inode); |
| 492 | BUG_ON(!d_unhashed(dentry)); | ||
| 492 | d_add(dentry, inode); | 493 | d_add(dentry, inode); |
| 493 | err = 0; | 494 | err = 0; |
| 494 | } | 495 | } |
diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index aca82d55cc53..26f883c275e8 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c | |||
| @@ -886,6 +886,7 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req, | |||
| 886 | struct inode *in = NULL; | 886 | struct inode *in = NULL; |
| 887 | struct ceph_mds_reply_inode *ininfo; | 887 | struct ceph_mds_reply_inode *ininfo; |
| 888 | struct ceph_vino vino; | 888 | struct ceph_vino vino; |
| 889 | struct ceph_client *client = ceph_sb_to_client(sb); | ||
| 889 | int i = 0; | 890 | int i = 0; |
| 890 | int err = 0; | 891 | int err = 0; |
| 891 | 892 | ||
| @@ -949,7 +950,14 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req, | |||
| 949 | return err; | 950 | return err; |
| 950 | } | 951 | } |
| 951 | 952 | ||
| 952 | if (rinfo->head->is_dentry && !req->r_aborted) { | 953 | /* |
| 954 | * ignore null lease/binding on snapdir ENOENT, or else we | ||
| 955 | * will have trouble splicing in the virtual snapdir later | ||
| 956 | */ | ||
| 957 | if (rinfo->head->is_dentry && !req->r_aborted && | ||
| 958 | (rinfo->head->is_target || strncmp(req->r_dentry->d_name.name, | ||
| 959 | client->mount_args->snapdir_name, | ||
| 960 | req->r_dentry->d_name.len))) { | ||
| 953 | /* | 961 | /* |
| 954 | * lookup link rename : null -> possibly existing inode | 962 | * lookup link rename : null -> possibly existing inode |
| 955 | * mknod symlink mkdir : null -> new inode | 963 | * mknod symlink mkdir : null -> new inode |
diff --git a/fs/ceph/messenger.c b/fs/ceph/messenger.c index 8f1715ffbe4b..cdaaa131add3 100644 --- a/fs/ceph/messenger.c +++ b/fs/ceph/messenger.c | |||
| @@ -30,6 +30,10 @@ static char tag_msg = CEPH_MSGR_TAG_MSG; | |||
| 30 | static char tag_ack = CEPH_MSGR_TAG_ACK; | 30 | static char tag_ack = CEPH_MSGR_TAG_ACK; |
| 31 | static char tag_keepalive = CEPH_MSGR_TAG_KEEPALIVE; | 31 | static char tag_keepalive = CEPH_MSGR_TAG_KEEPALIVE; |
| 32 | 32 | ||
| 33 | #ifdef CONFIG_LOCKDEP | ||
| 34 | static struct lock_class_key socket_class; | ||
| 35 | #endif | ||
| 36 | |||
| 33 | 37 | ||
| 34 | static void queue_con(struct ceph_connection *con); | 38 | static void queue_con(struct ceph_connection *con); |
| 35 | static void con_work(struct work_struct *); | 39 | static void con_work(struct work_struct *); |
| @@ -228,6 +232,10 @@ static struct socket *ceph_tcp_connect(struct ceph_connection *con) | |||
| 228 | con->sock = sock; | 232 | con->sock = sock; |
| 229 | sock->sk->sk_allocation = GFP_NOFS; | 233 | sock->sk->sk_allocation = GFP_NOFS; |
| 230 | 234 | ||
| 235 | #ifdef CONFIG_LOCKDEP | ||
| 236 | lockdep_set_class(&sock->sk->sk_lock, &socket_class); | ||
| 237 | #endif | ||
| 238 | |||
| 231 | set_sock_callbacks(sock, con); | 239 | set_sock_callbacks(sock, con); |
| 232 | 240 | ||
| 233 | dout("connect %s\n", pr_addr(&con->peer_addr.in_addr)); | 241 | dout("connect %s\n", pr_addr(&con->peer_addr.in_addr)); |
| @@ -333,6 +341,7 @@ static void reset_connection(struct ceph_connection *con) | |||
| 333 | con->out_msg = NULL; | 341 | con->out_msg = NULL; |
| 334 | } | 342 | } |
| 335 | con->in_seq = 0; | 343 | con->in_seq = 0; |
| 344 | con->in_seq_acked = 0; | ||
| 336 | } | 345 | } |
| 337 | 346 | ||
| 338 | /* | 347 | /* |
diff --git a/fs/ceph/osdmap.c b/fs/ceph/osdmap.c index 21c6623c4b07..2e2c15eed82a 100644 --- a/fs/ceph/osdmap.c +++ b/fs/ceph/osdmap.c | |||
| @@ -314,71 +314,6 @@ bad: | |||
| 314 | return ERR_PTR(err); | 314 | return ERR_PTR(err); |
| 315 | } | 315 | } |
| 316 | 316 | ||
| 317 | |||
| 318 | /* | ||
| 319 | * osd map | ||
| 320 | */ | ||
| 321 | void ceph_osdmap_destroy(struct ceph_osdmap *map) | ||
| 322 | { | ||
| 323 | dout("osdmap_destroy %p\n", map); | ||
| 324 | if (map->crush) | ||
| 325 | crush_destroy(map->crush); | ||
| 326 | while (!RB_EMPTY_ROOT(&map->pg_temp)) { | ||
| 327 | struct ceph_pg_mapping *pg = | ||
| 328 | rb_entry(rb_first(&map->pg_temp), | ||
| 329 | struct ceph_pg_mapping, node); | ||
| 330 | rb_erase(&pg->node, &map->pg_temp); | ||
| 331 | kfree(pg); | ||
| 332 | } | ||
| 333 | while (!RB_EMPTY_ROOT(&map->pg_pools)) { | ||
| 334 | struct ceph_pg_pool_info *pi = | ||
| 335 | rb_entry(rb_first(&map->pg_pools), | ||
| 336 | struct ceph_pg_pool_info, node); | ||
| 337 | rb_erase(&pi->node, &map->pg_pools); | ||
| 338 | kfree(pi); | ||
| 339 | } | ||
| 340 | kfree(map->osd_state); | ||
| 341 | kfree(map->osd_weight); | ||
| 342 | kfree(map->osd_addr); | ||
| 343 | kfree(map); | ||
| 344 | } | ||
| 345 | |||
| 346 | /* | ||
| 347 | * adjust max osd value. reallocate arrays. | ||
| 348 | */ | ||
| 349 | static int osdmap_set_max_osd(struct ceph_osdmap *map, int max) | ||
| 350 | { | ||
| 351 | u8 *state; | ||
| 352 | struct ceph_entity_addr *addr; | ||
| 353 | u32 *weight; | ||
| 354 | |||
| 355 | state = kcalloc(max, sizeof(*state), GFP_NOFS); | ||
| 356 | addr = kcalloc(max, sizeof(*addr), GFP_NOFS); | ||
| 357 | weight = kcalloc(max, sizeof(*weight), GFP_NOFS); | ||
| 358 | if (state == NULL || addr == NULL || weight == NULL) { | ||
| 359 | kfree(state); | ||
| 360 | kfree(addr); | ||
| 361 | kfree(weight); | ||
| 362 | return -ENOMEM; | ||
| 363 | } | ||
| 364 | |||
| 365 | /* copy old? */ | ||
| 366 | if (map->osd_state) { | ||
| 367 | memcpy(state, map->osd_state, map->max_osd*sizeof(*state)); | ||
| 368 | memcpy(addr, map->osd_addr, map->max_osd*sizeof(*addr)); | ||
| 369 | memcpy(weight, map->osd_weight, map->max_osd*sizeof(*weight)); | ||
| 370 | kfree(map->osd_state); | ||
| 371 | kfree(map->osd_addr); | ||
| 372 | kfree(map->osd_weight); | ||
| 373 | } | ||
| 374 | |||
| 375 | map->osd_state = state; | ||
| 376 | map->osd_weight = weight; | ||
| 377 | map->osd_addr = addr; | ||
| 378 | map->max_osd = max; | ||
| 379 | return 0; | ||
| 380 | } | ||
| 381 | |||
| 382 | /* | 317 | /* |
| 383 | * rbtree of pg_mapping for handling pg_temp (explicit mapping of pgid | 318 | * rbtree of pg_mapping for handling pg_temp (explicit mapping of pgid |
| 384 | * to a set of osds) | 319 | * to a set of osds) |
| @@ -482,6 +417,13 @@ static struct ceph_pg_pool_info *__lookup_pg_pool(struct rb_root *root, int id) | |||
| 482 | return NULL; | 417 | return NULL; |
| 483 | } | 418 | } |
| 484 | 419 | ||
| 420 | static void __remove_pg_pool(struct rb_root *root, struct ceph_pg_pool_info *pi) | ||
| 421 | { | ||
| 422 | rb_erase(&pi->node, root); | ||
| 423 | kfree(pi->name); | ||
| 424 | kfree(pi); | ||
| 425 | } | ||
| 426 | |||
| 485 | void __decode_pool(void **p, struct ceph_pg_pool_info *pi) | 427 | void __decode_pool(void **p, struct ceph_pg_pool_info *pi) |
| 486 | { | 428 | { |
| 487 | ceph_decode_copy(p, &pi->v, sizeof(pi->v)); | 429 | ceph_decode_copy(p, &pi->v, sizeof(pi->v)); |
| @@ -490,6 +432,98 @@ void __decode_pool(void **p, struct ceph_pg_pool_info *pi) | |||
| 490 | *p += le32_to_cpu(pi->v.num_removed_snap_intervals) * sizeof(u64) * 2; | 432 | *p += le32_to_cpu(pi->v.num_removed_snap_intervals) * sizeof(u64) * 2; |
| 491 | } | 433 | } |
| 492 | 434 | ||
| 435 | static int __decode_pool_names(void **p, void *end, struct ceph_osdmap *map) | ||
| 436 | { | ||
| 437 | struct ceph_pg_pool_info *pi; | ||
| 438 | u32 num, len, pool; | ||
| 439 | |||
| 440 | ceph_decode_32_safe(p, end, num, bad); | ||
| 441 | dout(" %d pool names\n", num); | ||
| 442 | while (num--) { | ||
| 443 | ceph_decode_32_safe(p, end, pool, bad); | ||
| 444 | ceph_decode_32_safe(p, end, len, bad); | ||
| 445 | dout(" pool %d len %d\n", pool, len); | ||
| 446 | pi = __lookup_pg_pool(&map->pg_pools, pool); | ||
| 447 | if (pi) { | ||
| 448 | kfree(pi->name); | ||
| 449 | pi->name = kmalloc(len + 1, GFP_NOFS); | ||
| 450 | if (pi->name) { | ||
| 451 | memcpy(pi->name, *p, len); | ||
| 452 | pi->name[len] = '\0'; | ||
| 453 | dout(" name is %s\n", pi->name); | ||
| 454 | } | ||
| 455 | } | ||
| 456 | *p += len; | ||
| 457 | } | ||
| 458 | return 0; | ||
| 459 | |||
| 460 | bad: | ||
| 461 | return -EINVAL; | ||
| 462 | } | ||
| 463 | |||
| 464 | /* | ||
| 465 | * osd map | ||
| 466 | */ | ||
| 467 | void ceph_osdmap_destroy(struct ceph_osdmap *map) | ||
| 468 | { | ||
| 469 | dout("osdmap_destroy %p\n", map); | ||
| 470 | if (map->crush) | ||
| 471 | crush_destroy(map->crush); | ||
| 472 | while (!RB_EMPTY_ROOT(&map->pg_temp)) { | ||
| 473 | struct ceph_pg_mapping *pg = | ||
| 474 | rb_entry(rb_first(&map->pg_temp), | ||
| 475 | struct ceph_pg_mapping, node); | ||
| 476 | rb_erase(&pg->node, &map->pg_temp); | ||
| 477 | kfree(pg); | ||
| 478 | } | ||
| 479 | while (!RB_EMPTY_ROOT(&map->pg_pools)) { | ||
| 480 | struct ceph_pg_pool_info *pi = | ||
| 481 | rb_entry(rb_first(&map->pg_pools), | ||
| 482 | struct ceph_pg_pool_info, node); | ||
| 483 | __remove_pg_pool(&map->pg_pools, pi); | ||
| 484 | } | ||
| 485 | kfree(map->osd_state); | ||
| 486 | kfree(map->osd_weight); | ||
| 487 | kfree(map->osd_addr); | ||
| 488 | kfree(map); | ||
| 489 | } | ||
| 490 | |||
| 491 | /* | ||
| 492 | * adjust max osd value. reallocate arrays. | ||
| 493 | */ | ||
| 494 | static int osdmap_set_max_osd(struct ceph_osdmap *map, int max) | ||
| 495 | { | ||
| 496 | u8 *state; | ||
| 497 | struct ceph_entity_addr *addr; | ||
| 498 | u32 *weight; | ||
| 499 | |||
| 500 | state = kcalloc(max, sizeof(*state), GFP_NOFS); | ||
| 501 | addr = kcalloc(max, sizeof(*addr), GFP_NOFS); | ||
| 502 | weight = kcalloc(max, sizeof(*weight), GFP_NOFS); | ||
| 503 | if (state == NULL || addr == NULL || weight == NULL) { | ||
| 504 | kfree(state); | ||
| 505 | kfree(addr); | ||
| 506 | kfree(weight); | ||
| 507 | return -ENOMEM; | ||
| 508 | } | ||
| 509 | |||
| 510 | /* copy old? */ | ||
| 511 | if (map->osd_state) { | ||
| 512 | memcpy(state, map->osd_state, map->max_osd*sizeof(*state)); | ||
| 513 | memcpy(addr, map->osd_addr, map->max_osd*sizeof(*addr)); | ||
| 514 | memcpy(weight, map->osd_weight, map->max_osd*sizeof(*weight)); | ||
| 515 | kfree(map->osd_state); | ||
| 516 | kfree(map->osd_addr); | ||
| 517 | kfree(map->osd_weight); | ||
| 518 | } | ||
| 519 | |||
| 520 | map->osd_state = state; | ||
| 521 | map->osd_weight = weight; | ||
| 522 | map->osd_addr = addr; | ||
| 523 | map->max_osd = max; | ||
| 524 | return 0; | ||
| 525 | } | ||
| 526 | |||
| 493 | /* | 527 | /* |
| 494 | * decode a full map. | 528 | * decode a full map. |
| 495 | */ | 529 | */ |
| @@ -526,7 +560,7 @@ struct ceph_osdmap *osdmap_decode(void **p, void *end) | |||
| 526 | ceph_decode_32_safe(p, end, max, bad); | 560 | ceph_decode_32_safe(p, end, max, bad); |
| 527 | while (max--) { | 561 | while (max--) { |
| 528 | ceph_decode_need(p, end, 4 + 1 + sizeof(pi->v), bad); | 562 | ceph_decode_need(p, end, 4 + 1 + sizeof(pi->v), bad); |
| 529 | pi = kmalloc(sizeof(*pi), GFP_NOFS); | 563 | pi = kzalloc(sizeof(*pi), GFP_NOFS); |
| 530 | if (!pi) | 564 | if (!pi) |
| 531 | goto bad; | 565 | goto bad; |
| 532 | pi->id = ceph_decode_32(p); | 566 | pi->id = ceph_decode_32(p); |
| @@ -539,6 +573,10 @@ struct ceph_osdmap *osdmap_decode(void **p, void *end) | |||
| 539 | __decode_pool(p, pi); | 573 | __decode_pool(p, pi); |
| 540 | __insert_pg_pool(&map->pg_pools, pi); | 574 | __insert_pg_pool(&map->pg_pools, pi); |
| 541 | } | 575 | } |
| 576 | |||
| 577 | if (version >= 5 && __decode_pool_names(p, end, map) < 0) | ||
| 578 | goto bad; | ||
| 579 | |||
| 542 | ceph_decode_32_safe(p, end, map->pool_max, bad); | 580 | ceph_decode_32_safe(p, end, map->pool_max, bad); |
| 543 | 581 | ||
| 544 | ceph_decode_32_safe(p, end, map->flags, bad); | 582 | ceph_decode_32_safe(p, end, map->flags, bad); |
| @@ -712,7 +750,7 @@ struct ceph_osdmap *osdmap_apply_incremental(void **p, void *end, | |||
| 712 | } | 750 | } |
| 713 | pi = __lookup_pg_pool(&map->pg_pools, pool); | 751 | pi = __lookup_pg_pool(&map->pg_pools, pool); |
| 714 | if (!pi) { | 752 | if (!pi) { |
| 715 | pi = kmalloc(sizeof(*pi), GFP_NOFS); | 753 | pi = kzalloc(sizeof(*pi), GFP_NOFS); |
| 716 | if (!pi) { | 754 | if (!pi) { |
| 717 | err = -ENOMEM; | 755 | err = -ENOMEM; |
| 718 | goto bad; | 756 | goto bad; |
| @@ -722,6 +760,8 @@ struct ceph_osdmap *osdmap_apply_incremental(void **p, void *end, | |||
| 722 | } | 760 | } |
| 723 | __decode_pool(p, pi); | 761 | __decode_pool(p, pi); |
| 724 | } | 762 | } |
| 763 | if (version >= 5 && __decode_pool_names(p, end, map) < 0) | ||
| 764 | goto bad; | ||
| 725 | 765 | ||
| 726 | /* old_pool */ | 766 | /* old_pool */ |
| 727 | ceph_decode_32_safe(p, end, len, bad); | 767 | ceph_decode_32_safe(p, end, len, bad); |
| @@ -730,10 +770,8 @@ struct ceph_osdmap *osdmap_apply_incremental(void **p, void *end, | |||
| 730 | 770 | ||
| 731 | ceph_decode_32_safe(p, end, pool, bad); | 771 | ceph_decode_32_safe(p, end, pool, bad); |
| 732 | pi = __lookup_pg_pool(&map->pg_pools, pool); | 772 | pi = __lookup_pg_pool(&map->pg_pools, pool); |
| 733 | if (pi) { | 773 | if (pi) |
| 734 | rb_erase(&pi->node, &map->pg_pools); | 774 | __remove_pg_pool(&map->pg_pools, pi); |
| 735 | kfree(pi); | ||
| 736 | } | ||
| 737 | } | 775 | } |
| 738 | 776 | ||
| 739 | /* new_up */ | 777 | /* new_up */ |
diff --git a/fs/ceph/osdmap.h b/fs/ceph/osdmap.h index 1fb55afb2642..8bc9f1e4f562 100644 --- a/fs/ceph/osdmap.h +++ b/fs/ceph/osdmap.h | |||
| @@ -23,6 +23,7 @@ struct ceph_pg_pool_info { | |||
| 23 | int id; | 23 | int id; |
| 24 | struct ceph_pg_pool v; | 24 | struct ceph_pg_pool v; |
| 25 | int pg_num_mask, pgp_num_mask, lpg_num_mask, lpgp_num_mask; | 25 | int pg_num_mask, pgp_num_mask, lpg_num_mask, lpgp_num_mask; |
| 26 | char *name; | ||
| 26 | }; | 27 | }; |
| 27 | 28 | ||
| 28 | struct ceph_pg_mapping { | 29 | struct ceph_pg_mapping { |
diff --git a/fs/ceph/rados.h b/fs/ceph/rados.h index 26ac8b89a676..a1fc1d017b58 100644 --- a/fs/ceph/rados.h +++ b/fs/ceph/rados.h | |||
| @@ -11,8 +11,10 @@ | |||
| 11 | /* | 11 | /* |
| 12 | * osdmap encoding versions | 12 | * osdmap encoding versions |
| 13 | */ | 13 | */ |
| 14 | #define CEPH_OSDMAP_INC_VERSION 4 | 14 | #define CEPH_OSDMAP_INC_VERSION 5 |
| 15 | #define CEPH_OSDMAP_VERSION 4 | 15 | #define CEPH_OSDMAP_INC_VERSION_EXT 5 |
| 16 | #define CEPH_OSDMAP_VERSION 5 | ||
| 17 | #define CEPH_OSDMAP_VERSION_EXT 5 | ||
| 16 | 18 | ||
| 17 | /* | 19 | /* |
| 18 | * fs id | 20 | * fs id |
diff --git a/fs/ceph/snap.c b/fs/ceph/snap.c index e6f9bc57d472..2b881262ef67 100644 --- a/fs/ceph/snap.c +++ b/fs/ceph/snap.c | |||
| @@ -431,8 +431,7 @@ static int dup_array(u64 **dst, __le64 *src, int num) | |||
| 431 | * Caller must hold snap_rwsem for read (i.e., the realm topology won't | 431 | * Caller must hold snap_rwsem for read (i.e., the realm topology won't |
| 432 | * change). | 432 | * change). |
| 433 | */ | 433 | */ |
| 434 | void ceph_queue_cap_snap(struct ceph_inode_info *ci, | 434 | void ceph_queue_cap_snap(struct ceph_inode_info *ci) |
| 435 | struct ceph_snap_context *snapc) | ||
| 436 | { | 435 | { |
| 437 | struct inode *inode = &ci->vfs_inode; | 436 | struct inode *inode = &ci->vfs_inode; |
| 438 | struct ceph_cap_snap *capsnap; | 437 | struct ceph_cap_snap *capsnap; |
| @@ -451,10 +450,11 @@ void ceph_queue_cap_snap(struct ceph_inode_info *ci, | |||
| 451 | as no new writes are allowed to start when pending, so any | 450 | as no new writes are allowed to start when pending, so any |
| 452 | writes in progress now were started before the previous | 451 | writes in progress now were started before the previous |
| 453 | cap_snap. lucky us. */ | 452 | cap_snap. lucky us. */ |
| 454 | dout("queue_cap_snap %p snapc %p seq %llu used %d" | 453 | dout("queue_cap_snap %p already pending\n", inode); |
| 455 | " already pending\n", inode, snapc, snapc->seq, used); | ||
| 456 | kfree(capsnap); | 454 | kfree(capsnap); |
| 457 | } else if (ci->i_wrbuffer_ref_head || (used & CEPH_CAP_FILE_WR)) { | 455 | } else if (ci->i_wrbuffer_ref_head || (used & CEPH_CAP_FILE_WR)) { |
| 456 | struct ceph_snap_context *snapc = ci->i_head_snapc; | ||
| 457 | |||
| 458 | igrab(inode); | 458 | igrab(inode); |
| 459 | 459 | ||
| 460 | atomic_set(&capsnap->nref, 1); | 460 | atomic_set(&capsnap->nref, 1); |
| @@ -463,7 +463,6 @@ void ceph_queue_cap_snap(struct ceph_inode_info *ci, | |||
| 463 | INIT_LIST_HEAD(&capsnap->flushing_item); | 463 | INIT_LIST_HEAD(&capsnap->flushing_item); |
| 464 | 464 | ||
| 465 | capsnap->follows = snapc->seq - 1; | 465 | capsnap->follows = snapc->seq - 1; |
| 466 | capsnap->context = ceph_get_snap_context(snapc); | ||
| 467 | capsnap->issued = __ceph_caps_issued(ci, NULL); | 466 | capsnap->issued = __ceph_caps_issued(ci, NULL); |
| 468 | capsnap->dirty = __ceph_caps_dirty(ci); | 467 | capsnap->dirty = __ceph_caps_dirty(ci); |
| 469 | 468 | ||
| @@ -480,7 +479,7 @@ void ceph_queue_cap_snap(struct ceph_inode_info *ci, | |||
| 480 | snapshot. */ | 479 | snapshot. */ |
| 481 | capsnap->dirty_pages = ci->i_wrbuffer_ref_head; | 480 | capsnap->dirty_pages = ci->i_wrbuffer_ref_head; |
| 482 | ci->i_wrbuffer_ref_head = 0; | 481 | ci->i_wrbuffer_ref_head = 0; |
| 483 | ceph_put_snap_context(ci->i_head_snapc); | 482 | capsnap->context = snapc; |
| 484 | ci->i_head_snapc = NULL; | 483 | ci->i_head_snapc = NULL; |
| 485 | list_add_tail(&capsnap->ci_item, &ci->i_cap_snaps); | 484 | list_add_tail(&capsnap->ci_item, &ci->i_cap_snaps); |
| 486 | 485 | ||
| @@ -522,15 +521,17 @@ int __ceph_finish_cap_snap(struct ceph_inode_info *ci, | |||
| 522 | capsnap->ctime = inode->i_ctime; | 521 | capsnap->ctime = inode->i_ctime; |
| 523 | capsnap->time_warp_seq = ci->i_time_warp_seq; | 522 | capsnap->time_warp_seq = ci->i_time_warp_seq; |
| 524 | if (capsnap->dirty_pages) { | 523 | if (capsnap->dirty_pages) { |
| 525 | dout("finish_cap_snap %p cap_snap %p snapc %p %llu s=%llu " | 524 | dout("finish_cap_snap %p cap_snap %p snapc %p %llu %s s=%llu " |
| 526 | "still has %d dirty pages\n", inode, capsnap, | 525 | "still has %d dirty pages\n", inode, capsnap, |
| 527 | capsnap->context, capsnap->context->seq, | 526 | capsnap->context, capsnap->context->seq, |
| 528 | capsnap->size, capsnap->dirty_pages); | 527 | ceph_cap_string(capsnap->dirty), capsnap->size, |
| 528 | capsnap->dirty_pages); | ||
| 529 | return 0; | 529 | return 0; |
| 530 | } | 530 | } |
| 531 | dout("finish_cap_snap %p cap_snap %p snapc %p %llu s=%llu clean\n", | 531 | dout("finish_cap_snap %p cap_snap %p snapc %p %llu %s s=%llu\n", |
| 532 | inode, capsnap, capsnap->context, | 532 | inode, capsnap, capsnap->context, |
| 533 | capsnap->context->seq, capsnap->size); | 533 | capsnap->context->seq, ceph_cap_string(capsnap->dirty), |
| 534 | capsnap->size); | ||
| 534 | 535 | ||
| 535 | spin_lock(&mdsc->snap_flush_lock); | 536 | spin_lock(&mdsc->snap_flush_lock); |
| 536 | list_add_tail(&ci->i_snap_flush_item, &mdsc->snap_flush_list); | 537 | list_add_tail(&ci->i_snap_flush_item, &mdsc->snap_flush_list); |
| @@ -602,7 +603,7 @@ more: | |||
| 602 | if (lastinode) | 603 | if (lastinode) |
| 603 | iput(lastinode); | 604 | iput(lastinode); |
| 604 | lastinode = inode; | 605 | lastinode = inode; |
| 605 | ceph_queue_cap_snap(ci, realm->cached_context); | 606 | ceph_queue_cap_snap(ci); |
| 606 | spin_lock(&realm->inodes_with_caps_lock); | 607 | spin_lock(&realm->inodes_with_caps_lock); |
| 607 | } | 608 | } |
| 608 | spin_unlock(&realm->inodes_with_caps_lock); | 609 | spin_unlock(&realm->inodes_with_caps_lock); |
| @@ -824,8 +825,7 @@ void ceph_handle_snap(struct ceph_mds_client *mdsc, | |||
| 824 | spin_unlock(&realm->inodes_with_caps_lock); | 825 | spin_unlock(&realm->inodes_with_caps_lock); |
| 825 | spin_unlock(&inode->i_lock); | 826 | spin_unlock(&inode->i_lock); |
| 826 | 827 | ||
| 827 | ceph_queue_cap_snap(ci, | 828 | ceph_queue_cap_snap(ci); |
| 828 | ci->i_snap_realm->cached_context); | ||
| 829 | 829 | ||
| 830 | iput(inode); | 830 | iput(inode); |
| 831 | continue; | 831 | continue; |
diff --git a/fs/ceph/super.h b/fs/ceph/super.h index ca702c67bc66..e30dfbb056c3 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h | |||
| @@ -715,8 +715,7 @@ extern int ceph_update_snap_trace(struct ceph_mds_client *m, | |||
| 715 | extern void ceph_handle_snap(struct ceph_mds_client *mdsc, | 715 | extern void ceph_handle_snap(struct ceph_mds_client *mdsc, |
| 716 | struct ceph_mds_session *session, | 716 | struct ceph_mds_session *session, |
| 717 | struct ceph_msg *msg); | 717 | struct ceph_msg *msg); |
| 718 | extern void ceph_queue_cap_snap(struct ceph_inode_info *ci, | 718 | extern void ceph_queue_cap_snap(struct ceph_inode_info *ci); |
| 719 | struct ceph_snap_context *snapc); | ||
| 720 | extern int __ceph_finish_cap_snap(struct ceph_inode_info *ci, | 719 | extern int __ceph_finish_cap_snap(struct ceph_inode_info *ci, |
| 721 | struct ceph_cap_snap *capsnap); | 720 | struct ceph_cap_snap *capsnap); |
| 722 | extern void ceph_cleanup_empty_realms(struct ceph_mds_client *mdsc); | 721 | extern void ceph_cleanup_empty_realms(struct ceph_mds_client *mdsc); |
diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c index efb2b9400391..1cc087635a5e 100644 --- a/fs/ecryptfs/crypto.c +++ b/fs/ecryptfs/crypto.c | |||
| @@ -382,8 +382,8 @@ out: | |||
| 382 | static void ecryptfs_lower_offset_for_extent(loff_t *offset, loff_t extent_num, | 382 | static void ecryptfs_lower_offset_for_extent(loff_t *offset, loff_t extent_num, |
| 383 | struct ecryptfs_crypt_stat *crypt_stat) | 383 | struct ecryptfs_crypt_stat *crypt_stat) |
| 384 | { | 384 | { |
| 385 | (*offset) = (crypt_stat->num_header_bytes_at_front | 385 | (*offset) = ecryptfs_lower_header_size(crypt_stat) |
| 386 | + (crypt_stat->extent_size * extent_num)); | 386 | + (crypt_stat->extent_size * extent_num); |
| 387 | } | 387 | } |
| 388 | 388 | ||
| 389 | /** | 389 | /** |
| @@ -835,13 +835,13 @@ void ecryptfs_set_default_sizes(struct ecryptfs_crypt_stat *crypt_stat) | |||
| 835 | set_extent_mask_and_shift(crypt_stat); | 835 | set_extent_mask_and_shift(crypt_stat); |
| 836 | crypt_stat->iv_bytes = ECRYPTFS_DEFAULT_IV_BYTES; | 836 | crypt_stat->iv_bytes = ECRYPTFS_DEFAULT_IV_BYTES; |
| 837 | if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) | 837 | if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) |
| 838 | crypt_stat->num_header_bytes_at_front = 0; | 838 | crypt_stat->metadata_size = ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE; |
| 839 | else { | 839 | else { |
| 840 | if (PAGE_CACHE_SIZE <= ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE) | 840 | if (PAGE_CACHE_SIZE <= ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE) |
| 841 | crypt_stat->num_header_bytes_at_front = | 841 | crypt_stat->metadata_size = |
| 842 | ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE; | 842 | ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE; |
| 843 | else | 843 | else |
| 844 | crypt_stat->num_header_bytes_at_front = PAGE_CACHE_SIZE; | 844 | crypt_stat->metadata_size = PAGE_CACHE_SIZE; |
| 845 | } | 845 | } |
| 846 | } | 846 | } |
| 847 | 847 | ||
| @@ -1108,9 +1108,9 @@ static void write_ecryptfs_marker(char *page_virt, size_t *written) | |||
| 1108 | (*written) = MAGIC_ECRYPTFS_MARKER_SIZE_BYTES; | 1108 | (*written) = MAGIC_ECRYPTFS_MARKER_SIZE_BYTES; |
| 1109 | } | 1109 | } |
| 1110 | 1110 | ||
| 1111 | static void | 1111 | void ecryptfs_write_crypt_stat_flags(char *page_virt, |
| 1112 | write_ecryptfs_flags(char *page_virt, struct ecryptfs_crypt_stat *crypt_stat, | 1112 | struct ecryptfs_crypt_stat *crypt_stat, |
| 1113 | size_t *written) | 1113 | size_t *written) |
| 1114 | { | 1114 | { |
| 1115 | u32 flags = 0; | 1115 | u32 flags = 0; |
| 1116 | int i; | 1116 | int i; |
| @@ -1238,8 +1238,7 @@ ecryptfs_write_header_metadata(char *virt, | |||
| 1238 | 1238 | ||
| 1239 | header_extent_size = (u32)crypt_stat->extent_size; | 1239 | header_extent_size = (u32)crypt_stat->extent_size; |
| 1240 | num_header_extents_at_front = | 1240 | num_header_extents_at_front = |
| 1241 | (u16)(crypt_stat->num_header_bytes_at_front | 1241 | (u16)(crypt_stat->metadata_size / crypt_stat->extent_size); |
| 1242 | / crypt_stat->extent_size); | ||
| 1243 | put_unaligned_be32(header_extent_size, virt); | 1242 | put_unaligned_be32(header_extent_size, virt); |
| 1244 | virt += 4; | 1243 | virt += 4; |
| 1245 | put_unaligned_be16(num_header_extents_at_front, virt); | 1244 | put_unaligned_be16(num_header_extents_at_front, virt); |
| @@ -1292,7 +1291,8 @@ static int ecryptfs_write_headers_virt(char *page_virt, size_t max, | |||
| 1292 | offset = ECRYPTFS_FILE_SIZE_BYTES; | 1291 | offset = ECRYPTFS_FILE_SIZE_BYTES; |
| 1293 | write_ecryptfs_marker((page_virt + offset), &written); | 1292 | write_ecryptfs_marker((page_virt + offset), &written); |
| 1294 | offset += written; | 1293 | offset += written; |
| 1295 | write_ecryptfs_flags((page_virt + offset), crypt_stat, &written); | 1294 | ecryptfs_write_crypt_stat_flags((page_virt + offset), crypt_stat, |
| 1295 | &written); | ||
| 1296 | offset += written; | 1296 | offset += written; |
| 1297 | ecryptfs_write_header_metadata((page_virt + offset), crypt_stat, | 1297 | ecryptfs_write_header_metadata((page_virt + offset), crypt_stat, |
| 1298 | &written); | 1298 | &written); |
| @@ -1382,7 +1382,7 @@ int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry) | |||
| 1382 | rc = -EINVAL; | 1382 | rc = -EINVAL; |
| 1383 | goto out; | 1383 | goto out; |
| 1384 | } | 1384 | } |
| 1385 | virt_len = crypt_stat->num_header_bytes_at_front; | 1385 | virt_len = crypt_stat->metadata_size; |
| 1386 | order = get_order(virt_len); | 1386 | order = get_order(virt_len); |
| 1387 | /* Released in this function */ | 1387 | /* Released in this function */ |
| 1388 | virt = (char *)ecryptfs_get_zeroed_pages(GFP_KERNEL, order); | 1388 | virt = (char *)ecryptfs_get_zeroed_pages(GFP_KERNEL, order); |
| @@ -1428,16 +1428,15 @@ static int parse_header_metadata(struct ecryptfs_crypt_stat *crypt_stat, | |||
| 1428 | header_extent_size = get_unaligned_be32(virt); | 1428 | header_extent_size = get_unaligned_be32(virt); |
| 1429 | virt += sizeof(__be32); | 1429 | virt += sizeof(__be32); |
| 1430 | num_header_extents_at_front = get_unaligned_be16(virt); | 1430 | num_header_extents_at_front = get_unaligned_be16(virt); |
| 1431 | crypt_stat->num_header_bytes_at_front = | 1431 | crypt_stat->metadata_size = (((size_t)num_header_extents_at_front |
| 1432 | (((size_t)num_header_extents_at_front | 1432 | * (size_t)header_extent_size)); |
| 1433 | * (size_t)header_extent_size)); | ||
| 1434 | (*bytes_read) = (sizeof(__be32) + sizeof(__be16)); | 1433 | (*bytes_read) = (sizeof(__be32) + sizeof(__be16)); |
| 1435 | if ((validate_header_size == ECRYPTFS_VALIDATE_HEADER_SIZE) | 1434 | if ((validate_header_size == ECRYPTFS_VALIDATE_HEADER_SIZE) |
| 1436 | && (crypt_stat->num_header_bytes_at_front | 1435 | && (crypt_stat->metadata_size |
| 1437 | < ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE)) { | 1436 | < ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE)) { |
| 1438 | rc = -EINVAL; | 1437 | rc = -EINVAL; |
| 1439 | printk(KERN_WARNING "Invalid header size: [%zd]\n", | 1438 | printk(KERN_WARNING "Invalid header size: [%zd]\n", |
| 1440 | crypt_stat->num_header_bytes_at_front); | 1439 | crypt_stat->metadata_size); |
| 1441 | } | 1440 | } |
| 1442 | return rc; | 1441 | return rc; |
| 1443 | } | 1442 | } |
| @@ -1452,8 +1451,7 @@ static int parse_header_metadata(struct ecryptfs_crypt_stat *crypt_stat, | |||
| 1452 | */ | 1451 | */ |
| 1453 | static void set_default_header_data(struct ecryptfs_crypt_stat *crypt_stat) | 1452 | static void set_default_header_data(struct ecryptfs_crypt_stat *crypt_stat) |
| 1454 | { | 1453 | { |
| 1455 | crypt_stat->num_header_bytes_at_front = | 1454 | crypt_stat->metadata_size = ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE; |
| 1456 | ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE; | ||
| 1457 | } | 1455 | } |
| 1458 | 1456 | ||
| 1459 | /** | 1457 | /** |
| @@ -1607,6 +1605,7 @@ int ecryptfs_read_metadata(struct dentry *ecryptfs_dentry) | |||
| 1607 | ecryptfs_dentry, | 1605 | ecryptfs_dentry, |
| 1608 | ECRYPTFS_VALIDATE_HEADER_SIZE); | 1606 | ECRYPTFS_VALIDATE_HEADER_SIZE); |
| 1609 | if (rc) { | 1607 | if (rc) { |
| 1608 | memset(page_virt, 0, PAGE_CACHE_SIZE); | ||
| 1610 | rc = ecryptfs_read_xattr_region(page_virt, ecryptfs_inode); | 1609 | rc = ecryptfs_read_xattr_region(page_virt, ecryptfs_inode); |
| 1611 | if (rc) { | 1610 | if (rc) { |
| 1612 | printk(KERN_DEBUG "Valid eCryptfs headers not found in " | 1611 | printk(KERN_DEBUG "Valid eCryptfs headers not found in " |
diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h index 542f625312f3..bc7115403f38 100644 --- a/fs/ecryptfs/ecryptfs_kernel.h +++ b/fs/ecryptfs/ecryptfs_kernel.h | |||
| @@ -273,7 +273,7 @@ struct ecryptfs_crypt_stat { | |||
| 273 | u32 flags; | 273 | u32 flags; |
| 274 | unsigned int file_version; | 274 | unsigned int file_version; |
| 275 | size_t iv_bytes; | 275 | size_t iv_bytes; |
| 276 | size_t num_header_bytes_at_front; | 276 | size_t metadata_size; |
| 277 | size_t extent_size; /* Data extent size; default is 4096 */ | 277 | size_t extent_size; /* Data extent size; default is 4096 */ |
| 278 | size_t key_size; | 278 | size_t key_size; |
| 279 | size_t extent_shift; | 279 | size_t extent_shift; |
| @@ -464,6 +464,14 @@ struct ecryptfs_daemon { | |||
| 464 | 464 | ||
| 465 | extern struct mutex ecryptfs_daemon_hash_mux; | 465 | extern struct mutex ecryptfs_daemon_hash_mux; |
| 466 | 466 | ||
| 467 | static inline size_t | ||
| 468 | ecryptfs_lower_header_size(struct ecryptfs_crypt_stat *crypt_stat) | ||
| 469 | { | ||
| 470 | if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) | ||
| 471 | return 0; | ||
| 472 | return crypt_stat->metadata_size; | ||
| 473 | } | ||
| 474 | |||
| 467 | static inline struct ecryptfs_file_info * | 475 | static inline struct ecryptfs_file_info * |
| 468 | ecryptfs_file_to_private(struct file *file) | 476 | ecryptfs_file_to_private(struct file *file) |
| 469 | { | 477 | { |
| @@ -651,6 +659,9 @@ int ecryptfs_decrypt_page(struct page *page); | |||
| 651 | int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry); | 659 | int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry); |
| 652 | int ecryptfs_read_metadata(struct dentry *ecryptfs_dentry); | 660 | int ecryptfs_read_metadata(struct dentry *ecryptfs_dentry); |
| 653 | int ecryptfs_new_file_context(struct dentry *ecryptfs_dentry); | 661 | int ecryptfs_new_file_context(struct dentry *ecryptfs_dentry); |
| 662 | void ecryptfs_write_crypt_stat_flags(char *page_virt, | ||
| 663 | struct ecryptfs_crypt_stat *crypt_stat, | ||
| 664 | size_t *written); | ||
| 654 | int ecryptfs_read_and_validate_header_region(char *data, | 665 | int ecryptfs_read_and_validate_header_region(char *data, |
| 655 | struct inode *ecryptfs_inode); | 666 | struct inode *ecryptfs_inode); |
| 656 | int ecryptfs_read_and_validate_xattr_region(char *page_virt, | 667 | int ecryptfs_read_and_validate_xattr_region(char *page_virt, |
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index d3362faf3852..e2d4418affac 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c | |||
| @@ -324,6 +324,7 @@ int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry, | |||
| 324 | rc = ecryptfs_read_and_validate_header_region(page_virt, | 324 | rc = ecryptfs_read_and_validate_header_region(page_virt, |
| 325 | ecryptfs_dentry->d_inode); | 325 | ecryptfs_dentry->d_inode); |
| 326 | if (rc) { | 326 | if (rc) { |
| 327 | memset(page_virt, 0, PAGE_CACHE_SIZE); | ||
| 327 | rc = ecryptfs_read_and_validate_xattr_region(page_virt, | 328 | rc = ecryptfs_read_and_validate_xattr_region(page_virt, |
| 328 | ecryptfs_dentry); | 329 | ecryptfs_dentry); |
| 329 | if (rc) { | 330 | if (rc) { |
| @@ -336,7 +337,7 @@ int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry, | |||
| 336 | ecryptfs_dentry->d_sb)->mount_crypt_stat; | 337 | ecryptfs_dentry->d_sb)->mount_crypt_stat; |
| 337 | if (mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED) { | 338 | if (mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED) { |
| 338 | if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) | 339 | if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) |
| 339 | file_size = (crypt_stat->num_header_bytes_at_front | 340 | file_size = (crypt_stat->metadata_size |
| 340 | + i_size_read(lower_dentry->d_inode)); | 341 | + i_size_read(lower_dentry->d_inode)); |
| 341 | else | 342 | else |
| 342 | file_size = i_size_read(lower_dentry->d_inode); | 343 | file_size = i_size_read(lower_dentry->d_inode); |
| @@ -388,9 +389,9 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode, | |||
| 388 | mutex_unlock(&lower_dir_dentry->d_inode->i_mutex); | 389 | mutex_unlock(&lower_dir_dentry->d_inode->i_mutex); |
| 389 | if (IS_ERR(lower_dentry)) { | 390 | if (IS_ERR(lower_dentry)) { |
| 390 | rc = PTR_ERR(lower_dentry); | 391 | rc = PTR_ERR(lower_dentry); |
| 391 | printk(KERN_ERR "%s: lookup_one_len() returned [%d] on " | 392 | ecryptfs_printk(KERN_DEBUG, "%s: lookup_one_len() returned " |
| 392 | "lower_dentry = [%s]\n", __func__, rc, | 393 | "[%d] on lower_dentry = [%s]\n", __func__, rc, |
| 393 | ecryptfs_dentry->d_name.name); | 394 | encrypted_and_encoded_name); |
| 394 | goto out_d_drop; | 395 | goto out_d_drop; |
| 395 | } | 396 | } |
| 396 | if (lower_dentry->d_inode) | 397 | if (lower_dentry->d_inode) |
| @@ -417,9 +418,9 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode, | |||
| 417 | mutex_unlock(&lower_dir_dentry->d_inode->i_mutex); | 418 | mutex_unlock(&lower_dir_dentry->d_inode->i_mutex); |
| 418 | if (IS_ERR(lower_dentry)) { | 419 | if (IS_ERR(lower_dentry)) { |
| 419 | rc = PTR_ERR(lower_dentry); | 420 | rc = PTR_ERR(lower_dentry); |
| 420 | printk(KERN_ERR "%s: lookup_one_len() returned [%d] on " | 421 | ecryptfs_printk(KERN_DEBUG, "%s: lookup_one_len() returned " |
| 421 | "lower_dentry = [%s]\n", __func__, rc, | 422 | "[%d] on lower_dentry = [%s]\n", __func__, rc, |
| 422 | encrypted_and_encoded_name); | 423 | encrypted_and_encoded_name); |
| 423 | goto out_d_drop; | 424 | goto out_d_drop; |
| 424 | } | 425 | } |
| 425 | lookup_and_interpose: | 426 | lookup_and_interpose: |
| @@ -456,8 +457,8 @@ static int ecryptfs_link(struct dentry *old_dentry, struct inode *dir, | |||
| 456 | rc = ecryptfs_interpose(lower_new_dentry, new_dentry, dir->i_sb, 0); | 457 | rc = ecryptfs_interpose(lower_new_dentry, new_dentry, dir->i_sb, 0); |
| 457 | if (rc) | 458 | if (rc) |
| 458 | goto out_lock; | 459 | goto out_lock; |
| 459 | fsstack_copy_attr_times(dir, lower_new_dentry->d_inode); | 460 | fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode); |
| 460 | fsstack_copy_inode_size(dir, lower_new_dentry->d_inode); | 461 | fsstack_copy_inode_size(dir, lower_dir_dentry->d_inode); |
| 461 | old_dentry->d_inode->i_nlink = | 462 | old_dentry->d_inode->i_nlink = |
| 462 | ecryptfs_inode_to_lower(old_dentry->d_inode)->i_nlink; | 463 | ecryptfs_inode_to_lower(old_dentry->d_inode)->i_nlink; |
| 463 | i_size_write(new_dentry->d_inode, file_size_save); | 464 | i_size_write(new_dentry->d_inode, file_size_save); |
| @@ -648,38 +649,17 @@ out_lock: | |||
| 648 | return rc; | 649 | return rc; |
| 649 | } | 650 | } |
| 650 | 651 | ||
| 651 | static int | 652 | static int ecryptfs_readlink_lower(struct dentry *dentry, char **buf, |
| 652 | ecryptfs_readlink(struct dentry *dentry, char __user *buf, int bufsiz) | 653 | size_t *bufsiz) |
| 653 | { | 654 | { |
| 655 | struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); | ||
| 654 | char *lower_buf; | 656 | char *lower_buf; |
| 655 | size_t lower_bufsiz; | 657 | size_t lower_bufsiz = PATH_MAX; |
| 656 | struct dentry *lower_dentry; | ||
| 657 | struct ecryptfs_mount_crypt_stat *mount_crypt_stat; | ||
| 658 | char *plaintext_name; | ||
| 659 | size_t plaintext_name_size; | ||
| 660 | mm_segment_t old_fs; | 658 | mm_segment_t old_fs; |
| 661 | int rc; | 659 | int rc; |
| 662 | 660 | ||
| 663 | lower_dentry = ecryptfs_dentry_to_lower(dentry); | ||
| 664 | if (!lower_dentry->d_inode->i_op->readlink) { | ||
| 665 | rc = -EINVAL; | ||
| 666 | goto out; | ||
| 667 | } | ||
| 668 | mount_crypt_stat = &ecryptfs_superblock_to_private( | ||
| 669 | dentry->d_sb)->mount_crypt_stat; | ||
| 670 | /* | ||
| 671 | * If the lower filename is encrypted, it will result in a significantly | ||
| 672 | * longer name. If needed, truncate the name after decode and decrypt. | ||
| 673 | */ | ||
| 674 | if (mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES) | ||
| 675 | lower_bufsiz = PATH_MAX; | ||
| 676 | else | ||
| 677 | lower_bufsiz = bufsiz; | ||
| 678 | /* Released in this function */ | ||
| 679 | lower_buf = kmalloc(lower_bufsiz, GFP_KERNEL); | 661 | lower_buf = kmalloc(lower_bufsiz, GFP_KERNEL); |
| 680 | if (lower_buf == NULL) { | 662 | if (!lower_buf) { |
| 681 | printk(KERN_ERR "%s: Out of memory whilst attempting to " | ||
| 682 | "kmalloc [%zd] bytes\n", __func__, lower_bufsiz); | ||
| 683 | rc = -ENOMEM; | 663 | rc = -ENOMEM; |
| 684 | goto out; | 664 | goto out; |
| 685 | } | 665 | } |
| @@ -689,29 +669,31 @@ ecryptfs_readlink(struct dentry *dentry, char __user *buf, int bufsiz) | |||
| 689 | (char __user *)lower_buf, | 669 | (char __user *)lower_buf, |
| 690 | lower_bufsiz); | 670 | lower_bufsiz); |
| 691 | set_fs(old_fs); | 671 | set_fs(old_fs); |
| 692 | if (rc >= 0) { | 672 | if (rc < 0) |
| 693 | rc = ecryptfs_decode_and_decrypt_filename(&plaintext_name, | 673 | goto out; |
| 694 | &plaintext_name_size, | 674 | lower_bufsiz = rc; |
| 695 | dentry, lower_buf, | 675 | rc = ecryptfs_decode_and_decrypt_filename(buf, bufsiz, dentry, |
| 696 | rc); | 676 | lower_buf, lower_bufsiz); |
| 697 | if (rc) { | 677 | out: |
| 698 | printk(KERN_ERR "%s: Error attempting to decode and " | ||
| 699 | "decrypt filename; rc = [%d]\n", __func__, | ||
| 700 | rc); | ||
| 701 | goto out_free_lower_buf; | ||
| 702 | } | ||
| 703 | /* Check for bufsiz <= 0 done in sys_readlinkat() */ | ||
| 704 | rc = copy_to_user(buf, plaintext_name, | ||
| 705 | min((size_t) bufsiz, plaintext_name_size)); | ||
| 706 | if (rc) | ||
| 707 | rc = -EFAULT; | ||
| 708 | else | ||
| 709 | rc = plaintext_name_size; | ||
| 710 | kfree(plaintext_name); | ||
| 711 | fsstack_copy_attr_atime(dentry->d_inode, lower_dentry->d_inode); | ||
| 712 | } | ||
| 713 | out_free_lower_buf: | ||
| 714 | kfree(lower_buf); | 678 | kfree(lower_buf); |
| 679 | return rc; | ||
| 680 | } | ||
| 681 | |||
| 682 | static int | ||
| 683 | ecryptfs_readlink(struct dentry *dentry, char __user *buf, int bufsiz) | ||
| 684 | { | ||
| 685 | char *kbuf; | ||
| 686 | size_t kbufsiz, copied; | ||
| 687 | int rc; | ||
| 688 | |||
| 689 | rc = ecryptfs_readlink_lower(dentry, &kbuf, &kbufsiz); | ||
| 690 | if (rc) | ||
| 691 | goto out; | ||
| 692 | copied = min_t(size_t, bufsiz, kbufsiz); | ||
| 693 | rc = copy_to_user(buf, kbuf, copied) ? -EFAULT : copied; | ||
| 694 | kfree(kbuf); | ||
| 695 | fsstack_copy_attr_atime(dentry->d_inode, | ||
| 696 | ecryptfs_dentry_to_lower(dentry)->d_inode); | ||
| 715 | out: | 697 | out: |
| 716 | return rc; | 698 | return rc; |
| 717 | } | 699 | } |
| @@ -769,7 +751,7 @@ upper_size_to_lower_size(struct ecryptfs_crypt_stat *crypt_stat, | |||
| 769 | { | 751 | { |
| 770 | loff_t lower_size; | 752 | loff_t lower_size; |
| 771 | 753 | ||
| 772 | lower_size = crypt_stat->num_header_bytes_at_front; | 754 | lower_size = ecryptfs_lower_header_size(crypt_stat); |
| 773 | if (upper_size != 0) { | 755 | if (upper_size != 0) { |
| 774 | loff_t num_extents; | 756 | loff_t num_extents; |
| 775 | 757 | ||
| @@ -1016,6 +998,28 @@ out: | |||
| 1016 | return rc; | 998 | return rc; |
| 1017 | } | 999 | } |
| 1018 | 1000 | ||
| 1001 | int ecryptfs_getattr_link(struct vfsmount *mnt, struct dentry *dentry, | ||
| 1002 | struct kstat *stat) | ||
| 1003 | { | ||
| 1004 | struct ecryptfs_mount_crypt_stat *mount_crypt_stat; | ||
| 1005 | int rc = 0; | ||
| 1006 | |||
| 1007 | mount_crypt_stat = &ecryptfs_superblock_to_private( | ||
| 1008 | dentry->d_sb)->mount_crypt_stat; | ||
| 1009 | generic_fillattr(dentry->d_inode, stat); | ||
| 1010 | if (mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES) { | ||
| 1011 | char *target; | ||
| 1012 | size_t targetsiz; | ||
| 1013 | |||
| 1014 | rc = ecryptfs_readlink_lower(dentry, &target, &targetsiz); | ||
| 1015 | if (!rc) { | ||
| 1016 | kfree(target); | ||
| 1017 | stat->size = targetsiz; | ||
| 1018 | } | ||
| 1019 | } | ||
| 1020 | return rc; | ||
| 1021 | } | ||
| 1022 | |||
| 1019 | int ecryptfs_getattr(struct vfsmount *mnt, struct dentry *dentry, | 1023 | int ecryptfs_getattr(struct vfsmount *mnt, struct dentry *dentry, |
| 1020 | struct kstat *stat) | 1024 | struct kstat *stat) |
| 1021 | { | 1025 | { |
| @@ -1040,7 +1044,7 @@ ecryptfs_setxattr(struct dentry *dentry, const char *name, const void *value, | |||
| 1040 | 1044 | ||
| 1041 | lower_dentry = ecryptfs_dentry_to_lower(dentry); | 1045 | lower_dentry = ecryptfs_dentry_to_lower(dentry); |
| 1042 | if (!lower_dentry->d_inode->i_op->setxattr) { | 1046 | if (!lower_dentry->d_inode->i_op->setxattr) { |
| 1043 | rc = -ENOSYS; | 1047 | rc = -EOPNOTSUPP; |
| 1044 | goto out; | 1048 | goto out; |
| 1045 | } | 1049 | } |
| 1046 | mutex_lock(&lower_dentry->d_inode->i_mutex); | 1050 | mutex_lock(&lower_dentry->d_inode->i_mutex); |
| @@ -1058,7 +1062,7 @@ ecryptfs_getxattr_lower(struct dentry *lower_dentry, const char *name, | |||
| 1058 | int rc = 0; | 1062 | int rc = 0; |
| 1059 | 1063 | ||
| 1060 | if (!lower_dentry->d_inode->i_op->getxattr) { | 1064 | if (!lower_dentry->d_inode->i_op->getxattr) { |
| 1061 | rc = -ENOSYS; | 1065 | rc = -EOPNOTSUPP; |
| 1062 | goto out; | 1066 | goto out; |
| 1063 | } | 1067 | } |
| 1064 | mutex_lock(&lower_dentry->d_inode->i_mutex); | 1068 | mutex_lock(&lower_dentry->d_inode->i_mutex); |
| @@ -1085,7 +1089,7 @@ ecryptfs_listxattr(struct dentry *dentry, char *list, size_t size) | |||
| 1085 | 1089 | ||
| 1086 | lower_dentry = ecryptfs_dentry_to_lower(dentry); | 1090 | lower_dentry = ecryptfs_dentry_to_lower(dentry); |
| 1087 | if (!lower_dentry->d_inode->i_op->listxattr) { | 1091 | if (!lower_dentry->d_inode->i_op->listxattr) { |
| 1088 | rc = -ENOSYS; | 1092 | rc = -EOPNOTSUPP; |
| 1089 | goto out; | 1093 | goto out; |
| 1090 | } | 1094 | } |
| 1091 | mutex_lock(&lower_dentry->d_inode->i_mutex); | 1095 | mutex_lock(&lower_dentry->d_inode->i_mutex); |
| @@ -1102,7 +1106,7 @@ static int ecryptfs_removexattr(struct dentry *dentry, const char *name) | |||
| 1102 | 1106 | ||
| 1103 | lower_dentry = ecryptfs_dentry_to_lower(dentry); | 1107 | lower_dentry = ecryptfs_dentry_to_lower(dentry); |
| 1104 | if (!lower_dentry->d_inode->i_op->removexattr) { | 1108 | if (!lower_dentry->d_inode->i_op->removexattr) { |
| 1105 | rc = -ENOSYS; | 1109 | rc = -EOPNOTSUPP; |
| 1106 | goto out; | 1110 | goto out; |
| 1107 | } | 1111 | } |
| 1108 | mutex_lock(&lower_dentry->d_inode->i_mutex); | 1112 | mutex_lock(&lower_dentry->d_inode->i_mutex); |
| @@ -1133,6 +1137,7 @@ const struct inode_operations ecryptfs_symlink_iops = { | |||
| 1133 | .put_link = ecryptfs_put_link, | 1137 | .put_link = ecryptfs_put_link, |
| 1134 | .permission = ecryptfs_permission, | 1138 | .permission = ecryptfs_permission, |
| 1135 | .setattr = ecryptfs_setattr, | 1139 | .setattr = ecryptfs_setattr, |
| 1140 | .getattr = ecryptfs_getattr_link, | ||
| 1136 | .setxattr = ecryptfs_setxattr, | 1141 | .setxattr = ecryptfs_setxattr, |
| 1137 | .getxattr = ecryptfs_getxattr, | 1142 | .getxattr = ecryptfs_getxattr, |
| 1138 | .listxattr = ecryptfs_listxattr, | 1143 | .listxattr = ecryptfs_listxattr, |
diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c index d491237c98e7..2ee9a3a7b68c 100644 --- a/fs/ecryptfs/mmap.c +++ b/fs/ecryptfs/mmap.c | |||
| @@ -83,6 +83,19 @@ out: | |||
| 83 | return rc; | 83 | return rc; |
| 84 | } | 84 | } |
| 85 | 85 | ||
| 86 | static void strip_xattr_flag(char *page_virt, | ||
| 87 | struct ecryptfs_crypt_stat *crypt_stat) | ||
| 88 | { | ||
| 89 | if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) { | ||
| 90 | size_t written; | ||
| 91 | |||
| 92 | crypt_stat->flags &= ~ECRYPTFS_METADATA_IN_XATTR; | ||
| 93 | ecryptfs_write_crypt_stat_flags(page_virt, crypt_stat, | ||
| 94 | &written); | ||
| 95 | crypt_stat->flags |= ECRYPTFS_METADATA_IN_XATTR; | ||
| 96 | } | ||
| 97 | } | ||
| 98 | |||
| 86 | /** | 99 | /** |
| 87 | * Header Extent: | 100 | * Header Extent: |
| 88 | * Octets 0-7: Unencrypted file size (big-endian) | 101 | * Octets 0-7: Unencrypted file size (big-endian) |
| @@ -98,19 +111,6 @@ out: | |||
| 98 | * (big-endian) | 111 | * (big-endian) |
| 99 | * Octet 26: Begin RFC 2440 authentication token packet set | 112 | * Octet 26: Begin RFC 2440 authentication token packet set |
| 100 | */ | 113 | */ |
| 101 | static void set_header_info(char *page_virt, | ||
| 102 | struct ecryptfs_crypt_stat *crypt_stat) | ||
| 103 | { | ||
| 104 | size_t written; | ||
| 105 | size_t save_num_header_bytes_at_front = | ||
| 106 | crypt_stat->num_header_bytes_at_front; | ||
| 107 | |||
| 108 | crypt_stat->num_header_bytes_at_front = | ||
| 109 | ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE; | ||
| 110 | ecryptfs_write_header_metadata(page_virt + 20, crypt_stat, &written); | ||
| 111 | crypt_stat->num_header_bytes_at_front = | ||
| 112 | save_num_header_bytes_at_front; | ||
| 113 | } | ||
| 114 | 114 | ||
| 115 | /** | 115 | /** |
| 116 | * ecryptfs_copy_up_encrypted_with_header | 116 | * ecryptfs_copy_up_encrypted_with_header |
| @@ -136,8 +136,7 @@ ecryptfs_copy_up_encrypted_with_header(struct page *page, | |||
| 136 | * num_extents_per_page) | 136 | * num_extents_per_page) |
| 137 | + extent_num_in_page); | 137 | + extent_num_in_page); |
| 138 | size_t num_header_extents_at_front = | 138 | size_t num_header_extents_at_front = |
| 139 | (crypt_stat->num_header_bytes_at_front | 139 | (crypt_stat->metadata_size / crypt_stat->extent_size); |
| 140 | / crypt_stat->extent_size); | ||
| 141 | 140 | ||
| 142 | if (view_extent_num < num_header_extents_at_front) { | 141 | if (view_extent_num < num_header_extents_at_front) { |
| 143 | /* This is a header extent */ | 142 | /* This is a header extent */ |
| @@ -147,9 +146,14 @@ ecryptfs_copy_up_encrypted_with_header(struct page *page, | |||
| 147 | memset(page_virt, 0, PAGE_CACHE_SIZE); | 146 | memset(page_virt, 0, PAGE_CACHE_SIZE); |
| 148 | /* TODO: Support more than one header extent */ | 147 | /* TODO: Support more than one header extent */ |
| 149 | if (view_extent_num == 0) { | 148 | if (view_extent_num == 0) { |
| 149 | size_t written; | ||
| 150 | |||
| 150 | rc = ecryptfs_read_xattr_region( | 151 | rc = ecryptfs_read_xattr_region( |
| 151 | page_virt, page->mapping->host); | 152 | page_virt, page->mapping->host); |
| 152 | set_header_info(page_virt, crypt_stat); | 153 | strip_xattr_flag(page_virt + 16, crypt_stat); |
| 154 | ecryptfs_write_header_metadata(page_virt + 20, | ||
| 155 | crypt_stat, | ||
| 156 | &written); | ||
| 153 | } | 157 | } |
| 154 | kunmap_atomic(page_virt, KM_USER0); | 158 | kunmap_atomic(page_virt, KM_USER0); |
| 155 | flush_dcache_page(page); | 159 | flush_dcache_page(page); |
| @@ -162,7 +166,7 @@ ecryptfs_copy_up_encrypted_with_header(struct page *page, | |||
| 162 | /* This is an encrypted data extent */ | 166 | /* This is an encrypted data extent */ |
| 163 | loff_t lower_offset = | 167 | loff_t lower_offset = |
| 164 | ((view_extent_num * crypt_stat->extent_size) | 168 | ((view_extent_num * crypt_stat->extent_size) |
| 165 | - crypt_stat->num_header_bytes_at_front); | 169 | - crypt_stat->metadata_size); |
| 166 | 170 | ||
| 167 | rc = ecryptfs_read_lower_page_segment( | 171 | rc = ecryptfs_read_lower_page_segment( |
| 168 | page, (lower_offset >> PAGE_CACHE_SHIFT), | 172 | page, (lower_offset >> PAGE_CACHE_SHIFT), |
diff --git a/fs/ecryptfs/super.c b/fs/ecryptfs/super.c index fcef41c1d2cf..278743c7716a 100644 --- a/fs/ecryptfs/super.c +++ b/fs/ecryptfs/super.c | |||
| @@ -86,7 +86,6 @@ static void ecryptfs_destroy_inode(struct inode *inode) | |||
| 86 | if (lower_dentry->d_inode) { | 86 | if (lower_dentry->d_inode) { |
| 87 | fput(inode_info->lower_file); | 87 | fput(inode_info->lower_file); |
| 88 | inode_info->lower_file = NULL; | 88 | inode_info->lower_file = NULL; |
| 89 | d_drop(lower_dentry); | ||
| 90 | } | 89 | } |
| 91 | } | 90 | } |
| 92 | ecryptfs_destroy_crypt_stat(&inode_info->crypt_stat); | 91 | ecryptfs_destroy_crypt_stat(&inode_info->crypt_stat); |
diff --git a/fs/ext2/symlink.c b/fs/ext2/symlink.c index 4e2426e22bbe..565cf817bbf1 100644 --- a/fs/ext2/symlink.c +++ b/fs/ext2/symlink.c | |||
| @@ -32,6 +32,7 @@ const struct inode_operations ext2_symlink_inode_operations = { | |||
| 32 | .readlink = generic_readlink, | 32 | .readlink = generic_readlink, |
| 33 | .follow_link = page_follow_link_light, | 33 | .follow_link = page_follow_link_light, |
| 34 | .put_link = page_put_link, | 34 | .put_link = page_put_link, |
| 35 | .setattr = ext2_setattr, | ||
| 35 | #ifdef CONFIG_EXT2_FS_XATTR | 36 | #ifdef CONFIG_EXT2_FS_XATTR |
| 36 | .setxattr = generic_setxattr, | 37 | .setxattr = generic_setxattr, |
| 37 | .getxattr = generic_getxattr, | 38 | .getxattr = generic_getxattr, |
| @@ -43,6 +44,7 @@ const struct inode_operations ext2_symlink_inode_operations = { | |||
| 43 | const struct inode_operations ext2_fast_symlink_inode_operations = { | 44 | const struct inode_operations ext2_fast_symlink_inode_operations = { |
| 44 | .readlink = generic_readlink, | 45 | .readlink = generic_readlink, |
| 45 | .follow_link = ext2_follow_link, | 46 | .follow_link = ext2_follow_link, |
| 47 | .setattr = ext2_setattr, | ||
| 46 | #ifdef CONFIG_EXT2_FS_XATTR | 48 | #ifdef CONFIG_EXT2_FS_XATTR |
| 47 | .setxattr = generic_setxattr, | 49 | .setxattr = generic_setxattr, |
| 48 | .getxattr = generic_getxattr, | 50 | .getxattr = generic_getxattr, |
diff --git a/fs/ext3/symlink.c b/fs/ext3/symlink.c index ff7b4ccd8983..7c4898207776 100644 --- a/fs/ext3/symlink.c +++ b/fs/ext3/symlink.c | |||
| @@ -34,6 +34,7 @@ const struct inode_operations ext3_symlink_inode_operations = { | |||
| 34 | .readlink = generic_readlink, | 34 | .readlink = generic_readlink, |
| 35 | .follow_link = page_follow_link_light, | 35 | .follow_link = page_follow_link_light, |
| 36 | .put_link = page_put_link, | 36 | .put_link = page_put_link, |
| 37 | .setattr = ext3_setattr, | ||
| 37 | #ifdef CONFIG_EXT3_FS_XATTR | 38 | #ifdef CONFIG_EXT3_FS_XATTR |
| 38 | .setxattr = generic_setxattr, | 39 | .setxattr = generic_setxattr, |
| 39 | .getxattr = generic_getxattr, | 40 | .getxattr = generic_getxattr, |
| @@ -45,6 +46,7 @@ const struct inode_operations ext3_symlink_inode_operations = { | |||
| 45 | const struct inode_operations ext3_fast_symlink_inode_operations = { | 46 | const struct inode_operations ext3_fast_symlink_inode_operations = { |
| 46 | .readlink = generic_readlink, | 47 | .readlink = generic_readlink, |
| 47 | .follow_link = ext3_follow_link, | 48 | .follow_link = ext3_follow_link, |
| 49 | .setattr = ext3_setattr, | ||
| 48 | #ifdef CONFIG_EXT3_FS_XATTR | 50 | #ifdef CONFIG_EXT3_FS_XATTR |
| 49 | .setxattr = generic_setxattr, | 51 | .setxattr = generic_setxattr, |
| 50 | .getxattr = generic_getxattr, | 52 | .getxattr = generic_getxattr, |
diff --git a/fs/fcntl.c b/fs/fcntl.c index 452d02f9075e..0a140741b39e 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c | |||
| @@ -614,9 +614,15 @@ int send_sigurg(struct fown_struct *fown) | |||
| 614 | return ret; | 614 | return ret; |
| 615 | } | 615 | } |
| 616 | 616 | ||
| 617 | static DEFINE_RWLOCK(fasync_lock); | 617 | static DEFINE_SPINLOCK(fasync_lock); |
| 618 | static struct kmem_cache *fasync_cache __read_mostly; | 618 | static struct kmem_cache *fasync_cache __read_mostly; |
| 619 | 619 | ||
| 620 | static void fasync_free_rcu(struct rcu_head *head) | ||
| 621 | { | ||
| 622 | kmem_cache_free(fasync_cache, | ||
| 623 | container_of(head, struct fasync_struct, fa_rcu)); | ||
| 624 | } | ||
| 625 | |||
| 620 | /* | 626 | /* |
| 621 | * Remove a fasync entry. If successfully removed, return | 627 | * Remove a fasync entry. If successfully removed, return |
| 622 | * positive and clear the FASYNC flag. If no entry exists, | 628 | * positive and clear the FASYNC flag. If no entry exists, |
| @@ -625,8 +631,6 @@ static struct kmem_cache *fasync_cache __read_mostly; | |||
| 625 | * NOTE! It is very important that the FASYNC flag always | 631 | * NOTE! It is very important that the FASYNC flag always |
| 626 | * match the state "is the filp on a fasync list". | 632 | * match the state "is the filp on a fasync list". |
| 627 | * | 633 | * |
| 628 | * We always take the 'filp->f_lock', in since fasync_lock | ||
| 629 | * needs to be irq-safe. | ||
| 630 | */ | 634 | */ |
| 631 | static int fasync_remove_entry(struct file *filp, struct fasync_struct **fapp) | 635 | static int fasync_remove_entry(struct file *filp, struct fasync_struct **fapp) |
| 632 | { | 636 | { |
| @@ -634,17 +638,22 @@ static int fasync_remove_entry(struct file *filp, struct fasync_struct **fapp) | |||
| 634 | int result = 0; | 638 | int result = 0; |
| 635 | 639 | ||
| 636 | spin_lock(&filp->f_lock); | 640 | spin_lock(&filp->f_lock); |
| 637 | write_lock_irq(&fasync_lock); | 641 | spin_lock(&fasync_lock); |
| 638 | for (fp = fapp; (fa = *fp) != NULL; fp = &fa->fa_next) { | 642 | for (fp = fapp; (fa = *fp) != NULL; fp = &fa->fa_next) { |
| 639 | if (fa->fa_file != filp) | 643 | if (fa->fa_file != filp) |
| 640 | continue; | 644 | continue; |
| 645 | |||
| 646 | spin_lock_irq(&fa->fa_lock); | ||
| 647 | fa->fa_file = NULL; | ||
| 648 | spin_unlock_irq(&fa->fa_lock); | ||
| 649 | |||
| 641 | *fp = fa->fa_next; | 650 | *fp = fa->fa_next; |
| 642 | kmem_cache_free(fasync_cache, fa); | 651 | call_rcu(&fa->fa_rcu, fasync_free_rcu); |
| 643 | filp->f_flags &= ~FASYNC; | 652 | filp->f_flags &= ~FASYNC; |
| 644 | result = 1; | 653 | result = 1; |
| 645 | break; | 654 | break; |
| 646 | } | 655 | } |
| 647 | write_unlock_irq(&fasync_lock); | 656 | spin_unlock(&fasync_lock); |
| 648 | spin_unlock(&filp->f_lock); | 657 | spin_unlock(&filp->f_lock); |
| 649 | return result; | 658 | return result; |
| 650 | } | 659 | } |
| @@ -666,25 +675,30 @@ static int fasync_add_entry(int fd, struct file *filp, struct fasync_struct **fa | |||
| 666 | return -ENOMEM; | 675 | return -ENOMEM; |
| 667 | 676 | ||
| 668 | spin_lock(&filp->f_lock); | 677 | spin_lock(&filp->f_lock); |
| 669 | write_lock_irq(&fasync_lock); | 678 | spin_lock(&fasync_lock); |
| 670 | for (fp = fapp; (fa = *fp) != NULL; fp = &fa->fa_next) { | 679 | for (fp = fapp; (fa = *fp) != NULL; fp = &fa->fa_next) { |
| 671 | if (fa->fa_file != filp) | 680 | if (fa->fa_file != filp) |
| 672 | continue; | 681 | continue; |
| 682 | |||
| 683 | spin_lock_irq(&fa->fa_lock); | ||
| 673 | fa->fa_fd = fd; | 684 | fa->fa_fd = fd; |
| 685 | spin_unlock_irq(&fa->fa_lock); | ||
| 686 | |||
| 674 | kmem_cache_free(fasync_cache, new); | 687 | kmem_cache_free(fasync_cache, new); |
| 675 | goto out; | 688 | goto out; |
| 676 | } | 689 | } |
| 677 | 690 | ||
| 691 | spin_lock_init(&new->fa_lock); | ||
| 678 | new->magic = FASYNC_MAGIC; | 692 | new->magic = FASYNC_MAGIC; |
| 679 | new->fa_file = filp; | 693 | new->fa_file = filp; |
| 680 | new->fa_fd = fd; | 694 | new->fa_fd = fd; |
| 681 | new->fa_next = *fapp; | 695 | new->fa_next = *fapp; |
| 682 | *fapp = new; | 696 | rcu_assign_pointer(*fapp, new); |
| 683 | result = 1; | 697 | result = 1; |
| 684 | filp->f_flags |= FASYNC; | 698 | filp->f_flags |= FASYNC; |
| 685 | 699 | ||
| 686 | out: | 700 | out: |
| 687 | write_unlock_irq(&fasync_lock); | 701 | spin_unlock(&fasync_lock); |
| 688 | spin_unlock(&filp->f_lock); | 702 | spin_unlock(&filp->f_lock); |
| 689 | return result; | 703 | return result; |
| 690 | } | 704 | } |
| @@ -704,37 +718,41 @@ int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fap | |||
| 704 | 718 | ||
| 705 | EXPORT_SYMBOL(fasync_helper); | 719 | EXPORT_SYMBOL(fasync_helper); |
| 706 | 720 | ||
| 707 | void __kill_fasync(struct fasync_struct *fa, int sig, int band) | 721 | /* |
| 722 | * rcu_read_lock() is held | ||
| 723 | */ | ||
| 724 | static void kill_fasync_rcu(struct fasync_struct *fa, int sig, int band) | ||
| 708 | { | 725 | { |
| 709 | while (fa) { | 726 | while (fa) { |
| 710 | struct fown_struct * fown; | 727 | struct fown_struct *fown; |
| 711 | if (fa->magic != FASYNC_MAGIC) { | 728 | if (fa->magic != FASYNC_MAGIC) { |
| 712 | printk(KERN_ERR "kill_fasync: bad magic number in " | 729 | printk(KERN_ERR "kill_fasync: bad magic number in " |
| 713 | "fasync_struct!\n"); | 730 | "fasync_struct!\n"); |
| 714 | return; | 731 | return; |
| 715 | } | 732 | } |
| 716 | fown = &fa->fa_file->f_owner; | 733 | spin_lock(&fa->fa_lock); |
| 717 | /* Don't send SIGURG to processes which have not set a | 734 | if (fa->fa_file) { |
| 718 | queued signum: SIGURG has its own default signalling | 735 | fown = &fa->fa_file->f_owner; |
| 719 | mechanism. */ | 736 | /* Don't send SIGURG to processes which have not set a |
| 720 | if (!(sig == SIGURG && fown->signum == 0)) | 737 | queued signum: SIGURG has its own default signalling |
| 721 | send_sigio(fown, fa->fa_fd, band); | 738 | mechanism. */ |
| 722 | fa = fa->fa_next; | 739 | if (!(sig == SIGURG && fown->signum == 0)) |
| 740 | send_sigio(fown, fa->fa_fd, band); | ||
| 741 | } | ||
| 742 | spin_unlock(&fa->fa_lock); | ||
| 743 | fa = rcu_dereference(fa->fa_next); | ||
| 723 | } | 744 | } |
| 724 | } | 745 | } |
| 725 | 746 | ||
| 726 | EXPORT_SYMBOL(__kill_fasync); | ||
| 727 | |||
| 728 | void kill_fasync(struct fasync_struct **fp, int sig, int band) | 747 | void kill_fasync(struct fasync_struct **fp, int sig, int band) |
| 729 | { | 748 | { |
| 730 | /* First a quick test without locking: usually | 749 | /* First a quick test without locking: usually |
| 731 | * the list is empty. | 750 | * the list is empty. |
| 732 | */ | 751 | */ |
| 733 | if (*fp) { | 752 | if (*fp) { |
| 734 | read_lock(&fasync_lock); | 753 | rcu_read_lock(); |
| 735 | /* reread *fp after obtaining the lock */ | 754 | kill_fasync_rcu(rcu_dereference(*fp), sig, band); |
| 736 | __kill_fasync(*fp, sig, band); | 755 | rcu_read_unlock(); |
| 737 | read_unlock(&fasync_lock); | ||
| 738 | } | 756 | } |
| 739 | } | 757 | } |
| 740 | EXPORT_SYMBOL(kill_fasync); | 758 | EXPORT_SYMBOL(kill_fasync); |
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 2a3d352c0bff..a8766c4ef2e0 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
| @@ -1294,7 +1294,8 @@ static int nfs4_init_server(struct nfs_server *server, | |||
| 1294 | 1294 | ||
| 1295 | /* Initialise the client representation from the mount data */ | 1295 | /* Initialise the client representation from the mount data */ |
| 1296 | server->flags = data->flags; | 1296 | server->flags = data->flags; |
| 1297 | server->caps |= NFS_CAP_ATOMIC_OPEN|NFS_CAP_CHANGE_ATTR; | 1297 | server->caps |= NFS_CAP_ATOMIC_OPEN|NFS_CAP_CHANGE_ATTR| |
| 1298 | NFS_CAP_POSIX_LOCK; | ||
| 1298 | server->options = data->options; | 1299 | server->options = data->options; |
| 1299 | 1300 | ||
| 1300 | /* Get a client record */ | 1301 | /* Get a client record */ |
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index c6f2750648f4..be46f26c9a56 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
| @@ -1025,12 +1025,12 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry | |||
| 1025 | res = NULL; | 1025 | res = NULL; |
| 1026 | goto out; | 1026 | goto out; |
| 1027 | /* This turned out not to be a regular file */ | 1027 | /* This turned out not to be a regular file */ |
| 1028 | case -EISDIR: | ||
| 1028 | case -ENOTDIR: | 1029 | case -ENOTDIR: |
| 1029 | goto no_open; | 1030 | goto no_open; |
| 1030 | case -ELOOP: | 1031 | case -ELOOP: |
| 1031 | if (!(nd->intent.open.flags & O_NOFOLLOW)) | 1032 | if (!(nd->intent.open.flags & O_NOFOLLOW)) |
| 1032 | goto no_open; | 1033 | goto no_open; |
| 1033 | /* case -EISDIR: */ | ||
| 1034 | /* case -EINVAL: */ | 1034 | /* case -EINVAL: */ |
| 1035 | default: | 1035 | default: |
| 1036 | goto out; | 1036 | goto out; |
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 737128f777f3..50a56edca0b5 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
| @@ -623,10 +623,10 @@ struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_c | |||
| 623 | list_for_each_entry(pos, &nfsi->open_files, list) { | 623 | list_for_each_entry(pos, &nfsi->open_files, list) { |
| 624 | if (cred != NULL && pos->cred != cred) | 624 | if (cred != NULL && pos->cred != cred) |
| 625 | continue; | 625 | continue; |
| 626 | if ((pos->mode & mode) == mode) { | 626 | if ((pos->mode & (FMODE_READ|FMODE_WRITE)) != mode) |
| 627 | ctx = get_nfs_open_context(pos); | 627 | continue; |
| 628 | break; | 628 | ctx = get_nfs_open_context(pos); |
| 629 | } | 629 | break; |
| 630 | } | 630 | } |
| 631 | spin_unlock(&inode->i_lock); | 631 | spin_unlock(&inode->i_lock); |
| 632 | return ctx; | 632 | return ctx; |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index fe0cd9eb1d4d..638067007c65 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
| @@ -1523,6 +1523,8 @@ static int _nfs4_proc_open(struct nfs4_opendata *data) | |||
| 1523 | nfs_post_op_update_inode(dir, o_res->dir_attr); | 1523 | nfs_post_op_update_inode(dir, o_res->dir_attr); |
| 1524 | } else | 1524 | } else |
| 1525 | nfs_refresh_inode(dir, o_res->dir_attr); | 1525 | nfs_refresh_inode(dir, o_res->dir_attr); |
| 1526 | if ((o_res->rflags & NFS4_OPEN_RESULT_LOCKTYPE_POSIX) == 0) | ||
| 1527 | server->caps &= ~NFS_CAP_POSIX_LOCK; | ||
| 1526 | if(o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) { | 1528 | if(o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) { |
| 1527 | status = _nfs4_proc_open_confirm(data); | 1529 | status = _nfs4_proc_open_confirm(data); |
| 1528 | if (status != 0) | 1530 | if (status != 0) |
| @@ -1664,7 +1666,7 @@ static int _nfs4_do_open(struct inode *dir, struct path *path, fmode_t fmode, in | |||
| 1664 | status = PTR_ERR(state); | 1666 | status = PTR_ERR(state); |
| 1665 | if (IS_ERR(state)) | 1667 | if (IS_ERR(state)) |
| 1666 | goto err_opendata_put; | 1668 | goto err_opendata_put; |
| 1667 | if ((opendata->o_res.rflags & NFS4_OPEN_RESULT_LOCKTYPE_POSIX) != 0) | 1669 | if (server->caps & NFS_CAP_POSIX_LOCK) |
| 1668 | set_bit(NFS_STATE_POSIX_LOCKS, &state->flags); | 1670 | set_bit(NFS_STATE_POSIX_LOCKS, &state->flags); |
| 1669 | nfs4_opendata_put(opendata); | 1671 | nfs4_opendata_put(opendata); |
| 1670 | nfs4_put_state_owner(sp); | 1672 | nfs4_put_state_owner(sp); |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 53ff70e23993..de38d63aa920 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
| @@ -201,6 +201,7 @@ static int nfs_set_page_writeback(struct page *page) | |||
| 201 | struct inode *inode = page->mapping->host; | 201 | struct inode *inode = page->mapping->host; |
| 202 | struct nfs_server *nfss = NFS_SERVER(inode); | 202 | struct nfs_server *nfss = NFS_SERVER(inode); |
| 203 | 203 | ||
| 204 | page_cache_get(page); | ||
| 204 | if (atomic_long_inc_return(&nfss->writeback) > | 205 | if (atomic_long_inc_return(&nfss->writeback) > |
| 205 | NFS_CONGESTION_ON_THRESH) { | 206 | NFS_CONGESTION_ON_THRESH) { |
| 206 | set_bdi_congested(&nfss->backing_dev_info, | 207 | set_bdi_congested(&nfss->backing_dev_info, |
| @@ -216,6 +217,7 @@ static void nfs_end_page_writeback(struct page *page) | |||
| 216 | struct nfs_server *nfss = NFS_SERVER(inode); | 217 | struct nfs_server *nfss = NFS_SERVER(inode); |
| 217 | 218 | ||
| 218 | end_page_writeback(page); | 219 | end_page_writeback(page); |
| 220 | page_cache_release(page); | ||
| 219 | if (atomic_long_dec_return(&nfss->writeback) < NFS_CONGESTION_OFF_THRESH) | 221 | if (atomic_long_dec_return(&nfss->writeback) < NFS_CONGESTION_OFF_THRESH) |
| 220 | clear_bdi_congested(&nfss->backing_dev_info, BLK_RW_ASYNC); | 222 | clear_bdi_congested(&nfss->backing_dev_info, BLK_RW_ASYNC); |
| 221 | } | 223 | } |
| @@ -421,6 +423,7 @@ static void | |||
| 421 | nfs_mark_request_dirty(struct nfs_page *req) | 423 | nfs_mark_request_dirty(struct nfs_page *req) |
| 422 | { | 424 | { |
| 423 | __set_page_dirty_nobuffers(req->wb_page); | 425 | __set_page_dirty_nobuffers(req->wb_page); |
| 426 | __mark_inode_dirty(req->wb_page->mapping->host, I_DIRTY_DATASYNC); | ||
| 424 | } | 427 | } |
| 425 | 428 | ||
| 426 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | 429 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) |
| @@ -660,9 +663,11 @@ static int nfs_writepage_setup(struct nfs_open_context *ctx, struct page *page, | |||
| 660 | req = nfs_setup_write_request(ctx, page, offset, count); | 663 | req = nfs_setup_write_request(ctx, page, offset, count); |
| 661 | if (IS_ERR(req)) | 664 | if (IS_ERR(req)) |
| 662 | return PTR_ERR(req); | 665 | return PTR_ERR(req); |
| 666 | nfs_mark_request_dirty(req); | ||
| 663 | /* Update file length */ | 667 | /* Update file length */ |
| 664 | nfs_grow_file(page, offset, count); | 668 | nfs_grow_file(page, offset, count); |
| 665 | nfs_mark_uptodate(page, req->wb_pgbase, req->wb_bytes); | 669 | nfs_mark_uptodate(page, req->wb_pgbase, req->wb_bytes); |
| 670 | nfs_mark_request_dirty(req); | ||
| 666 | nfs_clear_page_tag_locked(req); | 671 | nfs_clear_page_tag_locked(req); |
| 667 | return 0; | 672 | return 0; |
| 668 | } | 673 | } |
| @@ -739,8 +744,6 @@ int nfs_updatepage(struct file *file, struct page *page, | |||
| 739 | status = nfs_writepage_setup(ctx, page, offset, count); | 744 | status = nfs_writepage_setup(ctx, page, offset, count); |
| 740 | if (status < 0) | 745 | if (status < 0) |
| 741 | nfs_set_pageerror(page); | 746 | nfs_set_pageerror(page); |
| 742 | else | ||
| 743 | __set_page_dirty_nobuffers(page); | ||
| 744 | 747 | ||
| 745 | dprintk("NFS: nfs_updatepage returns %d (isize %lld)\n", | 748 | dprintk("NFS: nfs_updatepage returns %d (isize %lld)\n", |
| 746 | status, (long long)i_size_read(inode)); | 749 | status, (long long)i_size_read(inode)); |
| @@ -749,13 +752,12 @@ int nfs_updatepage(struct file *file, struct page *page, | |||
| 749 | 752 | ||
| 750 | static void nfs_writepage_release(struct nfs_page *req) | 753 | static void nfs_writepage_release(struct nfs_page *req) |
| 751 | { | 754 | { |
| 755 | struct page *page = req->wb_page; | ||
| 752 | 756 | ||
| 753 | if (PageError(req->wb_page) || !nfs_reschedule_unstable_write(req)) { | 757 | if (PageError(req->wb_page) || !nfs_reschedule_unstable_write(req)) |
| 754 | nfs_end_page_writeback(req->wb_page); | ||
| 755 | nfs_inode_remove_request(req); | 758 | nfs_inode_remove_request(req); |
| 756 | } else | ||
| 757 | nfs_end_page_writeback(req->wb_page); | ||
| 758 | nfs_clear_page_tag_locked(req); | 759 | nfs_clear_page_tag_locked(req); |
| 760 | nfs_end_page_writeback(page); | ||
| 759 | } | 761 | } |
| 760 | 762 | ||
| 761 | static int flush_task_priority(int how) | 763 | static int flush_task_priority(int how) |
| @@ -779,7 +781,6 @@ static int nfs_write_rpcsetup(struct nfs_page *req, | |||
| 779 | int how) | 781 | int how) |
| 780 | { | 782 | { |
| 781 | struct inode *inode = req->wb_context->path.dentry->d_inode; | 783 | struct inode *inode = req->wb_context->path.dentry->d_inode; |
| 782 | int flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; | ||
| 783 | int priority = flush_task_priority(how); | 784 | int priority = flush_task_priority(how); |
| 784 | struct rpc_task *task; | 785 | struct rpc_task *task; |
| 785 | struct rpc_message msg = { | 786 | struct rpc_message msg = { |
| @@ -794,9 +795,10 @@ static int nfs_write_rpcsetup(struct nfs_page *req, | |||
| 794 | .callback_ops = call_ops, | 795 | .callback_ops = call_ops, |
| 795 | .callback_data = data, | 796 | .callback_data = data, |
| 796 | .workqueue = nfsiod_workqueue, | 797 | .workqueue = nfsiod_workqueue, |
| 797 | .flags = flags, | 798 | .flags = RPC_TASK_ASYNC, |
| 798 | .priority = priority, | 799 | .priority = priority, |
| 799 | }; | 800 | }; |
| 801 | int ret = 0; | ||
| 800 | 802 | ||
| 801 | /* Set up the RPC argument and reply structs | 803 | /* Set up the RPC argument and reply structs |
| 802 | * NB: take care not to mess about with data->commit et al. */ | 804 | * NB: take care not to mess about with data->commit et al. */ |
| @@ -835,10 +837,18 @@ static int nfs_write_rpcsetup(struct nfs_page *req, | |||
| 835 | (unsigned long long)data->args.offset); | 837 | (unsigned long long)data->args.offset); |
| 836 | 838 | ||
| 837 | task = rpc_run_task(&task_setup_data); | 839 | task = rpc_run_task(&task_setup_data); |
| 838 | if (IS_ERR(task)) | 840 | if (IS_ERR(task)) { |
| 839 | return PTR_ERR(task); | 841 | ret = PTR_ERR(task); |
| 842 | goto out; | ||
| 843 | } | ||
| 844 | if (how & FLUSH_SYNC) { | ||
| 845 | ret = rpc_wait_for_completion_task(task); | ||
| 846 | if (ret == 0) | ||
| 847 | ret = task->tk_status; | ||
| 848 | } | ||
| 840 | rpc_put_task(task); | 849 | rpc_put_task(task); |
| 841 | return 0; | 850 | out: |
| 851 | return ret; | ||
| 842 | } | 852 | } |
| 843 | 853 | ||
| 844 | /* If a nfs_flush_* function fails, it should remove reqs from @head and | 854 | /* If a nfs_flush_* function fails, it should remove reqs from @head and |
| @@ -847,9 +857,11 @@ static int nfs_write_rpcsetup(struct nfs_page *req, | |||
| 847 | */ | 857 | */ |
| 848 | static void nfs_redirty_request(struct nfs_page *req) | 858 | static void nfs_redirty_request(struct nfs_page *req) |
| 849 | { | 859 | { |
| 860 | struct page *page = req->wb_page; | ||
| 861 | |||
| 850 | nfs_mark_request_dirty(req); | 862 | nfs_mark_request_dirty(req); |
| 851 | nfs_end_page_writeback(req->wb_page); | ||
| 852 | nfs_clear_page_tag_locked(req); | 863 | nfs_clear_page_tag_locked(req); |
| 864 | nfs_end_page_writeback(page); | ||
| 853 | } | 865 | } |
| 854 | 866 | ||
| 855 | /* | 867 | /* |
| @@ -1084,16 +1096,15 @@ static void nfs_writeback_release_full(void *calldata) | |||
| 1084 | if (nfs_write_need_commit(data)) { | 1096 | if (nfs_write_need_commit(data)) { |
| 1085 | memcpy(&req->wb_verf, &data->verf, sizeof(req->wb_verf)); | 1097 | memcpy(&req->wb_verf, &data->verf, sizeof(req->wb_verf)); |
| 1086 | nfs_mark_request_commit(req); | 1098 | nfs_mark_request_commit(req); |
| 1087 | nfs_end_page_writeback(page); | ||
| 1088 | dprintk(" marked for commit\n"); | 1099 | dprintk(" marked for commit\n"); |
| 1089 | goto next; | 1100 | goto next; |
| 1090 | } | 1101 | } |
| 1091 | dprintk(" OK\n"); | 1102 | dprintk(" OK\n"); |
| 1092 | remove_request: | 1103 | remove_request: |
| 1093 | nfs_end_page_writeback(page); | ||
| 1094 | nfs_inode_remove_request(req); | 1104 | nfs_inode_remove_request(req); |
| 1095 | next: | 1105 | next: |
| 1096 | nfs_clear_page_tag_locked(req); | 1106 | nfs_clear_page_tag_locked(req); |
| 1107 | nfs_end_page_writeback(page); | ||
| 1097 | } | 1108 | } |
| 1098 | nfs_writedata_release(calldata); | 1109 | nfs_writedata_release(calldata); |
| 1099 | } | 1110 | } |
| @@ -1207,7 +1218,6 @@ static int nfs_commit_rpcsetup(struct list_head *head, | |||
| 1207 | { | 1218 | { |
| 1208 | struct nfs_page *first = nfs_list_entry(head->next); | 1219 | struct nfs_page *first = nfs_list_entry(head->next); |
| 1209 | struct inode *inode = first->wb_context->path.dentry->d_inode; | 1220 | struct inode *inode = first->wb_context->path.dentry->d_inode; |
| 1210 | int flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; | ||
| 1211 | int priority = flush_task_priority(how); | 1221 | int priority = flush_task_priority(how); |
| 1212 | struct rpc_task *task; | 1222 | struct rpc_task *task; |
| 1213 | struct rpc_message msg = { | 1223 | struct rpc_message msg = { |
| @@ -1222,7 +1232,7 @@ static int nfs_commit_rpcsetup(struct list_head *head, | |||
| 1222 | .callback_ops = &nfs_commit_ops, | 1232 | .callback_ops = &nfs_commit_ops, |
| 1223 | .callback_data = data, | 1233 | .callback_data = data, |
| 1224 | .workqueue = nfsiod_workqueue, | 1234 | .workqueue = nfsiod_workqueue, |
| 1225 | .flags = flags, | 1235 | .flags = RPC_TASK_ASYNC, |
| 1226 | .priority = priority, | 1236 | .priority = priority, |
| 1227 | }; | 1237 | }; |
| 1228 | 1238 | ||
| @@ -1252,6 +1262,8 @@ static int nfs_commit_rpcsetup(struct list_head *head, | |||
| 1252 | task = rpc_run_task(&task_setup_data); | 1262 | task = rpc_run_task(&task_setup_data); |
| 1253 | if (IS_ERR(task)) | 1263 | if (IS_ERR(task)) |
| 1254 | return PTR_ERR(task); | 1264 | return PTR_ERR(task); |
| 1265 | if (how & FLUSH_SYNC) | ||
| 1266 | rpc_wait_for_completion_task(task); | ||
| 1255 | rpc_put_task(task); | 1267 | rpc_put_task(task); |
| 1256 | return 0; | 1268 | return 0; |
| 1257 | } | 1269 | } |
diff --git a/fs/nilfs2/alloc.c b/fs/nilfs2/alloc.c index 8d6356a804f3..7cfb87e692da 100644 --- a/fs/nilfs2/alloc.c +++ b/fs/nilfs2/alloc.c | |||
| @@ -426,7 +426,7 @@ void nilfs_palloc_abort_alloc_entry(struct inode *inode, | |||
| 426 | bitmap = bitmap_kaddr + bh_offset(req->pr_bitmap_bh); | 426 | bitmap = bitmap_kaddr + bh_offset(req->pr_bitmap_bh); |
| 427 | if (!nilfs_clear_bit_atomic(nilfs_mdt_bgl_lock(inode, group), | 427 | if (!nilfs_clear_bit_atomic(nilfs_mdt_bgl_lock(inode, group), |
| 428 | group_offset, bitmap)) | 428 | group_offset, bitmap)) |
| 429 | printk(KERN_WARNING "%s: entry numer %llu already freed\n", | 429 | printk(KERN_WARNING "%s: entry number %llu already freed\n", |
| 430 | __func__, (unsigned long long)req->pr_entry_nr); | 430 | __func__, (unsigned long long)req->pr_entry_nr); |
| 431 | 431 | ||
| 432 | nilfs_palloc_group_desc_add_entries(inode, group, desc, 1); | 432 | nilfs_palloc_group_desc_add_entries(inode, group, desc, 1); |
diff --git a/fs/nilfs2/btree.c b/fs/nilfs2/btree.c index 7cdd98b8d514..76c38e3e19d2 100644 --- a/fs/nilfs2/btree.c +++ b/fs/nilfs2/btree.c | |||
| @@ -1879,7 +1879,7 @@ static int nilfs_btree_propagate_v(struct nilfs_btree *btree, | |||
| 1879 | struct nilfs_btree_path *path, | 1879 | struct nilfs_btree_path *path, |
| 1880 | int level, struct buffer_head *bh) | 1880 | int level, struct buffer_head *bh) |
| 1881 | { | 1881 | { |
| 1882 | int maxlevel, ret; | 1882 | int maxlevel = 0, ret; |
| 1883 | struct nilfs_btree_node *parent; | 1883 | struct nilfs_btree_node *parent; |
| 1884 | struct inode *dat = nilfs_bmap_get_dat(&btree->bt_bmap); | 1884 | struct inode *dat = nilfs_bmap_get_dat(&btree->bt_bmap); |
| 1885 | __u64 ptr; | 1885 | __u64 ptr; |
diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c index c2ff1b306012..f90a33d9a5b0 100644 --- a/fs/nilfs2/ioctl.c +++ b/fs/nilfs2/ioctl.c | |||
| @@ -649,7 +649,7 @@ static int nilfs_ioctl_get_info(struct inode *inode, struct file *filp, | |||
| 649 | long nilfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | 649 | long nilfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) |
| 650 | { | 650 | { |
| 651 | struct inode *inode = filp->f_dentry->d_inode; | 651 | struct inode *inode = filp->f_dentry->d_inode; |
| 652 | void __user *argp = (void * __user *)arg; | 652 | void __user *argp = (void __user *)arg; |
| 653 | 653 | ||
| 654 | switch (cmd) { | 654 | switch (cmd) { |
| 655 | case NILFS_IOCTL_CHANGE_CPMODE: | 655 | case NILFS_IOCTL_CHANGE_CPMODE: |
diff --git a/fs/quota/Kconfig b/fs/quota/Kconfig index dad7fb247ddc..3e21b1e2ad3a 100644 --- a/fs/quota/Kconfig +++ b/fs/quota/Kconfig | |||
| @@ -33,6 +33,14 @@ config PRINT_QUOTA_WARNING | |||
| 33 | Note that this behavior is currently deprecated and may go away in | 33 | Note that this behavior is currently deprecated and may go away in |
| 34 | future. Please use notification via netlink socket instead. | 34 | future. Please use notification via netlink socket instead. |
| 35 | 35 | ||
| 36 | config QUOTA_DEBUG | ||
| 37 | bool "Additional quota sanity checks" | ||
| 38 | depends on QUOTA | ||
| 39 | default n | ||
| 40 | help | ||
| 41 | If you say Y here, quota subsystem will perform some additional | ||
| 42 | sanity checks of quota internal structures. If unsure, say N. | ||
| 43 | |||
| 36 | # Generic support for tree structured quota files. Selected when needed. | 44 | # Generic support for tree structured quota files. Selected when needed. |
| 37 | config QUOTA_TREE | 45 | config QUOTA_TREE |
| 38 | tristate | 46 | tristate |
diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c index e0b870f4749f..788b5802a7ce 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c | |||
| @@ -80,8 +80,6 @@ | |||
| 80 | 80 | ||
| 81 | #include <asm/uaccess.h> | 81 | #include <asm/uaccess.h> |
| 82 | 82 | ||
| 83 | #define __DQUOT_PARANOIA | ||
| 84 | |||
| 85 | /* | 83 | /* |
| 86 | * There are three quota SMP locks. dq_list_lock protects all lists with quotas | 84 | * There are three quota SMP locks. dq_list_lock protects all lists with quotas |
| 87 | * and quota formats, dqstats structure containing statistics about the lists | 85 | * and quota formats, dqstats structure containing statistics about the lists |
| @@ -695,7 +693,7 @@ void dqput(struct dquot *dquot) | |||
| 695 | 693 | ||
| 696 | if (!dquot) | 694 | if (!dquot) |
| 697 | return; | 695 | return; |
| 698 | #ifdef __DQUOT_PARANOIA | 696 | #ifdef CONFIG_QUOTA_DEBUG |
| 699 | if (!atomic_read(&dquot->dq_count)) { | 697 | if (!atomic_read(&dquot->dq_count)) { |
| 700 | printk("VFS: dqput: trying to free free dquot\n"); | 698 | printk("VFS: dqput: trying to free free dquot\n"); |
| 701 | printk("VFS: device %s, dquot of %s %d\n", | 699 | printk("VFS: device %s, dquot of %s %d\n", |
| @@ -748,7 +746,7 @@ we_slept: | |||
| 748 | goto we_slept; | 746 | goto we_slept; |
| 749 | } | 747 | } |
| 750 | atomic_dec(&dquot->dq_count); | 748 | atomic_dec(&dquot->dq_count); |
| 751 | #ifdef __DQUOT_PARANOIA | 749 | #ifdef CONFIG_QUOTA_DEBUG |
| 752 | /* sanity check */ | 750 | /* sanity check */ |
| 753 | BUG_ON(!list_empty(&dquot->dq_free)); | 751 | BUG_ON(!list_empty(&dquot->dq_free)); |
| 754 | #endif | 752 | #endif |
| @@ -845,7 +843,7 @@ we_slept: | |||
| 845 | dquot = NULL; | 843 | dquot = NULL; |
| 846 | goto out; | 844 | goto out; |
| 847 | } | 845 | } |
| 848 | #ifdef __DQUOT_PARANOIA | 846 | #ifdef CONFIG_QUOTA_DEBUG |
| 849 | BUG_ON(!dquot->dq_sb); /* Has somebody invalidated entry under us? */ | 847 | BUG_ON(!dquot->dq_sb); /* Has somebody invalidated entry under us? */ |
| 850 | #endif | 848 | #endif |
| 851 | out: | 849 | out: |
| @@ -874,14 +872,18 @@ static int dqinit_needed(struct inode *inode, int type) | |||
| 874 | static void add_dquot_ref(struct super_block *sb, int type) | 872 | static void add_dquot_ref(struct super_block *sb, int type) |
| 875 | { | 873 | { |
| 876 | struct inode *inode, *old_inode = NULL; | 874 | struct inode *inode, *old_inode = NULL; |
| 875 | #ifdef CONFIG_QUOTA_DEBUG | ||
| 877 | int reserved = 0; | 876 | int reserved = 0; |
| 877 | #endif | ||
| 878 | 878 | ||
| 879 | spin_lock(&inode_lock); | 879 | spin_lock(&inode_lock); |
| 880 | list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { | 880 | list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { |
| 881 | if (inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE|I_NEW)) | 881 | if (inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE|I_NEW)) |
| 882 | continue; | 882 | continue; |
| 883 | #ifdef CONFIG_QUOTA_DEBUG | ||
| 883 | if (unlikely(inode_get_rsv_space(inode) > 0)) | 884 | if (unlikely(inode_get_rsv_space(inode) > 0)) |
| 884 | reserved = 1; | 885 | reserved = 1; |
| 886 | #endif | ||
| 885 | if (!atomic_read(&inode->i_writecount)) | 887 | if (!atomic_read(&inode->i_writecount)) |
| 886 | continue; | 888 | continue; |
| 887 | if (!dqinit_needed(inode, type)) | 889 | if (!dqinit_needed(inode, type)) |
| @@ -903,11 +905,13 @@ static void add_dquot_ref(struct super_block *sb, int type) | |||
| 903 | spin_unlock(&inode_lock); | 905 | spin_unlock(&inode_lock); |
| 904 | iput(old_inode); | 906 | iput(old_inode); |
| 905 | 907 | ||
| 908 | #ifdef CONFIG_QUOTA_DEBUG | ||
| 906 | if (reserved) { | 909 | if (reserved) { |
| 907 | printk(KERN_WARNING "VFS (%s): Writes happened before quota" | 910 | printk(KERN_WARNING "VFS (%s): Writes happened before quota" |
| 908 | " was turned on thus quota information is probably " | 911 | " was turned on thus quota information is probably " |
| 909 | "inconsistent. Please run quotacheck(8).\n", sb->s_id); | 912 | "inconsistent. Please run quotacheck(8).\n", sb->s_id); |
| 910 | } | 913 | } |
| 914 | #endif | ||
| 911 | } | 915 | } |
| 912 | 916 | ||
| 913 | /* | 917 | /* |
| @@ -934,7 +938,7 @@ static int remove_inode_dquot_ref(struct inode *inode, int type, | |||
| 934 | inode->i_dquot[type] = NULL; | 938 | inode->i_dquot[type] = NULL; |
| 935 | if (dquot) { | 939 | if (dquot) { |
| 936 | if (dqput_blocks(dquot)) { | 940 | if (dqput_blocks(dquot)) { |
| 937 | #ifdef __DQUOT_PARANOIA | 941 | #ifdef CONFIG_QUOTA_DEBUG |
| 938 | if (atomic_read(&dquot->dq_count) != 1) | 942 | if (atomic_read(&dquot->dq_count) != 1) |
| 939 | printk(KERN_WARNING "VFS: Adding dquot with dq_count %d to dispose list.\n", atomic_read(&dquot->dq_count)); | 943 | printk(KERN_WARNING "VFS: Adding dquot with dq_count %d to dispose list.\n", atomic_read(&dquot->dq_count)); |
| 940 | #endif | 944 | #endif |
| @@ -2322,34 +2326,34 @@ static int do_set_dqblk(struct dquot *dquot, struct if_dqblk *di) | |||
| 2322 | if (di->dqb_valid & QIF_SPACE) { | 2326 | if (di->dqb_valid & QIF_SPACE) { |
| 2323 | dm->dqb_curspace = di->dqb_curspace - dm->dqb_rsvspace; | 2327 | dm->dqb_curspace = di->dqb_curspace - dm->dqb_rsvspace; |
| 2324 | check_blim = 1; | 2328 | check_blim = 1; |
| 2325 | __set_bit(DQ_LASTSET_B + QIF_SPACE_B, &dquot->dq_flags); | 2329 | set_bit(DQ_LASTSET_B + QIF_SPACE_B, &dquot->dq_flags); |
| 2326 | } | 2330 | } |
| 2327 | if (di->dqb_valid & QIF_BLIMITS) { | 2331 | if (di->dqb_valid & QIF_BLIMITS) { |
| 2328 | dm->dqb_bsoftlimit = qbtos(di->dqb_bsoftlimit); | 2332 | dm->dqb_bsoftlimit = qbtos(di->dqb_bsoftlimit); |
| 2329 | dm->dqb_bhardlimit = qbtos(di->dqb_bhardlimit); | 2333 | dm->dqb_bhardlimit = qbtos(di->dqb_bhardlimit); |
| 2330 | check_blim = 1; | 2334 | check_blim = 1; |
| 2331 | __set_bit(DQ_LASTSET_B + QIF_BLIMITS_B, &dquot->dq_flags); | 2335 | set_bit(DQ_LASTSET_B + QIF_BLIMITS_B, &dquot->dq_flags); |
| 2332 | } | 2336 | } |
| 2333 | if (di->dqb_valid & QIF_INODES) { | 2337 | if (di->dqb_valid & QIF_INODES) { |
| 2334 | dm->dqb_curinodes = di->dqb_curinodes; | 2338 | dm->dqb_curinodes = di->dqb_curinodes; |
| 2335 | check_ilim = 1; | 2339 | check_ilim = 1; |
| 2336 | __set_bit(DQ_LASTSET_B + QIF_INODES_B, &dquot->dq_flags); | 2340 | set_bit(DQ_LASTSET_B + QIF_INODES_B, &dquot->dq_flags); |
| 2337 | } | 2341 | } |
| 2338 | if (di->dqb_valid & QIF_ILIMITS) { | 2342 | if (di->dqb_valid & QIF_ILIMITS) { |
| 2339 | dm->dqb_isoftlimit = di->dqb_isoftlimit; | 2343 | dm->dqb_isoftlimit = di->dqb_isoftlimit; |
| 2340 | dm->dqb_ihardlimit = di->dqb_ihardlimit; | 2344 | dm->dqb_ihardlimit = di->dqb_ihardlimit; |
| 2341 | check_ilim = 1; | 2345 | check_ilim = 1; |
| 2342 | __set_bit(DQ_LASTSET_B + QIF_ILIMITS_B, &dquot->dq_flags); | 2346 | set_bit(DQ_LASTSET_B + QIF_ILIMITS_B, &dquot->dq_flags); |
| 2343 | } | 2347 | } |
| 2344 | if (di->dqb_valid & QIF_BTIME) { | 2348 | if (di->dqb_valid & QIF_BTIME) { |
| 2345 | dm->dqb_btime = di->dqb_btime; | 2349 | dm->dqb_btime = di->dqb_btime; |
| 2346 | check_blim = 1; | 2350 | check_blim = 1; |
| 2347 | __set_bit(DQ_LASTSET_B + QIF_BTIME_B, &dquot->dq_flags); | 2351 | set_bit(DQ_LASTSET_B + QIF_BTIME_B, &dquot->dq_flags); |
| 2348 | } | 2352 | } |
| 2349 | if (di->dqb_valid & QIF_ITIME) { | 2353 | if (di->dqb_valid & QIF_ITIME) { |
| 2350 | dm->dqb_itime = di->dqb_itime; | 2354 | dm->dqb_itime = di->dqb_itime; |
| 2351 | check_ilim = 1; | 2355 | check_ilim = 1; |
| 2352 | __set_bit(DQ_LASTSET_B + QIF_ITIME_B, &dquot->dq_flags); | 2356 | set_bit(DQ_LASTSET_B + QIF_ITIME_B, &dquot->dq_flags); |
| 2353 | } | 2357 | } |
| 2354 | 2358 | ||
| 2355 | if (check_blim) { | 2359 | if (check_blim) { |
diff --git a/fs/udf/balloc.c b/fs/udf/balloc.c index 19626e2491c4..9a9378b4eb5a 100644 --- a/fs/udf/balloc.c +++ b/fs/udf/balloc.c | |||
| @@ -125,9 +125,8 @@ static void udf_bitmap_free_blocks(struct super_block *sb, | |||
| 125 | 125 | ||
| 126 | mutex_lock(&sbi->s_alloc_mutex); | 126 | mutex_lock(&sbi->s_alloc_mutex); |
| 127 | partmap = &sbi->s_partmaps[bloc->partitionReferenceNum]; | 127 | partmap = &sbi->s_partmaps[bloc->partitionReferenceNum]; |
| 128 | if (bloc->logicalBlockNum < 0 || | 128 | if (bloc->logicalBlockNum + count < count || |
| 129 | (bloc->logicalBlockNum + count) > | 129 | (bloc->logicalBlockNum + count) > partmap->s_partition_len) { |
| 130 | partmap->s_partition_len) { | ||
| 131 | udf_debug("%d < %d || %d + %d > %d\n", | 130 | udf_debug("%d < %d || %d + %d > %d\n", |
| 132 | bloc->logicalBlockNum, 0, bloc->logicalBlockNum, | 131 | bloc->logicalBlockNum, 0, bloc->logicalBlockNum, |
| 133 | count, partmap->s_partition_len); | 132 | count, partmap->s_partition_len); |
| @@ -393,9 +392,8 @@ static void udf_table_free_blocks(struct super_block *sb, | |||
| 393 | 392 | ||
| 394 | mutex_lock(&sbi->s_alloc_mutex); | 393 | mutex_lock(&sbi->s_alloc_mutex); |
| 395 | partmap = &sbi->s_partmaps[bloc->partitionReferenceNum]; | 394 | partmap = &sbi->s_partmaps[bloc->partitionReferenceNum]; |
| 396 | if (bloc->logicalBlockNum < 0 || | 395 | if (bloc->logicalBlockNum + count < count || |
| 397 | (bloc->logicalBlockNum + count) > | 396 | (bloc->logicalBlockNum + count) > partmap->s_partition_len) { |
| 398 | partmap->s_partition_len) { | ||
| 399 | udf_debug("%d < %d || %d + %d > %d\n", | 397 | udf_debug("%d < %d || %d + %d > %d\n", |
| 400 | bloc->logicalBlockNum, 0, bloc->logicalBlockNum, count, | 398 | bloc->logicalBlockNum, 0, bloc->logicalBlockNum, count, |
| 401 | partmap->s_partition_len); | 399 | partmap->s_partition_len); |
diff --git a/fs/udf/file.c b/fs/udf/file.c index 1eb06774ed90..4b6a46ccbf46 100644 --- a/fs/udf/file.c +++ b/fs/udf/file.c | |||
| @@ -218,7 +218,7 @@ const struct file_operations udf_file_operations = { | |||
| 218 | .llseek = generic_file_llseek, | 218 | .llseek = generic_file_llseek, |
| 219 | }; | 219 | }; |
| 220 | 220 | ||
| 221 | static int udf_setattr(struct dentry *dentry, struct iattr *iattr) | 221 | int udf_setattr(struct dentry *dentry, struct iattr *iattr) |
| 222 | { | 222 | { |
| 223 | struct inode *inode = dentry->d_inode; | 223 | struct inode *inode = dentry->d_inode; |
| 224 | int error; | 224 | int error; |
diff --git a/fs/udf/inode.c b/fs/udf/inode.c index bb863fe579ac..8a3fbd177cab 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c | |||
| @@ -1314,7 +1314,7 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh) | |||
| 1314 | break; | 1314 | break; |
| 1315 | case ICBTAG_FILE_TYPE_SYMLINK: | 1315 | case ICBTAG_FILE_TYPE_SYMLINK: |
| 1316 | inode->i_data.a_ops = &udf_symlink_aops; | 1316 | inode->i_data.a_ops = &udf_symlink_aops; |
| 1317 | inode->i_op = &page_symlink_inode_operations; | 1317 | inode->i_op = &udf_symlink_inode_operations; |
| 1318 | inode->i_mode = S_IFLNK | S_IRWXUGO; | 1318 | inode->i_mode = S_IFLNK | S_IRWXUGO; |
| 1319 | break; | 1319 | break; |
| 1320 | case ICBTAG_FILE_TYPE_MAIN: | 1320 | case ICBTAG_FILE_TYPE_MAIN: |
diff --git a/fs/udf/namei.c b/fs/udf/namei.c index db423ab078b1..75816025f95f 100644 --- a/fs/udf/namei.c +++ b/fs/udf/namei.c | |||
| @@ -925,7 +925,7 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry, | |||
| 925 | iinfo = UDF_I(inode); | 925 | iinfo = UDF_I(inode); |
| 926 | inode->i_mode = S_IFLNK | S_IRWXUGO; | 926 | inode->i_mode = S_IFLNK | S_IRWXUGO; |
| 927 | inode->i_data.a_ops = &udf_symlink_aops; | 927 | inode->i_data.a_ops = &udf_symlink_aops; |
| 928 | inode->i_op = &page_symlink_inode_operations; | 928 | inode->i_op = &udf_symlink_inode_operations; |
| 929 | 929 | ||
| 930 | if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) { | 930 | if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) { |
| 931 | struct kernel_lb_addr eloc; | 931 | struct kernel_lb_addr eloc; |
| @@ -1393,6 +1393,7 @@ const struct export_operations udf_export_ops = { | |||
| 1393 | const struct inode_operations udf_dir_inode_operations = { | 1393 | const struct inode_operations udf_dir_inode_operations = { |
| 1394 | .lookup = udf_lookup, | 1394 | .lookup = udf_lookup, |
| 1395 | .create = udf_create, | 1395 | .create = udf_create, |
| 1396 | .setattr = udf_setattr, | ||
| 1396 | .link = udf_link, | 1397 | .link = udf_link, |
| 1397 | .unlink = udf_unlink, | 1398 | .unlink = udf_unlink, |
| 1398 | .symlink = udf_symlink, | 1399 | .symlink = udf_symlink, |
| @@ -1401,3 +1402,9 @@ const struct inode_operations udf_dir_inode_operations = { | |||
| 1401 | .mknod = udf_mknod, | 1402 | .mknod = udf_mknod, |
| 1402 | .rename = udf_rename, | 1403 | .rename = udf_rename, |
| 1403 | }; | 1404 | }; |
| 1405 | const struct inode_operations udf_symlink_inode_operations = { | ||
| 1406 | .readlink = generic_readlink, | ||
| 1407 | .follow_link = page_follow_link_light, | ||
| 1408 | .put_link = page_put_link, | ||
| 1409 | .setattr = udf_setattr, | ||
| 1410 | }; | ||
diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h index 4223ac855da9..702a1148e702 100644 --- a/fs/udf/udfdecl.h +++ b/fs/udf/udfdecl.h | |||
| @@ -76,6 +76,7 @@ extern const struct inode_operations udf_dir_inode_operations; | |||
| 76 | extern const struct file_operations udf_dir_operations; | 76 | extern const struct file_operations udf_dir_operations; |
| 77 | extern const struct inode_operations udf_file_inode_operations; | 77 | extern const struct inode_operations udf_file_inode_operations; |
| 78 | extern const struct file_operations udf_file_operations; | 78 | extern const struct file_operations udf_file_operations; |
| 79 | extern const struct inode_operations udf_symlink_inode_operations; | ||
| 79 | extern const struct address_space_operations udf_aops; | 80 | extern const struct address_space_operations udf_aops; |
| 80 | extern const struct address_space_operations udf_adinicb_aops; | 81 | extern const struct address_space_operations udf_adinicb_aops; |
| 81 | extern const struct address_space_operations udf_symlink_aops; | 82 | extern const struct address_space_operations udf_symlink_aops; |
| @@ -131,7 +132,7 @@ extern int udf_write_fi(struct inode *inode, struct fileIdentDesc *, | |||
| 131 | /* file.c */ | 132 | /* file.c */ |
| 132 | extern int udf_ioctl(struct inode *, struct file *, unsigned int, | 133 | extern int udf_ioctl(struct inode *, struct file *, unsigned int, |
| 133 | unsigned long); | 134 | unsigned long); |
| 134 | 135 | extern int udf_setattr(struct dentry *dentry, struct iattr *iattr); | |
| 135 | /* inode.c */ | 136 | /* inode.c */ |
| 136 | extern struct inode *udf_iget(struct super_block *, struct kernel_lb_addr *); | 137 | extern struct inode *udf_iget(struct super_block *, struct kernel_lb_addr *); |
| 137 | extern int udf_sync_inode(struct inode *); | 138 | extern int udf_sync_inode(struct inode *); |
diff --git a/fs/xfs/linux-2.6/xfs_sync.c b/fs/xfs/linux-2.6/xfs_sync.c index 05cd85317f6f..fd9698215759 100644 --- a/fs/xfs/linux-2.6/xfs_sync.c +++ b/fs/xfs/linux-2.6/xfs_sync.c | |||
| @@ -820,10 +820,10 @@ xfs_reclaim_inode( | |||
| 820 | * call into reclaim to find it in a clean state instead of waiting for | 820 | * call into reclaim to find it in a clean state instead of waiting for |
| 821 | * it now. We also don't return errors here - if the error is transient | 821 | * it now. We also don't return errors here - if the error is transient |
| 822 | * then the next reclaim pass will flush the inode, and if the error | 822 | * then the next reclaim pass will flush the inode, and if the error |
| 823 | * is permanent then the next sync reclaim will relcaim the inode and | 823 | * is permanent then the next sync reclaim will reclaim the inode and |
| 824 | * pass on the error. | 824 | * pass on the error. |
| 825 | */ | 825 | */ |
| 826 | if (error && !XFS_FORCED_SHUTDOWN(ip->i_mount)) { | 826 | if (error && error != EAGAIN && !XFS_FORCED_SHUTDOWN(ip->i_mount)) { |
| 827 | xfs_fs_cmn_err(CE_WARN, ip->i_mount, | 827 | xfs_fs_cmn_err(CE_WARN, ip->i_mount, |
| 828 | "inode 0x%llx background reclaim flush failed with %d", | 828 | "inode 0x%llx background reclaim flush failed with %d", |
| 829 | (long long)ip->i_ino, error); | 829 | (long long)ip->i_ino, error); |
diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c index e8fba92d7cd9..2be019136287 100644 --- a/fs/xfs/xfs_log.c +++ b/fs/xfs/xfs_log.c | |||
| @@ -745,9 +745,16 @@ xfs_log_move_tail(xfs_mount_t *mp, | |||
| 745 | 745 | ||
| 746 | /* | 746 | /* |
| 747 | * Determine if we have a transaction that has gone to disk | 747 | * Determine if we have a transaction that has gone to disk |
| 748 | * that needs to be covered. Log activity needs to be idle (no AIL and | 748 | * that needs to be covered. To begin the transition to the idle state |
| 749 | * nothing in the iclogs). And, we need to be in the right state indicating | 749 | * firstly the log needs to be idle (no AIL and nothing in the iclogs). |
| 750 | * something has gone out. | 750 | * If we are then in a state where covering is needed, the caller is informed |
| 751 | * that dummy transactions are required to move the log into the idle state. | ||
| 752 | * | ||
| 753 | * Because this is called as part of the sync process, we should also indicate | ||
| 754 | * that dummy transactions should be issued in anything but the covered or | ||
| 755 | * idle states. This ensures that the log tail is accurately reflected in | ||
| 756 | * the log at the end of the sync, hence if a crash occurrs avoids replay | ||
| 757 | * of transactions where the metadata is already on disk. | ||
| 751 | */ | 758 | */ |
| 752 | int | 759 | int |
| 753 | xfs_log_need_covered(xfs_mount_t *mp) | 760 | xfs_log_need_covered(xfs_mount_t *mp) |
| @@ -759,17 +766,24 @@ xfs_log_need_covered(xfs_mount_t *mp) | |||
| 759 | return 0; | 766 | return 0; |
| 760 | 767 | ||
| 761 | spin_lock(&log->l_icloglock); | 768 | spin_lock(&log->l_icloglock); |
| 762 | if (((log->l_covered_state == XLOG_STATE_COVER_NEED) || | 769 | switch (log->l_covered_state) { |
| 763 | (log->l_covered_state == XLOG_STATE_COVER_NEED2)) | 770 | case XLOG_STATE_COVER_DONE: |
| 764 | && !xfs_trans_ail_tail(log->l_ailp) | 771 | case XLOG_STATE_COVER_DONE2: |
| 765 | && xlog_iclogs_empty(log)) { | 772 | case XLOG_STATE_COVER_IDLE: |
| 766 | if (log->l_covered_state == XLOG_STATE_COVER_NEED) | 773 | break; |
| 767 | log->l_covered_state = XLOG_STATE_COVER_DONE; | 774 | case XLOG_STATE_COVER_NEED: |
| 768 | else { | 775 | case XLOG_STATE_COVER_NEED2: |
| 769 | ASSERT(log->l_covered_state == XLOG_STATE_COVER_NEED2); | 776 | if (!xfs_trans_ail_tail(log->l_ailp) && |
| 770 | log->l_covered_state = XLOG_STATE_COVER_DONE2; | 777 | xlog_iclogs_empty(log)) { |
| 778 | if (log->l_covered_state == XLOG_STATE_COVER_NEED) | ||
| 779 | log->l_covered_state = XLOG_STATE_COVER_DONE; | ||
| 780 | else | ||
| 781 | log->l_covered_state = XLOG_STATE_COVER_DONE2; | ||
| 771 | } | 782 | } |
| 783 | /* FALLTHRU */ | ||
| 784 | default: | ||
| 772 | needed = 1; | 785 | needed = 1; |
| 786 | break; | ||
| 773 | } | 787 | } |
| 774 | spin_unlock(&log->l_icloglock); | 788 | spin_unlock(&log->l_icloglock); |
| 775 | return needed; | 789 | return needed; |
