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; |
