aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/ceph/dir.c6
-rw-r--r--fs/ceph/inode.c16
-rw-r--r--fs/ceph/mds_client.c70
-rw-r--r--fs/ceph/snap.c7
4 files changed, 85 insertions, 14 deletions
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c
index a8f429882249..0637149fb9f9 100644
--- a/fs/ceph/dir.c
+++ b/fs/ceph/dir.c
@@ -1766,6 +1766,7 @@ static ssize_t ceph_read_dir(struct file *file, char __user *buf, size_t size,
1766unsigned ceph_dentry_hash(struct inode *dir, struct dentry *dn) 1766unsigned ceph_dentry_hash(struct inode *dir, struct dentry *dn)
1767{ 1767{
1768 struct ceph_inode_info *dci = ceph_inode(dir); 1768 struct ceph_inode_info *dci = ceph_inode(dir);
1769 unsigned hash;
1769 1770
1770 switch (dci->i_dir_layout.dl_dir_hash) { 1771 switch (dci->i_dir_layout.dl_dir_hash) {
1771 case 0: /* for backward compat */ 1772 case 0: /* for backward compat */
@@ -1773,8 +1774,11 @@ unsigned ceph_dentry_hash(struct inode *dir, struct dentry *dn)
1773 return dn->d_name.hash; 1774 return dn->d_name.hash;
1774 1775
1775 default: 1776 default:
1776 return ceph_str_hash(dci->i_dir_layout.dl_dir_hash, 1777 spin_lock(&dn->d_lock);
1778 hash = ceph_str_hash(dci->i_dir_layout.dl_dir_hash,
1777 dn->d_name.name, dn->d_name.len); 1779 dn->d_name.name, dn->d_name.len);
1780 spin_unlock(&dn->d_lock);
1781 return hash;
1778 } 1782 }
1779} 1783}
1780 1784
diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c
index 2d61ddda9bf5..c2feb310ac1e 100644
--- a/fs/ceph/inode.c
+++ b/fs/ceph/inode.c
@@ -1163,6 +1163,19 @@ static int splice_dentry(struct dentry **pdn, struct inode *in)
1163 return 0; 1163 return 0;
1164} 1164}
1165 1165
1166static 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 * Incorporate results into the local cache. This is either just 1180 * Incorporate results into the local cache. This is either just
1168 * one inode, or a directory, dentry, and possibly linked-to inode (e.g., 1181 * one inode, or a directory, dentry, and possibly linked-to inode (e.g.,
@@ -1412,7 +1425,8 @@ retry_lookup:
1412 err = splice_dentry(&req->r_dentry, in); 1425 err = splice_dentry(&req->r_dentry, in);
1413 if (err < 0) 1426 if (err < 0)
1414 goto done; 1427 goto done;
1415 } else if (rinfo->head->is_dentry) { 1428 } else if (rinfo->head->is_dentry &&
1429 !d_name_cmp(req->r_dentry, rinfo->dname, rinfo->dname_len)) {
1416 struct ceph_vino *ptvino = NULL; 1430 struct ceph_vino *ptvino = NULL;
1417 1431
1418 if ((le32_to_cpu(rinfo->diri.in->cap.caps) & CEPH_CAP_FILE_SHARED) || 1432 if ((le32_to_cpu(rinfo->diri.in->cap.caps) & CEPH_CAP_FILE_SHARED) ||
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c
index 21c33ed048ed..9049c2a3e972 100644
--- a/fs/ceph/mds_client.c
+++ b/fs/ceph/mds_client.c
@@ -1414,6 +1414,15 @@ static int remove_session_caps_cb(struct inode *inode, struct ceph_cap *cap,
1414 list_add(&ci->i_prealloc_cap_flush->i_list, &to_remove); 1414 list_add(&ci->i_prealloc_cap_flush->i_list, &to_remove);
1415 ci->i_prealloc_cap_flush = NULL; 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 spin_unlock(&ci->i_ceph_lock); 1427 spin_unlock(&ci->i_ceph_lock);
1419 while (!list_empty(&to_remove)) { 1428 while (!list_empty(&to_remove)) {
@@ -2161,10 +2170,39 @@ retry:
2161 return path; 2170 return path;
2162} 2171}
2163 2172
2173/* Duplicate the dentry->d_name.name safely */
2174static int clone_dentry_name(struct dentry *dentry, const char **ppath,
2175 int *ppathlen)
2176{
2177 u32 len;
2178 char *name;
2179
2180retry:
2181 len = READ_ONCE(dentry->d_name.len);
2182 name = kmalloc(len + 1, GFP_NOFS);
2183 if (!name)
2184 return -ENOMEM;
2185
2186 spin_lock(&dentry->d_lock);
2187 if (dentry->d_name.len != len) {
2188 spin_unlock(&dentry->d_lock);
2189 kfree(name);
2190 goto retry;
2191 }
2192 memcpy(name, dentry->d_name.name, len);
2193 spin_unlock(&dentry->d_lock);
2194
2195 name[len] = '\0';
2196 *ppath = name;
2197 *ppathlen = len;
2198 return 0;
2199}
2200
2164static int build_dentry_path(struct dentry *dentry, struct inode *dir, 2201static int build_dentry_path(struct dentry *dentry, struct inode *dir,
2165 const char **ppath, int *ppathlen, u64 *pino, 2202 const char **ppath, int *ppathlen, u64 *pino,
2166 int *pfreepath) 2203 bool *pfreepath, bool parent_locked)
2167{ 2204{
2205 int ret;
2168 char *path; 2206 char *path;
2169 2207
2170 rcu_read_lock(); 2208 rcu_read_lock();
@@ -2173,8 +2211,15 @@ static int build_dentry_path(struct dentry *dentry, struct inode *dir,
2173 if (dir && ceph_snap(dir) == CEPH_NOSNAP) { 2211 if (dir && ceph_snap(dir) == CEPH_NOSNAP) {
2174 *pino = ceph_ino(dir); 2212 *pino = ceph_ino(dir);
2175 rcu_read_unlock(); 2213 rcu_read_unlock();
2176 *ppath = dentry->d_name.name; 2214 if (parent_locked) {
2177 *ppathlen = dentry->d_name.len; 2215 *ppath = dentry->d_name.name;
2216 *ppathlen = dentry->d_name.len;
2217 } else {
2218 ret = clone_dentry_name(dentry, ppath, ppathlen);
2219 if (ret)
2220 return ret;
2221 *pfreepath = true;
2222 }
2178 return 0; 2223 return 0;
2179 } 2224 }
2180 rcu_read_unlock(); 2225 rcu_read_unlock();
@@ -2182,13 +2227,13 @@ static int build_dentry_path(struct dentry *dentry, struct inode *dir,
2182 if (IS_ERR(path)) 2227 if (IS_ERR(path))
2183 return PTR_ERR(path); 2228 return PTR_ERR(path);
2184 *ppath = path; 2229 *ppath = path;
2185 *pfreepath = 1; 2230 *pfreepath = true;
2186 return 0; 2231 return 0;
2187} 2232}
2188 2233
2189static int build_inode_path(struct inode *inode, 2234static int build_inode_path(struct inode *inode,
2190 const char **ppath, int *ppathlen, u64 *pino, 2235 const char **ppath, int *ppathlen, u64 *pino,
2191 int *pfreepath) 2236 bool *pfreepath)
2192{ 2237{
2193 struct dentry *dentry; 2238 struct dentry *dentry;
2194 char *path; 2239 char *path;
@@ -2204,7 +2249,7 @@ static int build_inode_path(struct inode *inode,
2204 if (IS_ERR(path)) 2249 if (IS_ERR(path))
2205 return PTR_ERR(path); 2250 return PTR_ERR(path);
2206 *ppath = path; 2251 *ppath = path;
2207 *pfreepath = 1; 2252 *pfreepath = true;
2208 return 0; 2253 return 0;
2209} 2254}
2210 2255
@@ -2215,7 +2260,7 @@ static int build_inode_path(struct inode *inode,
2215static int set_request_path_attr(struct inode *rinode, struct dentry *rdentry, 2260static int set_request_path_attr(struct inode *rinode, struct dentry *rdentry,
2216 struct inode *rdiri, const char *rpath, 2261 struct inode *rdiri, const char *rpath,
2217 u64 rino, const char **ppath, int *pathlen, 2262 u64 rino, const char **ppath, int *pathlen,
2218 u64 *ino, int *freepath) 2263 u64 *ino, bool *freepath, bool parent_locked)
2219{ 2264{
2220 int r = 0; 2265 int r = 0;
2221 2266
@@ -2225,7 +2270,7 @@ static int set_request_path_attr(struct inode *rinode, struct dentry *rdentry,
2225 ceph_snap(rinode)); 2270 ceph_snap(rinode));
2226 } else if (rdentry) { 2271 } else if (rdentry) {
2227 r = build_dentry_path(rdentry, rdiri, ppath, pathlen, ino, 2272 r = build_dentry_path(rdentry, rdiri, ppath, pathlen, ino,
2228 freepath); 2273 freepath, parent_locked);
2229 dout(" dentry %p %llx/%.*s\n", rdentry, *ino, *pathlen, 2274 dout(" dentry %p %llx/%.*s\n", rdentry, *ino, *pathlen,
2230 *ppath); 2275 *ppath);
2231 } else if (rpath || rino) { 2276 } else if (rpath || rino) {
@@ -2251,7 +2296,7 @@ static struct ceph_msg *create_request_message(struct ceph_mds_client *mdsc,
2251 const char *path2 = NULL; 2296 const char *path2 = NULL;
2252 u64 ino1 = 0, ino2 = 0; 2297 u64 ino1 = 0, ino2 = 0;
2253 int pathlen1 = 0, pathlen2 = 0; 2298 int pathlen1 = 0, pathlen2 = 0;
2254 int freepath1 = 0, freepath2 = 0; 2299 bool freepath1 = false, freepath2 = false;
2255 int len; 2300 int len;
2256 u16 releases; 2301 u16 releases;
2257 void *p, *end; 2302 void *p, *end;
@@ -2259,16 +2304,19 @@ static struct ceph_msg *create_request_message(struct ceph_mds_client *mdsc,
2259 2304
2260 ret = set_request_path_attr(req->r_inode, req->r_dentry, 2305 ret = set_request_path_attr(req->r_inode, req->r_dentry,
2261 req->r_parent, req->r_path1, req->r_ino1.ino, 2306 req->r_parent, req->r_path1, req->r_ino1.ino,
2262 &path1, &pathlen1, &ino1, &freepath1); 2307 &path1, &pathlen1, &ino1, &freepath1,
2308 test_bit(CEPH_MDS_R_PARENT_LOCKED,
2309 &req->r_req_flags));
2263 if (ret < 0) { 2310 if (ret < 0) {
2264 msg = ERR_PTR(ret); 2311 msg = ERR_PTR(ret);
2265 goto out; 2312 goto out;
2266 } 2313 }
2267 2314
2315 /* If r_old_dentry is set, then assume that its parent is locked */
2268 ret = set_request_path_attr(NULL, req->r_old_dentry, 2316 ret = set_request_path_attr(NULL, req->r_old_dentry,
2269 req->r_old_dentry_dir, 2317 req->r_old_dentry_dir,
2270 req->r_path2, req->r_ino2.ino, 2318 req->r_path2, req->r_ino2.ino,
2271 &path2, &pathlen2, &ino2, &freepath2); 2319 &path2, &pathlen2, &ino2, &freepath2, true);
2272 if (ret < 0) { 2320 if (ret < 0) {
2273 msg = ERR_PTR(ret); 2321 msg = ERR_PTR(ret);
2274 goto out_free1; 2322 goto out_free1;
diff --git a/fs/ceph/snap.c b/fs/ceph/snap.c
index 89aa37fa0f84..b26e12cd8ec3 100644
--- a/fs/ceph/snap.c
+++ b/fs/ceph/snap.c
@@ -572,7 +572,12 @@ void ceph_queue_cap_snap(struct ceph_inode_info *ci)
572 old_snapc = NULL; 572 old_snapc = NULL;
573 573
574update_snapc: 574update_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 ci->i_head_snapc = ceph_get_snap_context(new_snapc); 581 ci->i_head_snapc = ceph_get_snap_context(new_snapc);
577 dout(" new snapc is %p\n", new_snapc); 582 dout(" new snapc is %p\n", new_snapc);
578 } 583 }