/** * switch_gc_head - switch the garbage collection journal head. * @c: UBIFS file-system description object * @buf: buffer to write * @len: length of the buffer to write * @lnum: LEB number written is returned here * @offs: offset written is returned here * * This function switch the GC head to the next LEB which is reserved in * @c->gc_lnum. Returns %0 in case of success, %-EAGAIN if commit is required, * and other negative error code in case of failures. */ static int switch_gc_head(struct ubifs_info *c) { int err, gc_lnum = c->gc_lnum; struct ubifs_wbuf *wbuf = &c->jheads[GCHD].wbuf; ubifs_assert(gc_lnum != -1); dbg_gc("switch GC head from LEB %d:%d to LEB %d (waste %d bytes)", wbuf->lnum, wbuf->offs + wbuf->used, gc_lnum, c->leb_size - wbuf->offs - wbuf->used); err = ubifs_wbuf_sync_nolock(wbuf); if (err) return err; /* * The GC write-buffer was synchronized, we may safely unmap * 'c->gc_lnum'. */ err = ubifs_leb_unmap(c, gc_lnum); if (err) return err; err = ubifs_wbuf_sync_nolock(wbuf); if (err) return err; err = ubifs_add_bud_to_log(c, GCHD, gc_lnum, 0); if (err) return err; c->gc_lnum = -1; err = ubifs_wbuf_seek_nolock(wbuf, gc_lnum, 0, UBI_LONGTERM); return err; }
/** * ubifs_sync_wbufs_by_inode - synchronize write-buffers for an inode. * @c: UBIFS file-system description object * @inode: inode to synchronize * * This function synchronizes write-buffers which contain nodes belonging to * @inode. Returns zero in case of success and a negative error code in case of * failure. */ int ubifs_sync_wbufs_by_inode(struct ubifs_info *c, struct inode *inode) { int i, err = 0; for (i = 0; i < c->jhead_cnt; i++) { struct ubifs_wbuf *wbuf = &c->jheads[i].wbuf; if (i == GCHD) /* * GC head is special, do not look at it. Even if the * head contains something related to this inode, it is * a _copy_ of corresponding on-flash node which sits * somewhere else. */ continue; if (!wbuf_has_ino(wbuf, inode->i_ino)) continue; mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead); if (wbuf_has_ino(wbuf, inode->i_ino)) err = ubifs_wbuf_sync_nolock(wbuf); mutex_unlock(&wbuf->io_mutex); if (err) { ubifs_ro_mode(c, err); return err; } } return 0; }
/** * ubifs_wbuf_seek_nolock - seek write-buffer. * @wbuf: write-buffer * @lnum: logical eraseblock number to seek to * @offs: logical eraseblock offset to seek to * @dtype: data type * * This function targets the write buffer to logical eraseblock @lnum:@offs. * The write-buffer is synchronized if it is not empty. Returns zero in case of * success and a negative error code in case of failure. */ int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs, int dtype) { const struct ubifs_info *c = wbuf->c; dbg_io("LEB %d:%d", lnum, offs); ubifs_assert(lnum >= 0 && lnum < c->leb_cnt); ubifs_assert(offs >= 0 && offs <= c->leb_size); ubifs_assert(offs % c->min_io_size == 0 && !(offs & 7)); ubifs_assert(lnum != wbuf->lnum); if (wbuf->used > 0) { int err = ubifs_wbuf_sync_nolock(wbuf); if (err) return err; } spin_lock(&wbuf->lock); wbuf->lnum = lnum; wbuf->offs = offs; wbuf->avail = c->min_io_size; wbuf->used = 0; spin_unlock(&wbuf->lock); wbuf->dtype = dtype; return 0; }
/** * ubifs_bg_wbufs_sync - synchronize write-buffers. * @c: UBIFS file-system description object * * This function is called by background thread to synchronize write-buffers. * Returns zero in case of success and a negative error code in case of * failure. */ int ubifs_bg_wbufs_sync(struct ubifs_info *c) { int err, i; ubifs_assert(!c->ro_media && !c->ro_mount); if (!c->need_wbuf_sync) return 0; c->need_wbuf_sync = 0; if (c->ro_error) { err = -EROFS; goto out_timers; } dbg_io("synchronize"); for (i = 0; i < c->jhead_cnt; i++) { struct ubifs_wbuf *wbuf = &c->jheads[i].wbuf; cond_resched(); /* * If the mutex is locked then wbuf is being changed, so * synchronization is not necessary. */ if (mutex_is_locked(&wbuf->io_mutex)) continue; mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead); if (!wbuf->need_sync) { mutex_unlock(&wbuf->io_mutex); continue; } err = ubifs_wbuf_sync_nolock(wbuf); mutex_unlock(&wbuf->io_mutex); if (err) { ubifs_err("cannot sync write-buffer, error %d", err); ubifs_ro_mode(c, err); goto out_timers; } } return 0; out_timers: /* Cancel all timers to prevent repeated errors */ for (i = 0; i < c->jhead_cnt; i++) { struct ubifs_wbuf *wbuf = &c->jheads[i].wbuf; mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead); cancel_wbuf_timer_nolock(wbuf); mutex_unlock(&wbuf->io_mutex); } return err; }
/** * write_head - write data to a journal head. * @c: UBIFS file-system description object * @jhead: journal head * @buf: buffer to write * @len: length to write * @lnum: LEB number written is returned here * @offs: offset written is returned here * @sync: non-zero if the write-buffer has to by synchronized * * This function is the same as 'write_node()' but it does not assume the * buffer it is writing is a node, so it does not prepare it (which means * initializing common header and calculating CRC). */ static int write_head(struct ubifs_info *c, int jhead, void *buf, int len, int *lnum, int *offs, int sync) { int err; struct ubifs_wbuf *wbuf = &c->jheads[jhead].wbuf; ubifs_assert(jhead != GCHD); *lnum = c->jheads[jhead].wbuf.lnum; *offs = c->jheads[jhead].wbuf.offs + c->jheads[jhead].wbuf.used; dbg_jrn("jhead %d, LEB %d:%d, len %d", jhead, *lnum, *offs, len); err = ubifs_wbuf_write_nolock(wbuf, buf, len); if (err) return err; if (sync) err = ubifs_wbuf_sync_nolock(wbuf); return err; }
/** * ubifs_sync_wbufs_by_inodes - synchronize write-buffers which have data. * belonging to specified inodes. * @c: UBIFS file-system description object * @inodes: array of inodes * @count: number of elements in @inodes * * This function synchronizes write-buffers which contain nodes belonging to * any inode specified in @inodes array. Returns zero in case of success and a * negative error code in case of failure. */ int ubifs_sync_wbufs_by_inodes(struct ubifs_info *c, struct inode * const *inodes, int count) { int i, j, err = 0; ubifs_assert(count); for (i = 0; i < c->jhead_cnt; i++) { struct ubifs_wbuf *wbuf = &c->jheads[i].wbuf; if (i == GCHD) /* * GC head is special, do not look at it. Even if the * head contains something related to this inode, it is * a _copy_ of corresponding on-flash node which sits * somewhere else. */ continue; for (j = 0; j < count && !err; j++) if (wbuf_has_ino(wbuf, inodes[j]->i_ino)) { mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead); if (wbuf_has_ino(wbuf, inodes[j]->i_ino)) err = ubifs_wbuf_sync_nolock(wbuf); mutex_unlock(&wbuf->io_mutex); break; } if (err) { ubifs_ro_mode(c, err); break; } } return err; }