diff options
Diffstat (limited to 'fs/dcache.c')
-rw-r--r-- | fs/dcache.c | 108 |
1 files changed, 37 insertions, 71 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index d45ff7f5ecc2..1710d2484fd9 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
@@ -1111,70 +1111,6 @@ static inline struct hlist_head *d_hash(struct dentry *parent, | |||
1111 | } | 1111 | } |
1112 | 1112 | ||
1113 | /** | 1113 | /** |
1114 | * d_alloc_anon - allocate an anonymous dentry | ||
1115 | * @inode: inode to allocate the dentry for | ||
1116 | * | ||
1117 | * This is similar to d_alloc_root. It is used by filesystems when | ||
1118 | * creating a dentry for a given inode, often in the process of | ||
1119 | * mapping a filehandle to a dentry. The returned dentry may be | ||
1120 | * anonymous, or may have a full name (if the inode was already | ||
1121 | * in the cache). The file system may need to make further | ||
1122 | * efforts to connect this dentry into the dcache properly. | ||
1123 | * | ||
1124 | * When called on a directory inode, we must ensure that | ||
1125 | * the inode only ever has one dentry. If a dentry is | ||
1126 | * found, that is returned instead of allocating a new one. | ||
1127 | * | ||
1128 | * On successful return, the reference to the inode has been transferred | ||
1129 | * to the dentry. If %NULL is returned (indicating kmalloc failure), | ||
1130 | * the reference on the inode has not been released. | ||
1131 | */ | ||
1132 | |||
1133 | struct dentry * d_alloc_anon(struct inode *inode) | ||
1134 | { | ||
1135 | static const struct qstr anonstring = { .name = "" }; | ||
1136 | struct dentry *tmp; | ||
1137 | struct dentry *res; | ||
1138 | |||
1139 | if ((res = d_find_alias(inode))) { | ||
1140 | iput(inode); | ||
1141 | return res; | ||
1142 | } | ||
1143 | |||
1144 | tmp = d_alloc(NULL, &anonstring); | ||
1145 | if (!tmp) | ||
1146 | return NULL; | ||
1147 | |||
1148 | tmp->d_parent = tmp; /* make sure dput doesn't croak */ | ||
1149 | |||
1150 | spin_lock(&dcache_lock); | ||
1151 | res = __d_find_alias(inode, 0); | ||
1152 | if (!res) { | ||
1153 | /* attach a disconnected dentry */ | ||
1154 | res = tmp; | ||
1155 | tmp = NULL; | ||
1156 | spin_lock(&res->d_lock); | ||
1157 | res->d_sb = inode->i_sb; | ||
1158 | res->d_parent = res; | ||
1159 | res->d_inode = inode; | ||
1160 | res->d_flags |= DCACHE_DISCONNECTED; | ||
1161 | res->d_flags &= ~DCACHE_UNHASHED; | ||
1162 | list_add(&res->d_alias, &inode->i_dentry); | ||
1163 | hlist_add_head(&res->d_hash, &inode->i_sb->s_anon); | ||
1164 | spin_unlock(&res->d_lock); | ||
1165 | |||
1166 | inode = NULL; /* don't drop reference */ | ||
1167 | } | ||
1168 | spin_unlock(&dcache_lock); | ||
1169 | |||
1170 | if (inode) | ||
1171 | iput(inode); | ||
1172 | if (tmp) | ||
1173 | dput(tmp); | ||
1174 | return res; | ||
1175 | } | ||
1176 | |||
1177 | /** | ||
1178 | * d_obtain_alias - find or allocate a dentry for a given inode | 1114 | * d_obtain_alias - find or allocate a dentry for a given inode |
1179 | * @inode: inode to allocate the dentry for | 1115 | * @inode: inode to allocate the dentry for |
1180 | * | 1116 | * |
@@ -1194,19 +1130,50 @@ struct dentry * d_alloc_anon(struct inode *inode) | |||
1194 | */ | 1130 | */ |
1195 | struct dentry *d_obtain_alias(struct inode *inode) | 1131 | struct dentry *d_obtain_alias(struct inode *inode) |
1196 | { | 1132 | { |
1197 | struct dentry *dentry; | 1133 | static const struct qstr anonstring = { .name = "" }; |
1134 | struct dentry *tmp; | ||
1135 | struct dentry *res; | ||
1198 | 1136 | ||
1199 | if (!inode) | 1137 | if (!inode) |
1200 | return ERR_PTR(-ESTALE); | 1138 | return ERR_PTR(-ESTALE); |
1201 | if (IS_ERR(inode)) | 1139 | if (IS_ERR(inode)) |
1202 | return ERR_CAST(inode); | 1140 | return ERR_CAST(inode); |
1203 | 1141 | ||
1204 | dentry = d_alloc_anon(inode); | 1142 | res = d_find_alias(inode); |
1205 | if (!dentry) { | 1143 | if (res) |
1206 | iput(inode); | 1144 | goto out_iput; |
1207 | dentry = ERR_PTR(-ENOMEM); | 1145 | |
1146 | tmp = d_alloc(NULL, &anonstring); | ||
1147 | if (!tmp) { | ||
1148 | res = ERR_PTR(-ENOMEM); | ||
1149 | goto out_iput; | ||
1208 | } | 1150 | } |
1209 | return dentry; | 1151 | tmp->d_parent = tmp; /* make sure dput doesn't croak */ |
1152 | |||
1153 | spin_lock(&dcache_lock); | ||
1154 | res = __d_find_alias(inode, 0); | ||
1155 | if (res) { | ||
1156 | spin_unlock(&dcache_lock); | ||
1157 | dput(tmp); | ||
1158 | goto out_iput; | ||
1159 | } | ||
1160 | |||
1161 | /* attach a disconnected dentry */ | ||
1162 | spin_lock(&tmp->d_lock); | ||
1163 | tmp->d_sb = inode->i_sb; | ||
1164 | tmp->d_inode = inode; | ||
1165 | tmp->d_flags |= DCACHE_DISCONNECTED; | ||
1166 | tmp->d_flags &= ~DCACHE_UNHASHED; | ||
1167 | list_add(&tmp->d_alias, &inode->i_dentry); | ||
1168 | hlist_add_head(&tmp->d_hash, &inode->i_sb->s_anon); | ||
1169 | spin_unlock(&tmp->d_lock); | ||
1170 | |||
1171 | spin_unlock(&dcache_lock); | ||
1172 | return tmp; | ||
1173 | |||
1174 | out_iput: | ||
1175 | iput(inode); | ||
1176 | return res; | ||
1210 | } | 1177 | } |
1211 | EXPORT_SYMBOL_GPL(d_obtain_alias); | 1178 | EXPORT_SYMBOL_GPL(d_obtain_alias); |
1212 | 1179 | ||
@@ -2379,7 +2346,6 @@ void __init vfs_caches_init(unsigned long mempages) | |||
2379 | } | 2346 | } |
2380 | 2347 | ||
2381 | EXPORT_SYMBOL(d_alloc); | 2348 | EXPORT_SYMBOL(d_alloc); |
2382 | EXPORT_SYMBOL(d_alloc_anon); | ||
2383 | EXPORT_SYMBOL(d_alloc_root); | 2349 | EXPORT_SYMBOL(d_alloc_root); |
2384 | EXPORT_SYMBOL(d_delete); | 2350 | EXPORT_SYMBOL(d_delete); |
2385 | EXPORT_SYMBOL(d_find_alias); | 2351 | EXPORT_SYMBOL(d_find_alias); |