| .. | .. |
|---|
| 44 | 44 | NOT_ON_MEDIA = 3, |
|---|
| 45 | 45 | }; |
|---|
| 46 | 46 | |
|---|
| 47 | +static void do_insert_old_idx(struct ubifs_info *c, |
|---|
| 48 | + struct ubifs_old_idx *old_idx) |
|---|
| 49 | +{ |
|---|
| 50 | + struct ubifs_old_idx *o; |
|---|
| 51 | + struct rb_node **p, *parent = NULL; |
|---|
| 52 | + |
|---|
| 53 | + p = &c->old_idx.rb_node; |
|---|
| 54 | + while (*p) { |
|---|
| 55 | + parent = *p; |
|---|
| 56 | + o = rb_entry(parent, struct ubifs_old_idx, rb); |
|---|
| 57 | + if (old_idx->lnum < o->lnum) |
|---|
| 58 | + p = &(*p)->rb_left; |
|---|
| 59 | + else if (old_idx->lnum > o->lnum) |
|---|
| 60 | + p = &(*p)->rb_right; |
|---|
| 61 | + else if (old_idx->offs < o->offs) |
|---|
| 62 | + p = &(*p)->rb_left; |
|---|
| 63 | + else if (old_idx->offs > o->offs) |
|---|
| 64 | + p = &(*p)->rb_right; |
|---|
| 65 | + else { |
|---|
| 66 | + ubifs_err(c, "old idx added twice!"); |
|---|
| 67 | + kfree(old_idx); |
|---|
| 68 | + } |
|---|
| 69 | + } |
|---|
| 70 | + rb_link_node(&old_idx->rb, parent, p); |
|---|
| 71 | + rb_insert_color(&old_idx->rb, &c->old_idx); |
|---|
| 72 | +} |
|---|
| 73 | + |
|---|
| 47 | 74 | /** |
|---|
| 48 | 75 | * insert_old_idx - record an index node obsoleted since the last commit start. |
|---|
| 49 | 76 | * @c: UBIFS file-system description object |
|---|
| .. | .. |
|---|
| 69 | 96 | */ |
|---|
| 70 | 97 | static int insert_old_idx(struct ubifs_info *c, int lnum, int offs) |
|---|
| 71 | 98 | { |
|---|
| 72 | | - struct ubifs_old_idx *old_idx, *o; |
|---|
| 73 | | - struct rb_node **p, *parent = NULL; |
|---|
| 99 | + struct ubifs_old_idx *old_idx; |
|---|
| 74 | 100 | |
|---|
| 75 | 101 | old_idx = kmalloc(sizeof(struct ubifs_old_idx), GFP_NOFS); |
|---|
| 76 | 102 | if (unlikely(!old_idx)) |
|---|
| 77 | 103 | return -ENOMEM; |
|---|
| 78 | 104 | old_idx->lnum = lnum; |
|---|
| 79 | 105 | old_idx->offs = offs; |
|---|
| 106 | + do_insert_old_idx(c, old_idx); |
|---|
| 80 | 107 | |
|---|
| 81 | | - p = &c->old_idx.rb_node; |
|---|
| 82 | | - while (*p) { |
|---|
| 83 | | - parent = *p; |
|---|
| 84 | | - o = rb_entry(parent, struct ubifs_old_idx, rb); |
|---|
| 85 | | - if (lnum < o->lnum) |
|---|
| 86 | | - p = &(*p)->rb_left; |
|---|
| 87 | | - else if (lnum > o->lnum) |
|---|
| 88 | | - p = &(*p)->rb_right; |
|---|
| 89 | | - else if (offs < o->offs) |
|---|
| 90 | | - p = &(*p)->rb_left; |
|---|
| 91 | | - else if (offs > o->offs) |
|---|
| 92 | | - p = &(*p)->rb_right; |
|---|
| 93 | | - else { |
|---|
| 94 | | - ubifs_err(c, "old idx added twice!"); |
|---|
| 95 | | - kfree(old_idx); |
|---|
| 96 | | - return 0; |
|---|
| 97 | | - } |
|---|
| 98 | | - } |
|---|
| 99 | | - rb_link_node(&old_idx->rb, parent, p); |
|---|
| 100 | | - rb_insert_color(&old_idx->rb, &c->old_idx); |
|---|
| 101 | 108 | return 0; |
|---|
| 102 | 109 | } |
|---|
| 103 | 110 | |
|---|
| .. | .. |
|---|
| 199 | 206 | __set_bit(DIRTY_ZNODE, &zn->flags); |
|---|
| 200 | 207 | __clear_bit(COW_ZNODE, &zn->flags); |
|---|
| 201 | 208 | |
|---|
| 202 | | - ubifs_assert(c, !ubifs_zn_obsolete(znode)); |
|---|
| 203 | | - __set_bit(OBSOLETE_ZNODE, &znode->flags); |
|---|
| 204 | | - |
|---|
| 205 | | - if (znode->level != 0) { |
|---|
| 206 | | - int i; |
|---|
| 207 | | - const int n = zn->child_cnt; |
|---|
| 208 | | - |
|---|
| 209 | | - /* The children now have new parent */ |
|---|
| 210 | | - for (i = 0; i < n; i++) { |
|---|
| 211 | | - struct ubifs_zbranch *zbr = &zn->zbranch[i]; |
|---|
| 212 | | - |
|---|
| 213 | | - if (zbr->znode) |
|---|
| 214 | | - zbr->znode->parent = zn; |
|---|
| 215 | | - } |
|---|
| 216 | | - } |
|---|
| 217 | | - |
|---|
| 218 | | - atomic_long_inc(&c->dirty_zn_cnt); |
|---|
| 219 | 209 | return zn; |
|---|
| 220 | 210 | } |
|---|
| 221 | 211 | |
|---|
| .. | .. |
|---|
| 231 | 221 | { |
|---|
| 232 | 222 | c->calc_idx_sz -= ALIGN(dirt, 8); |
|---|
| 233 | 223 | return ubifs_add_dirt(c, lnum, dirt); |
|---|
| 224 | +} |
|---|
| 225 | + |
|---|
| 226 | +/** |
|---|
| 227 | + * replace_znode - replace old znode with new znode. |
|---|
| 228 | + * @c: UBIFS file-system description object |
|---|
| 229 | + * @new_zn: new znode |
|---|
| 230 | + * @old_zn: old znode |
|---|
| 231 | + * @zbr: the branch of parent znode |
|---|
| 232 | + * |
|---|
| 233 | + * Replace old znode with new znode in TNC. |
|---|
| 234 | + */ |
|---|
| 235 | +static void replace_znode(struct ubifs_info *c, struct ubifs_znode *new_zn, |
|---|
| 236 | + struct ubifs_znode *old_zn, struct ubifs_zbranch *zbr) |
|---|
| 237 | +{ |
|---|
| 238 | + ubifs_assert(c, !ubifs_zn_obsolete(old_zn)); |
|---|
| 239 | + __set_bit(OBSOLETE_ZNODE, &old_zn->flags); |
|---|
| 240 | + |
|---|
| 241 | + if (old_zn->level != 0) { |
|---|
| 242 | + int i; |
|---|
| 243 | + const int n = new_zn->child_cnt; |
|---|
| 244 | + |
|---|
| 245 | + /* The children now have new parent */ |
|---|
| 246 | + for (i = 0; i < n; i++) { |
|---|
| 247 | + struct ubifs_zbranch *child = &new_zn->zbranch[i]; |
|---|
| 248 | + |
|---|
| 249 | + if (child->znode) |
|---|
| 250 | + child->znode->parent = new_zn; |
|---|
| 251 | + } |
|---|
| 252 | + } |
|---|
| 253 | + |
|---|
| 254 | + zbr->znode = new_zn; |
|---|
| 255 | + zbr->lnum = 0; |
|---|
| 256 | + zbr->offs = 0; |
|---|
| 257 | + zbr->len = 0; |
|---|
| 258 | + |
|---|
| 259 | + atomic_long_inc(&c->dirty_zn_cnt); |
|---|
| 234 | 260 | } |
|---|
| 235 | 261 | |
|---|
| 236 | 262 | /** |
|---|
| .. | .. |
|---|
| 265 | 291 | return zn; |
|---|
| 266 | 292 | |
|---|
| 267 | 293 | if (zbr->len) { |
|---|
| 268 | | - err = insert_old_idx(c, zbr->lnum, zbr->offs); |
|---|
| 269 | | - if (unlikely(err)) |
|---|
| 270 | | - return ERR_PTR(err); |
|---|
| 294 | + struct ubifs_old_idx *old_idx; |
|---|
| 295 | + |
|---|
| 296 | + old_idx = kmalloc(sizeof(struct ubifs_old_idx), GFP_NOFS); |
|---|
| 297 | + if (unlikely(!old_idx)) { |
|---|
| 298 | + err = -ENOMEM; |
|---|
| 299 | + goto out; |
|---|
| 300 | + } |
|---|
| 301 | + old_idx->lnum = zbr->lnum; |
|---|
| 302 | + old_idx->offs = zbr->offs; |
|---|
| 303 | + |
|---|
| 271 | 304 | err = add_idx_dirt(c, zbr->lnum, zbr->len); |
|---|
| 272 | | - } else |
|---|
| 273 | | - err = 0; |
|---|
| 305 | + if (err) { |
|---|
| 306 | + kfree(old_idx); |
|---|
| 307 | + goto out; |
|---|
| 308 | + } |
|---|
| 274 | 309 | |
|---|
| 275 | | - zbr->znode = zn; |
|---|
| 276 | | - zbr->lnum = 0; |
|---|
| 277 | | - zbr->offs = 0; |
|---|
| 278 | | - zbr->len = 0; |
|---|
| 310 | + do_insert_old_idx(c, old_idx); |
|---|
| 311 | + } |
|---|
| 279 | 312 | |
|---|
| 280 | | - if (unlikely(err)) |
|---|
| 281 | | - return ERR_PTR(err); |
|---|
| 313 | + replace_znode(c, zn, znode, zbr); |
|---|
| 314 | + |
|---|
| 282 | 315 | return zn; |
|---|
| 316 | + |
|---|
| 317 | +out: |
|---|
| 318 | + kfree(zn); |
|---|
| 319 | + return ERR_PTR(err); |
|---|
| 283 | 320 | } |
|---|
| 284 | 321 | |
|---|
| 285 | 322 | /** |
|---|
| .. | .. |
|---|
| 3053 | 3090 | cnext = cnext->cnext; |
|---|
| 3054 | 3091 | if (ubifs_zn_obsolete(znode)) |
|---|
| 3055 | 3092 | kfree(znode); |
|---|
| 3093 | + else if (!ubifs_zn_cow(znode)) { |
|---|
| 3094 | + /* |
|---|
| 3095 | + * Don't forget to update clean znode count after |
|---|
| 3096 | + * committing failed, because ubifs will check this |
|---|
| 3097 | + * count while closing tnc. Non-obsolete znode could |
|---|
| 3098 | + * be re-dirtied during committing process, so dirty |
|---|
| 3099 | + * flag is untrustable. The flag 'COW_ZNODE' is set |
|---|
| 3100 | + * for each dirty znode before committing, and it is |
|---|
| 3101 | + * cleared as long as the znode become clean, so we |
|---|
| 3102 | + * can statistic clean znode count according to this |
|---|
| 3103 | + * flag. |
|---|
| 3104 | + */ |
|---|
| 3105 | + atomic_long_inc(&c->clean_zn_cnt); |
|---|
| 3106 | + atomic_long_inc(&ubifs_clean_zn_cnt); |
|---|
| 3107 | + } |
|---|
| 3056 | 3108 | } while (cnext && cnext != c->cnext); |
|---|
| 3057 | 3109 | } |
|---|
| 3058 | 3110 | |
|---|