--- linux-2.6.16/drivers/block/loop.c~ 2006-06-29 13:22:37.000000000 +0200 +++ linux-2.6.16/drivers/block/loop.c 2006-06-29 13:28:17.000000000 +0200 @@ -467,16 +467,58 @@ return ret; } +/* + * This is best effort. We really wouldn't know what to do with a returned + * error. This code is taken from the implementation of fsync. + */ +static int sync_file(struct file * file) +{ + struct address_space *mapping; + int ret; + + if (!file->f_op || !file->f_op->fsync) + return -EOPNOTSUPP; + + mapping = file->f_mapping; + + ret = filemap_fdatawrite(mapping); + if (!ret) { + /* + * We need to protect against concurrent writers, + * which could cause livelocks in fsync_buffers_list + */ + mutex_lock(&mapping->host->i_mutex); + ret = file->f_op->fsync(file, file->f_dentry, 1); + mutex_unlock(&mapping->host->i_mutex); + + filemap_fdatawait(mapping); + } + + return ret; +} + static int do_bio_filebacked(struct loop_device *lo, struct bio *bio) { loff_t pos; int ret; + int sync = bio_sync(bio); + int barrier = bio_barrier(bio); + + if (barrier) { + ret = sync_file(lo->lo_backing_file); + if (unlikely(ret)) + return ret; + } pos = ((loff_t) bio->bi_sector << 9) + lo->lo_offset; if (bio_rw(bio) == WRITE) ret = lo_send(lo, bio, lo->lo_blocksize, pos); else ret = lo_receive(lo, bio, lo->lo_blocksize, pos); + + if ((barrier || sync) && !ret) + ret = sync_file(lo->lo_backing_file); + return ret; }