diff options
-rw-r--r-- | fs/ocfs2/namei.c | 127 |
1 files changed, 107 insertions, 20 deletions
diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c index 54c629855357..a00dda2e4f16 100644 --- a/fs/ocfs2/namei.c +++ b/fs/ocfs2/namei.c | |||
@@ -2128,6 +2128,99 @@ leave: | |||
2128 | return status; | 2128 | return status; |
2129 | } | 2129 | } |
2130 | 2130 | ||
2131 | /** | ||
2132 | * ocfs2_prep_new_orphaned_file() - Prepare the orphan dir to recieve a newly | ||
2133 | * allocated file. This is different from the typical 'add to orphan dir' | ||
2134 | * operation in that the inode does not yet exist. This is a problem because | ||
2135 | * the orphan dir stringifies the inode block number to come up with it's | ||
2136 | * dirent. Obviously if the inode does not yet exist we have a chicken and egg | ||
2137 | * problem. This function works around it by calling deeper into the orphan | ||
2138 | * and suballoc code than other callers. Use this only by necessity. | ||
2139 | * @dir: The directory which this inode will ultimately wind up under - not the | ||
2140 | * orphan dir! | ||
2141 | * @dir_bh: buffer_head the @dir inode block | ||
2142 | * @orphan_name: string of length (CFS2_ORPHAN_NAMELEN + 1). Will be filled | ||
2143 | * with the string to be used for orphan dirent. Pass back to the orphan dir | ||
2144 | * code. | ||
2145 | * @ret_orphan_dir: orphan dir inode returned to be passed back into orphan | ||
2146 | * dir code. | ||
2147 | * @ret_di_blkno: block number where the new inode will be allocated. | ||
2148 | * @orphan_insert: Dir insert context to be passed back into orphan dir code. | ||
2149 | * @ret_inode_ac: Inode alloc context to be passed back to the allocator. | ||
2150 | * | ||
2151 | * Returns zero on success and the ret_orphan_dir, name and lookup | ||
2152 | * fields will be populated. | ||
2153 | * | ||
2154 | * Returns non-zero on failure. | ||
2155 | */ | ||
2156 | static int ocfs2_prep_new_orphaned_file(struct inode *dir, | ||
2157 | struct buffer_head *dir_bh, | ||
2158 | char *orphan_name, | ||
2159 | struct inode **ret_orphan_dir, | ||
2160 | u64 *ret_di_blkno, | ||
2161 | struct ocfs2_dir_lookup_result *orphan_insert, | ||
2162 | struct ocfs2_alloc_context **ret_inode_ac) | ||
2163 | { | ||
2164 | int ret; | ||
2165 | u64 di_blkno; | ||
2166 | struct ocfs2_super *osb = OCFS2_SB(dir->i_sb); | ||
2167 | struct inode *orphan_dir = NULL; | ||
2168 | struct buffer_head *orphan_dir_bh = NULL; | ||
2169 | struct ocfs2_alloc_context *inode_ac = NULL; | ||
2170 | |||
2171 | ret = ocfs2_lookup_lock_orphan_dir(osb, &orphan_dir, &orphan_dir_bh); | ||
2172 | if (ret < 0) { | ||
2173 | mlog_errno(ret); | ||
2174 | return ret; | ||
2175 | } | ||
2176 | |||
2177 | /* reserve an inode spot */ | ||
2178 | ret = ocfs2_reserve_new_inode(osb, &inode_ac); | ||
2179 | if (ret < 0) { | ||
2180 | if (ret != -ENOSPC) | ||
2181 | mlog_errno(ret); | ||
2182 | goto out; | ||
2183 | } | ||
2184 | |||
2185 | ret = ocfs2_find_new_inode_loc(dir, dir_bh, inode_ac, | ||
2186 | &di_blkno); | ||
2187 | if (ret) { | ||
2188 | mlog_errno(ret); | ||
2189 | goto out; | ||
2190 | } | ||
2191 | |||
2192 | ret = __ocfs2_prepare_orphan_dir(orphan_dir, orphan_dir_bh, | ||
2193 | di_blkno, orphan_name, orphan_insert); | ||
2194 | if (ret < 0) { | ||
2195 | mlog_errno(ret); | ||
2196 | goto out; | ||
2197 | } | ||
2198 | |||
2199 | out: | ||
2200 | if (ret == 0) { | ||
2201 | *ret_orphan_dir = orphan_dir; | ||
2202 | *ret_di_blkno = di_blkno; | ||
2203 | *ret_inode_ac = inode_ac; | ||
2204 | /* | ||
2205 | * orphan_name and orphan_insert are already up to | ||
2206 | * date via prepare_orphan_dir | ||
2207 | */ | ||
2208 | } else { | ||
2209 | /* Unroll reserve_new_inode* */ | ||
2210 | if (inode_ac) | ||
2211 | ocfs2_free_alloc_context(inode_ac); | ||
2212 | |||
2213 | /* Unroll orphan dir locking */ | ||
2214 | mutex_unlock(&orphan_dir->i_mutex); | ||
2215 | ocfs2_inode_unlock(orphan_dir, 1); | ||
2216 | iput(orphan_dir); | ||
2217 | } | ||
2218 | |||
2219 | brelse(orphan_dir_bh); | ||
2220 | |||
2221 | return 0; | ||
2222 | } | ||
2223 | |||
2131 | int ocfs2_create_inode_in_orphan(struct inode *dir, | 2224 | int ocfs2_create_inode_in_orphan(struct inode *dir, |
2132 | int mode, | 2225 | int mode, |
2133 | struct inode **new_inode) | 2226 | struct inode **new_inode) |
@@ -2143,6 +2236,8 @@ int ocfs2_create_inode_in_orphan(struct inode *dir, | |||
2143 | struct buffer_head *new_di_bh = NULL; | 2236 | struct buffer_head *new_di_bh = NULL; |
2144 | struct ocfs2_alloc_context *inode_ac = NULL; | 2237 | struct ocfs2_alloc_context *inode_ac = NULL; |
2145 | struct ocfs2_dir_lookup_result orphan_insert = { NULL, }; | 2238 | struct ocfs2_dir_lookup_result orphan_insert = { NULL, }; |
2239 | u64 uninitialized_var(di_blkno), suballoc_loc; | ||
2240 | u16 suballoc_bit; | ||
2146 | 2241 | ||
2147 | status = ocfs2_inode_lock(dir, &parent_di_bh, 1); | 2242 | status = ocfs2_inode_lock(dir, &parent_di_bh, 1); |
2148 | if (status < 0) { | 2243 | if (status < 0) { |
@@ -2151,20 +2246,9 @@ int ocfs2_create_inode_in_orphan(struct inode *dir, | |||
2151 | return status; | 2246 | return status; |
2152 | } | 2247 | } |
2153 | 2248 | ||
2154 | /* | 2249 | status = ocfs2_prep_new_orphaned_file(dir, parent_di_bh, |
2155 | * We give the orphan dir the root blkno to fake an orphan name, | 2250 | orphan_name, &orphan_dir, |
2156 | * and allocate enough space for our insertion. | 2251 | &di_blkno, &orphan_insert, &inode_ac); |
2157 | */ | ||
2158 | status = ocfs2_prepare_orphan_dir(osb, &orphan_dir, | ||
2159 | osb->root_blkno, | ||
2160 | orphan_name, &orphan_insert); | ||
2161 | if (status < 0) { | ||
2162 | mlog_errno(status); | ||
2163 | goto leave; | ||
2164 | } | ||
2165 | |||
2166 | /* reserve an inode spot */ | ||
2167 | status = ocfs2_reserve_new_inode(osb, &inode_ac); | ||
2168 | if (status < 0) { | 2252 | if (status < 0) { |
2169 | if (status != -ENOSPC) | 2253 | if (status != -ENOSPC) |
2170 | mlog_errno(status); | 2254 | mlog_errno(status); |
@@ -2191,17 +2275,20 @@ int ocfs2_create_inode_in_orphan(struct inode *dir, | |||
2191 | goto leave; | 2275 | goto leave; |
2192 | did_quota_inode = 1; | 2276 | did_quota_inode = 1; |
2193 | 2277 | ||
2194 | inode->i_nlink = 0; | 2278 | status = ocfs2_claim_new_inode_at_loc(handle, dir, inode_ac, |
2195 | /* do the real work now. */ | 2279 | &suballoc_loc, |
2196 | status = ocfs2_mknod_locked(osb, dir, inode, | 2280 | &suballoc_bit, di_blkno); |
2197 | 0, &new_di_bh, parent_di_bh, handle, | ||
2198 | inode_ac); | ||
2199 | if (status < 0) { | 2281 | if (status < 0) { |
2200 | mlog_errno(status); | 2282 | mlog_errno(status); |
2201 | goto leave; | 2283 | goto leave; |
2202 | } | 2284 | } |
2203 | 2285 | ||
2204 | status = ocfs2_blkno_stringify(OCFS2_I(inode)->ip_blkno, orphan_name); | 2286 | inode->i_nlink = 0; |
2287 | /* do the real work now. */ | ||
2288 | status = __ocfs2_mknod_locked(dir, inode, | ||
2289 | 0, &new_di_bh, parent_di_bh, handle, | ||
2290 | inode_ac, di_blkno, suballoc_loc, | ||
2291 | suballoc_bit); | ||
2205 | if (status < 0) { | 2292 | if (status < 0) { |
2206 | mlog_errno(status); | 2293 | mlog_errno(status); |
2207 | goto leave; | 2294 | goto leave; |