diff options
| author | John Stultz <john.stultz@linaro.org> | 2011-07-25 09:58:06 -0700 |
|---|---|---|
| committer | John Stultz <john.stultz@linaro.org> | 2011-07-25 09:58:06 -0700 |
| commit | 21a602b5cdc203cbcf8bbeeb26edeb3de7c65955 (patch) | |
| tree | 8618b4a8882f78076a779ebb416b54332cc213db /fs/cifs/dir.c | |
| parent | 1a3807e5a6bea7e4b195fbb399bbc09e73230d4c (diff) | |
| parent | 81f6236c4811b2b2b3ea64a306c071f76788ac4b (diff) | |
Merge branch 'upstream/linaro-3.0' into linaro-android-3.0
Diffstat (limited to 'fs/cifs/dir.c')
| -rw-r--r-- | fs/cifs/dir.c | 13 |
1 files changed, 12 insertions, 1 deletions
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 81914df47ef..fa8c21d913b 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -55,6 +55,7 @@ build_path_from_dentry(struct dentry *direntry) char dirsep; struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb); struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); + unsigned seq; if (direntry == NULL) return NULL; /* not much we can do if dentry is freed and @@ -68,22 +69,29 @@ build_path_from_dentry(struct dentry *direntry) dfsplen = 0; cifs_bp_rename_retry: namelen = dfsplen; + seq = read_seqbegin(&rename_lock); + rcu_read_lock(); for (temp = direntry; !IS_ROOT(temp);) { namelen += (1 + temp->d_name.len); temp = temp->d_parent; if (temp == NULL) { cERROR(1, "corrupt dentry"); + rcu_read_unlock(); return NULL; } } + rcu_read_unlock(); full_path = kmalloc(namelen+1, GFP_KERNEL); if (full_path == NULL) return full_path; full_path[namelen] = 0; /* trailing null */ + rcu_read_lock(); for (temp = direntry; !IS_ROOT(temp);) { + spin_lock(&temp->d_lock); namelen -= 1 + temp->d_name.len; if (namelen < 0) { + spin_unlock(&temp->d_lock); break; } else { full_path[namelen] = dirsep; @@ -91,14 +99,17 @@ cifs_bp_rename_retry: temp->d_name.len); cFYI(0, "name: %s", full_path + namelen); } + spin_unlock(&temp->d_lock); temp = temp->d_parent; if (temp == NULL) { cERROR(1, "corrupt dentry"); + rcu_read_unlock(); kfree(full_path); return NULL; } } - if (namelen != dfsplen) { + rcu_read_unlock(); + if (namelen != dfsplen || read_seqretry(&rename_lock, seq)) { cERROR(1, "did not end path lookup where expected namelen is %d", namelen); /* presumably this is only possible if racing with a rename |
