Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'ceph-for-6.4-rc1' of https://github.com/ceph/ceph-client

Pull ceph updates from Ilya Dryomov:
"A few filesystem improvements, with a rather nasty use-after-free fix
from Xiubo intended for stable"

* tag 'ceph-for-6.4-rc1' of https://github.com/ceph/ceph-client:
ceph: reorder fields in 'struct ceph_snapid_map'
ceph: pass ino# instead of old_dentry if it's disconnected
ceph: fix potential use-after-free bug when trimming caps
ceph: implement writeback livelock avoidance using page tagging
ceph: do not print the whole xattr value if it's too long

+101 -46
+10 -1
fs/ceph/addr.c
··· 808 808 bool should_loop, range_whole = false; 809 809 bool done = false; 810 810 bool caching = ceph_is_cache_enabled(inode); 811 + xa_mark_t tag; 811 812 812 813 if (wbc->sync_mode == WB_SYNC_NONE && 813 814 fsc->write_congested) ··· 835 834 start_index = wbc->range_cyclic ? mapping->writeback_index : 0; 836 835 index = start_index; 837 836 837 + if (wbc->sync_mode == WB_SYNC_ALL || wbc->tagged_writepages) { 838 + tag = PAGECACHE_TAG_TOWRITE; 839 + } else { 840 + tag = PAGECACHE_TAG_DIRTY; 841 + } 838 842 retry: 839 843 /* find oldest snap context with dirty data */ 840 844 snapc = get_oldest_context(inode, &ceph_wbc, NULL); ··· 878 872 dout(" non-head snapc, range whole\n"); 879 873 } 880 874 875 + if (wbc->sync_mode == WB_SYNC_ALL || wbc->tagged_writepages) 876 + tag_pages_for_writeback(mapping, index, end); 877 + 881 878 ceph_put_snap_context(last_snapc); 882 879 last_snapc = snapc; 883 880 ··· 897 888 898 889 get_more_pages: 899 890 nr_folios = filemap_get_folios_tag(mapping, &index, 900 - end, PAGECACHE_TAG_DIRTY, &fbatch); 891 + end, tag, &fbatch); 901 892 dout("pagevec_lookup_range_tag got %d\n", nr_folios); 902 893 if (!nr_folios && !locked_pages) 903 894 break;
+1 -1
fs/ceph/caps.c
··· 431 431 * 432 432 * Called with i_ceph_lock held. 433 433 */ 434 - static struct ceph_cap *__get_cap_for_mds(struct ceph_inode_info *ci, int mds) 434 + struct ceph_cap *__get_cap_for_mds(struct ceph_inode_info *ci, int mds) 435 435 { 436 436 struct ceph_cap *cap; 437 437 struct rb_node *n = ci->i_caps.rb_node;
+11 -5
fs/ceph/debugfs.c
··· 248 248 return 0; 249 249 } 250 250 251 - static int caps_show_cb(struct inode *inode, struct ceph_cap *cap, void *p) 251 + static int caps_show_cb(struct inode *inode, int mds, void *p) 252 252 { 253 + struct ceph_inode_info *ci = ceph_inode(inode); 253 254 struct seq_file *s = p; 255 + struct ceph_cap *cap; 254 256 255 - seq_printf(s, "0x%-17llx%-3d%-17s%-17s\n", ceph_ino(inode), 256 - cap->session->s_mds, 257 - ceph_cap_string(cap->issued), 258 - ceph_cap_string(cap->implemented)); 257 + spin_lock(&ci->i_ceph_lock); 258 + cap = __get_cap_for_mds(ci, mds); 259 + if (cap) 260 + seq_printf(s, "0x%-17llx%-3d%-17s%-17s\n", ceph_ino(inode), 261 + cap->session->s_mds, 262 + ceph_cap_string(cap->issued), 263 + ceph_cap_string(cap->implemented)); 264 + spin_unlock(&ci->i_ceph_lock); 259 265 return 0; 260 266 } 261 267
+11 -2
fs/ceph/dir.c
··· 1050 1050 struct ceph_mds_request *req; 1051 1051 int err; 1052 1052 1053 + if (dentry->d_flags & DCACHE_DISCONNECTED) 1054 + return -EINVAL; 1055 + 1053 1056 err = ceph_wait_on_conflict_unlink(dentry); 1054 1057 if (err) 1055 1058 return err; ··· 1060 1057 if (ceph_snap(dir) != CEPH_NOSNAP) 1061 1058 return -EROFS; 1062 1059 1063 - dout("link in dir %p old_dentry %p dentry %p\n", dir, 1064 - old_dentry, dentry); 1060 + dout("link in dir %p %llx.%llx old_dentry %p:'%pd' dentry %p:'%pd'\n", 1061 + dir, ceph_vinop(dir), old_dentry, old_dentry, dentry, dentry); 1065 1062 req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LINK, USE_AUTH_MDS); 1066 1063 if (IS_ERR(req)) { 1067 1064 d_drop(dentry); ··· 1070 1067 req->r_dentry = dget(dentry); 1071 1068 req->r_num_caps = 2; 1072 1069 req->r_old_dentry = dget(old_dentry); 1070 + /* 1071 + * The old_dentry maybe a DCACHE_DISCONNECTED dentry, then we 1072 + * will just pass the ino# to MDSs. 1073 + */ 1074 + if (old_dentry->d_flags & DCACHE_DISCONNECTED) 1075 + req->r_ino2 = ceph_vino(d_inode(old_dentry)); 1073 1076 req->r_parent = dir; 1074 1077 ihold(dir); 1075 1078 set_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags);
+51 -27
fs/ceph/mds_client.c
··· 1632 1632 * Caller must hold session s_mutex. 1633 1633 */ 1634 1634 int ceph_iterate_session_caps(struct ceph_mds_session *session, 1635 - int (*cb)(struct inode *, struct ceph_cap *, 1636 - void *), void *arg) 1635 + int (*cb)(struct inode *, int mds, void *), 1636 + void *arg) 1637 1637 { 1638 1638 struct list_head *p; 1639 1639 struct ceph_cap *cap; ··· 1645 1645 spin_lock(&session->s_cap_lock); 1646 1646 p = session->s_caps.next; 1647 1647 while (p != &session->s_caps) { 1648 + int mds; 1649 + 1648 1650 cap = list_entry(p, struct ceph_cap, session_caps); 1649 1651 inode = igrab(&cap->ci->netfs.inode); 1650 1652 if (!inode) { ··· 1654 1652 continue; 1655 1653 } 1656 1654 session->s_cap_iterator = cap; 1655 + mds = cap->mds; 1657 1656 spin_unlock(&session->s_cap_lock); 1658 1657 1659 1658 if (last_inode) { ··· 1666 1663 old_cap = NULL; 1667 1664 } 1668 1665 1669 - ret = cb(inode, cap, arg); 1666 + ret = cb(inode, mds, arg); 1670 1667 last_inode = inode; 1671 1668 1672 1669 spin_lock(&session->s_cap_lock); ··· 1699 1696 return ret; 1700 1697 } 1701 1698 1702 - static int remove_session_caps_cb(struct inode *inode, struct ceph_cap *cap, 1703 - void *arg) 1699 + static int remove_session_caps_cb(struct inode *inode, int mds, void *arg) 1704 1700 { 1705 1701 struct ceph_inode_info *ci = ceph_inode(inode); 1706 1702 bool invalidate = false; 1707 - int iputs; 1703 + struct ceph_cap *cap; 1704 + int iputs = 0; 1708 1705 1709 - dout("removing cap %p, ci is %p, inode is %p\n", 1710 - cap, ci, &ci->netfs.inode); 1711 1706 spin_lock(&ci->i_ceph_lock); 1712 - iputs = ceph_purge_inode_cap(inode, cap, &invalidate); 1707 + cap = __get_cap_for_mds(ci, mds); 1708 + if (cap) { 1709 + dout(" removing cap %p, ci is %p, inode is %p\n", 1710 + cap, ci, &ci->netfs.inode); 1711 + 1712 + iputs = ceph_purge_inode_cap(inode, cap, &invalidate); 1713 + } 1713 1714 spin_unlock(&ci->i_ceph_lock); 1714 1715 1715 - wake_up_all(&ci->i_cap_wq); 1716 + if (cap) 1717 + wake_up_all(&ci->i_cap_wq); 1716 1718 if (invalidate) 1717 1719 ceph_queue_invalidate(inode); 1718 1720 while (iputs--) ··· 1788 1780 * 1789 1781 * caller must hold s_mutex. 1790 1782 */ 1791 - static int wake_up_session_cb(struct inode *inode, struct ceph_cap *cap, 1792 - void *arg) 1783 + static int wake_up_session_cb(struct inode *inode, int mds, void *arg) 1793 1784 { 1794 1785 struct ceph_inode_info *ci = ceph_inode(inode); 1795 1786 unsigned long ev = (unsigned long)arg; ··· 1799 1792 ci->i_requested_max_size = 0; 1800 1793 spin_unlock(&ci->i_ceph_lock); 1801 1794 } else if (ev == RENEWCAPS) { 1802 - if (cap->cap_gen < atomic_read(&cap->session->s_cap_gen)) { 1803 - /* mds did not re-issue stale cap */ 1804 - spin_lock(&ci->i_ceph_lock); 1795 + struct ceph_cap *cap; 1796 + 1797 + spin_lock(&ci->i_ceph_lock); 1798 + cap = __get_cap_for_mds(ci, mds); 1799 + /* mds did not re-issue stale cap */ 1800 + if (cap && cap->cap_gen < atomic_read(&cap->session->s_cap_gen)) 1805 1801 cap->issued = cap->implemented = CEPH_CAP_PIN; 1806 - spin_unlock(&ci->i_ceph_lock); 1807 - } 1802 + spin_unlock(&ci->i_ceph_lock); 1808 1803 } else if (ev == FORCE_RO) { 1809 1804 } 1810 1805 wake_up_all(&ci->i_cap_wq); ··· 1968 1959 * Yes, this is a bit sloppy. Our only real goal here is to respond to 1969 1960 * memory pressure from the MDS, though, so it needn't be perfect. 1970 1961 */ 1971 - static int trim_caps_cb(struct inode *inode, struct ceph_cap *cap, void *arg) 1962 + static int trim_caps_cb(struct inode *inode, int mds, void *arg) 1972 1963 { 1973 1964 int *remaining = arg; 1974 1965 struct ceph_inode_info *ci = ceph_inode(inode); 1975 1966 int used, wanted, oissued, mine; 1967 + struct ceph_cap *cap; 1976 1968 1977 1969 if (*remaining <= 0) 1978 1970 return -1; 1979 1971 1980 1972 spin_lock(&ci->i_ceph_lock); 1973 + cap = __get_cap_for_mds(ci, mds); 1974 + if (!cap) { 1975 + spin_unlock(&ci->i_ceph_lock); 1976 + return 0; 1977 + } 1981 1978 mine = cap->issued | cap->implemented; 1982 1979 used = __ceph_caps_used(ci); 1983 1980 wanted = __ceph_caps_file_wanted(ci); ··· 2570 2555 u64 ino1 = 0, ino2 = 0; 2571 2556 int pathlen1 = 0, pathlen2 = 0; 2572 2557 bool freepath1 = false, freepath2 = false; 2558 + struct dentry *old_dentry = NULL; 2573 2559 int len; 2574 2560 u16 releases; 2575 2561 void *p, *end; ··· 2588 2572 } 2589 2573 2590 2574 /* If r_old_dentry is set, then assume that its parent is locked */ 2591 - ret = set_request_path_attr(NULL, req->r_old_dentry, 2575 + if (req->r_old_dentry && 2576 + !(req->r_old_dentry->d_flags & DCACHE_DISCONNECTED)) 2577 + old_dentry = req->r_old_dentry; 2578 + ret = set_request_path_attr(NULL, old_dentry, 2592 2579 req->r_old_dentry_dir, 2593 2580 req->r_path2, req->r_ino2.ino, 2594 2581 &path2, &pathlen2, &ino2, &freepath2, true); ··· 3930 3911 /* 3931 3912 * Encode information about a cap for a reconnect with the MDS. 3932 3913 */ 3933 - static int reconnect_caps_cb(struct inode *inode, struct ceph_cap *cap, 3934 - void *arg) 3914 + static int reconnect_caps_cb(struct inode *inode, int mds, void *arg) 3935 3915 { 3936 3916 union { 3937 3917 struct ceph_mds_cap_reconnect v2; 3938 3918 struct ceph_mds_cap_reconnect_v1 v1; 3939 3919 } rec; 3940 - struct ceph_inode_info *ci = cap->ci; 3920 + struct ceph_inode_info *ci = ceph_inode(inode); 3941 3921 struct ceph_reconnect_state *recon_state = arg; 3942 3922 struct ceph_pagelist *pagelist = recon_state->pagelist; 3943 3923 struct dentry *dentry; 3924 + struct ceph_cap *cap; 3944 3925 char *path; 3945 - int pathlen = 0, err; 3926 + int pathlen = 0, err = 0; 3946 3927 u64 pathbase; 3947 3928 u64 snap_follows; 3948 - 3949 - dout(" adding %p ino %llx.%llx cap %p %lld %s\n", 3950 - inode, ceph_vinop(inode), cap, cap->cap_id, 3951 - ceph_cap_string(cap->issued)); 3952 3929 3953 3930 dentry = d_find_primary(inode); 3954 3931 if (dentry) { ··· 3962 3947 } 3963 3948 3964 3949 spin_lock(&ci->i_ceph_lock); 3950 + cap = __get_cap_for_mds(ci, mds); 3951 + if (!cap) { 3952 + spin_unlock(&ci->i_ceph_lock); 3953 + goto out_err; 3954 + } 3955 + dout(" adding %p ino %llx.%llx cap %p %lld %s\n", 3956 + inode, ceph_vinop(inode), cap, cap->cap_id, 3957 + ceph_cap_string(cap->issued)); 3958 + 3965 3959 cap->seq = 0; /* reset cap seq */ 3966 3960 cap->issue_seq = 0; /* and issue_seq */ 3967 3961 cap->mseq = 0; /* and migrate_seq */
+2 -3
fs/ceph/mds_client.h
··· 355 355 struct rb_node node; 356 356 struct list_head lru; 357 357 atomic_t ref; 358 - u64 snap; 359 358 dev_t dev; 359 + u64 snap; 360 360 unsigned long last_used; 361 361 }; 362 362 ··· 541 541 extern void ceph_queue_cap_reclaim_work(struct ceph_mds_client *mdsc); 542 542 extern void ceph_reclaim_caps_nr(struct ceph_mds_client *mdsc, int nr); 543 543 extern int ceph_iterate_session_caps(struct ceph_mds_session *session, 544 - int (*cb)(struct inode *, 545 - struct ceph_cap *, void *), 544 + int (*cb)(struct inode *, int mds, void *), 546 545 void *arg); 547 546 extern void ceph_mdsc_pre_umount(struct ceph_mds_client *mdsc); 548 547
+2
fs/ceph/super.h
··· 1192 1192 struct ceph_mds_session *session); 1193 1193 void ceph_kick_flushing_inode_caps(struct ceph_mds_session *session, 1194 1194 struct ceph_inode_info *ci); 1195 + extern struct ceph_cap *__get_cap_for_mds(struct ceph_inode_info *ci, 1196 + int mds); 1195 1197 extern struct ceph_cap *ceph_get_cap_for_mds(struct ceph_inode_info *ci, 1196 1198 int mds); 1197 1199 extern void ceph_take_cap_refs(struct ceph_inode_info *ci, int caps,
+13 -7
fs/ceph/xattr.c
··· 535 535 return NULL; 536 536 } 537 537 538 + #define MAX_XATTR_VAL_PRINT_LEN 256 539 + 538 540 static int __set_xattr(struct ceph_inode_info *ci, 539 541 const char *name, int name_len, 540 542 const char *val, int val_len, ··· 599 597 xattr->should_free_name = update_xattr; 600 598 601 599 ci->i_xattrs.count++; 602 - dout("__set_xattr count=%d\n", ci->i_xattrs.count); 600 + dout("%s count=%d\n", __func__, ci->i_xattrs.count); 603 601 } else { 604 602 kfree(*newxattr); 605 603 *newxattr = NULL; ··· 627 625 if (new) { 628 626 rb_link_node(&xattr->node, parent, p); 629 627 rb_insert_color(&xattr->node, &ci->i_xattrs.index); 630 - dout("__set_xattr_val p=%p\n", p); 628 + dout("%s p=%p\n", __func__, p); 631 629 } 632 630 633 - dout("__set_xattr_val added %llx.%llx xattr %p %.*s=%.*s\n", 634 - ceph_vinop(&ci->netfs.inode), xattr, name_len, name, val_len, val); 631 + dout("%s added %llx.%llx xattr %p %.*s=%.*s%s\n", __func__, 632 + ceph_vinop(&ci->netfs.inode), xattr, name_len, name, 633 + min(val_len, MAX_XATTR_VAL_PRINT_LEN), val, 634 + val_len > MAX_XATTR_VAL_PRINT_LEN ? "..." : ""); 635 635 636 636 return 0; 637 637 } ··· 659 655 else if (c > 0) 660 656 p = &(*p)->rb_right; 661 657 else { 662 - dout("__get_xattr %s: found %.*s\n", name, 663 - xattr->val_len, xattr->val); 658 + int len = min(xattr->val_len, MAX_XATTR_VAL_PRINT_LEN); 659 + 660 + dout("%s %s: found %.*s%s\n", __func__, name, len, 661 + xattr->val, xattr->val_len > len ? "..." : ""); 664 662 return xattr; 665 663 } 666 664 } 667 665 668 - dout("__get_xattr %s: not found\n", name); 666 + dout("%s %s: not found\n", __func__, name); 669 667 670 668 return NULL; 671 669 }