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-5.1-rc7' of git://github.com/ceph/ceph-client

Pull ceph fixes from Ilya Dryomov:
"dentry name handling fixes from Jeff and a memory leak fix from Zheng.

Both are old issues, marked for stable"

* tag 'ceph-for-5.1-rc7' of git://github.com/ceph/ceph-client:
ceph: fix ci->i_head_snapc leak
ceph: handle the case where a dentry has been renamed on outstanding req
ceph: ensure d_name stability in ceph_dentry_hash()
ceph: only use d_name directly when parent is locked

+85 -14
+5 -1
fs/ceph/dir.c
··· 1766 1766 unsigned ceph_dentry_hash(struct inode *dir, struct dentry *dn) 1767 1767 { 1768 1768 struct ceph_inode_info *dci = ceph_inode(dir); 1769 + unsigned hash; 1769 1770 1770 1771 switch (dci->i_dir_layout.dl_dir_hash) { 1771 1772 case 0: /* for backward compat */ ··· 1774 1773 return dn->d_name.hash; 1775 1774 1776 1775 default: 1777 - return ceph_str_hash(dci->i_dir_layout.dl_dir_hash, 1776 + spin_lock(&dn->d_lock); 1777 + hash = ceph_str_hash(dci->i_dir_layout.dl_dir_hash, 1778 1778 dn->d_name.name, dn->d_name.len); 1779 + spin_unlock(&dn->d_lock); 1780 + return hash; 1779 1781 } 1780 1782 } 1781 1783
+15 -1
fs/ceph/inode.c
··· 1163 1163 return 0; 1164 1164 } 1165 1165 1166 + static int d_name_cmp(struct dentry *dentry, const char *name, size_t len) 1167 + { 1168 + int ret; 1169 + 1170 + /* take d_lock to ensure dentry->d_name stability */ 1171 + spin_lock(&dentry->d_lock); 1172 + ret = dentry->d_name.len - len; 1173 + if (!ret) 1174 + ret = memcmp(dentry->d_name.name, name, len); 1175 + spin_unlock(&dentry->d_lock); 1176 + return ret; 1177 + } 1178 + 1166 1179 /* 1167 1180 * Incorporate results into the local cache. This is either just 1168 1181 * one inode, or a directory, dentry, and possibly linked-to inode (e.g., ··· 1425 1412 err = splice_dentry(&req->r_dentry, in); 1426 1413 if (err < 0) 1427 1414 goto done; 1428 - } else if (rinfo->head->is_dentry) { 1415 + } else if (rinfo->head->is_dentry && 1416 + !d_name_cmp(req->r_dentry, rinfo->dname, rinfo->dname_len)) { 1429 1417 struct ceph_vino *ptvino = NULL; 1430 1418 1431 1419 if ((le32_to_cpu(rinfo->diri.in->cap.caps) & CEPH_CAP_FILE_SHARED) ||
+59 -11
fs/ceph/mds_client.c
··· 1414 1414 list_add(&ci->i_prealloc_cap_flush->i_list, &to_remove); 1415 1415 ci->i_prealloc_cap_flush = NULL; 1416 1416 } 1417 + 1418 + if (drop && 1419 + ci->i_wrbuffer_ref_head == 0 && 1420 + ci->i_wr_ref == 0 && 1421 + ci->i_dirty_caps == 0 && 1422 + ci->i_flushing_caps == 0) { 1423 + ceph_put_snap_context(ci->i_head_snapc); 1424 + ci->i_head_snapc = NULL; 1425 + } 1417 1426 } 1418 1427 spin_unlock(&ci->i_ceph_lock); 1419 1428 while (!list_empty(&to_remove)) { ··· 2170 2161 return path; 2171 2162 } 2172 2163 2164 + /* Duplicate the dentry->d_name.name safely */ 2165 + static int clone_dentry_name(struct dentry *dentry, const char **ppath, 2166 + int *ppathlen) 2167 + { 2168 + u32 len; 2169 + char *name; 2170 + 2171 + retry: 2172 + len = READ_ONCE(dentry->d_name.len); 2173 + name = kmalloc(len + 1, GFP_NOFS); 2174 + if (!name) 2175 + return -ENOMEM; 2176 + 2177 + spin_lock(&dentry->d_lock); 2178 + if (dentry->d_name.len != len) { 2179 + spin_unlock(&dentry->d_lock); 2180 + kfree(name); 2181 + goto retry; 2182 + } 2183 + memcpy(name, dentry->d_name.name, len); 2184 + spin_unlock(&dentry->d_lock); 2185 + 2186 + name[len] = '\0'; 2187 + *ppath = name; 2188 + *ppathlen = len; 2189 + return 0; 2190 + } 2191 + 2173 2192 static int build_dentry_path(struct dentry *dentry, struct inode *dir, 2174 2193 const char **ppath, int *ppathlen, u64 *pino, 2175 - int *pfreepath) 2194 + bool *pfreepath, bool parent_locked) 2176 2195 { 2196 + int ret; 2177 2197 char *path; 2178 2198 2179 2199 rcu_read_lock(); ··· 2211 2173 if (dir && ceph_snap(dir) == CEPH_NOSNAP) { 2212 2174 *pino = ceph_ino(dir); 2213 2175 rcu_read_unlock(); 2214 - *ppath = dentry->d_name.name; 2215 - *ppathlen = dentry->d_name.len; 2176 + if (parent_locked) { 2177 + *ppath = dentry->d_name.name; 2178 + *ppathlen = dentry->d_name.len; 2179 + } else { 2180 + ret = clone_dentry_name(dentry, ppath, ppathlen); 2181 + if (ret) 2182 + return ret; 2183 + *pfreepath = true; 2184 + } 2216 2185 return 0; 2217 2186 } 2218 2187 rcu_read_unlock(); ··· 2227 2182 if (IS_ERR(path)) 2228 2183 return PTR_ERR(path); 2229 2184 *ppath = path; 2230 - *pfreepath = 1; 2185 + *pfreepath = true; 2231 2186 return 0; 2232 2187 } 2233 2188 2234 2189 static int build_inode_path(struct inode *inode, 2235 2190 const char **ppath, int *ppathlen, u64 *pino, 2236 - int *pfreepath) 2191 + bool *pfreepath) 2237 2192 { 2238 2193 struct dentry *dentry; 2239 2194 char *path; ··· 2249 2204 if (IS_ERR(path)) 2250 2205 return PTR_ERR(path); 2251 2206 *ppath = path; 2252 - *pfreepath = 1; 2207 + *pfreepath = true; 2253 2208 return 0; 2254 2209 } 2255 2210 ··· 2260 2215 static int set_request_path_attr(struct inode *rinode, struct dentry *rdentry, 2261 2216 struct inode *rdiri, const char *rpath, 2262 2217 u64 rino, const char **ppath, int *pathlen, 2263 - u64 *ino, int *freepath) 2218 + u64 *ino, bool *freepath, bool parent_locked) 2264 2219 { 2265 2220 int r = 0; 2266 2221 ··· 2270 2225 ceph_snap(rinode)); 2271 2226 } else if (rdentry) { 2272 2227 r = build_dentry_path(rdentry, rdiri, ppath, pathlen, ino, 2273 - freepath); 2228 + freepath, parent_locked); 2274 2229 dout(" dentry %p %llx/%.*s\n", rdentry, *ino, *pathlen, 2275 2230 *ppath); 2276 2231 } else if (rpath || rino) { ··· 2296 2251 const char *path2 = NULL; 2297 2252 u64 ino1 = 0, ino2 = 0; 2298 2253 int pathlen1 = 0, pathlen2 = 0; 2299 - int freepath1 = 0, freepath2 = 0; 2254 + bool freepath1 = false, freepath2 = false; 2300 2255 int len; 2301 2256 u16 releases; 2302 2257 void *p, *end; ··· 2304 2259 2305 2260 ret = set_request_path_attr(req->r_inode, req->r_dentry, 2306 2261 req->r_parent, req->r_path1, req->r_ino1.ino, 2307 - &path1, &pathlen1, &ino1, &freepath1); 2262 + &path1, &pathlen1, &ino1, &freepath1, 2263 + test_bit(CEPH_MDS_R_PARENT_LOCKED, 2264 + &req->r_req_flags)); 2308 2265 if (ret < 0) { 2309 2266 msg = ERR_PTR(ret); 2310 2267 goto out; 2311 2268 } 2312 2269 2270 + /* If r_old_dentry is set, then assume that its parent is locked */ 2313 2271 ret = set_request_path_attr(NULL, req->r_old_dentry, 2314 2272 req->r_old_dentry_dir, 2315 2273 req->r_path2, req->r_ino2.ino, 2316 - &path2, &pathlen2, &ino2, &freepath2); 2274 + &path2, &pathlen2, &ino2, &freepath2, true); 2317 2275 if (ret < 0) { 2318 2276 msg = ERR_PTR(ret); 2319 2277 goto out_free1;
+6 -1
fs/ceph/snap.c
··· 572 572 old_snapc = NULL; 573 573 574 574 update_snapc: 575 - if (ci->i_head_snapc) { 575 + if (ci->i_wrbuffer_ref_head == 0 && 576 + ci->i_wr_ref == 0 && 577 + ci->i_dirty_caps == 0 && 578 + ci->i_flushing_caps == 0) { 579 + ci->i_head_snapc = NULL; 580 + } else { 576 581 ci->i_head_snapc = ceph_get_snap_context(new_snapc); 577 582 dout(" new snapc is %p\n", new_snapc); 578 583 }