X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;ds=sidebyside;f=cmd_fusemount.c;h=54bc76cd25cdd7c9b7237792b2e2389ebaa8dd7f;hb=b61ad35b974038fd1b0396c51a61d84891ae0523;hp=a70f035bc70a36bc9e2fd716a9b496ca84c37b4d;hpb=de151b0659d75f91fc02ae55fd6ea45caa5a3eeb;p=bcachefs-tools-debian diff --git a/cmd_fusemount.c b/cmd_fusemount.c index a70f035..54bc76c 100644 --- a/cmd_fusemount.c +++ b/cmd_fusemount.c @@ -1,3 +1,5 @@ +#ifdef BCACHEFS_FUSE + #include #include #include @@ -44,7 +46,7 @@ static struct stat inode_to_stat(struct bch_fs *c, struct bch_inode_unpacked *bi) { return (struct stat) { - .st_ino = bi->bi_inum, + .st_ino = unmap_root_ino(bi->bi_inum), .st_size = bi->bi_size, .st_mode = bi->bi_mode, .st_uid = bi->bi_uid, @@ -63,7 +65,7 @@ static struct fuse_entry_param inode_to_entry(struct bch_fs *c, struct bch_inode_unpacked *bi) { return (struct fuse_entry_param) { - .ino = bi->bi_inum, + .ino = unmap_root_ino(bi->bi_inum), .generation = bi->bi_generation, .attr = inode_to_stat(c, bi), .attr_timeout = DBL_MAX, @@ -98,6 +100,9 @@ static void bcachefs_fuse_lookup(fuse_req_t req, fuse_ino_t dir, u64 inum; int ret; + fuse_log(FUSE_LOG_DEBUG, "fuse_lookup(dir=%llu name=%s)\n", + dir, name); + dir = map_root_ino(dir); ret = bch2_inode_find_by_inum(c, dir, &bi); @@ -110,20 +115,26 @@ static void bcachefs_fuse_lookup(fuse_req_t req, fuse_ino_t dir, inum = bch2_dirent_lookup(c, dir, &hash_info, &qstr); if (!inum) { - ret = -ENOENT; - goto err; + struct fuse_entry_param e = { + .attr_timeout = DBL_MAX, + .entry_timeout = DBL_MAX, + }; + fuse_reply_entry(req, &e); + return; } ret = bch2_inode_find_by_inum(c, inum, &bi); if (ret) goto err; - bi.bi_inum = unmap_root_ino(bi.bi_inum); + fuse_log(FUSE_LOG_DEBUG, "fuse_lookup ret(inum=%llu)\n", + bi.bi_inum); struct fuse_entry_param e = inode_to_entry(c, &bi); fuse_reply_entry(req, &e); return; err: + fuse_log(FUSE_LOG_DEBUG, "fuse_lookup error %i\n", ret); fuse_reply_err(req, -ret); } @@ -135,15 +146,19 @@ static void bcachefs_fuse_getattr(fuse_req_t req, fuse_ino_t inum, struct stat attr; int ret; + fuse_log(FUSE_LOG_DEBUG, "fuse_getattr(inum=%llu)\n", + inum); + inum = map_root_ino(inum); ret = bch2_inode_find_by_inum(c, inum, &bi); if (ret) { + fuse_log(FUSE_LOG_DEBUG, "fuse_getattr error %i\n", ret); fuse_reply_err(req, -ret); return; } - bi.bi_inum = unmap_root_ino(bi.bi_inum); + fuse_log(FUSE_LOG_DEBUG, "fuse_getattr success\n"); attr = inode_to_stat(c, &bi); fuse_reply_attr(req, &attr, DBL_MAX); @@ -160,6 +175,9 @@ static void bcachefs_fuse_setattr(fuse_req_t req, fuse_ino_t inum, u64 now; int ret; + fuse_log(FUSE_LOG_DEBUG, "bcachefs_fuse_setattr(%llu, %x)\n", + inum, to_set); + inum = map_root_ino(inum); bch2_trans_init(&trans, c, 0, 0); @@ -192,7 +210,6 @@ retry: ret = bch2_inode_write(&trans, iter, &inode_u) ?: bch2_trans_commit(&trans, NULL, NULL, - BTREE_INSERT_ATOMIC| BTREE_INSERT_NOFAIL); err: if (ret == -EINTR) @@ -219,7 +236,7 @@ static int do_create(struct bch_fs *c, u64 dir, bch2_inode_init_early(c, new_inode); - return bch2_trans_do(c, NULL, BTREE_INSERT_ATOMIC, + return bch2_trans_do(c, NULL, NULL, 0, bch2_create_trans(&trans, dir, &dir_u, new_inode, &qstr, @@ -234,6 +251,8 @@ static void bcachefs_fuse_mknod(fuse_req_t req, fuse_ino_t dir, struct bch_inode_unpacked new_inode; int ret; + fuse_log(FUSE_LOG_DEBUG, "bcachefs_fuse_mknod(%llu, %s, %x, %x)\n", + dir, name, mode, rdev); ret = do_create(c, dir, name, mode, rdev, &new_inode); if (ret) goto err; @@ -248,7 +267,10 @@ err: static void bcachefs_fuse_mkdir(fuse_req_t req, fuse_ino_t dir, const char *name, mode_t mode) { - BUG_ON(mode & (~S_IALLUGO)); + fuse_log(FUSE_LOG_DEBUG, "bcachefs_fuse_mkdir(%llu, %s, %x)\n", + dir, name, mode); + + BUG_ON(mode & S_IFMT); mode |= S_IFDIR; bcachefs_fuse_mknod(req, dir, name, mode, 0); @@ -262,9 +284,11 @@ static void bcachefs_fuse_unlink(fuse_req_t req, fuse_ino_t dir, struct qstr qstr = QSTR(name); int ret; + fuse_log(FUSE_LOG_DEBUG, "bcachefs_fuse_unlink(%llu, %s)\n", dir, name); + dir = map_root_ino(dir); - ret = bch2_trans_do(c, NULL, BTREE_INSERT_ATOMIC|BTREE_INSERT_NOFAIL, + ret = bch2_trans_do(c, NULL, NULL, BTREE_INSERT_NOFAIL, bch2_unlink_trans(&trans, dir, &dir_u, &inode_u, &qstr)); @@ -274,6 +298,8 @@ static void bcachefs_fuse_unlink(fuse_req_t req, fuse_ino_t dir, static void bcachefs_fuse_rmdir(fuse_req_t req, fuse_ino_t dir, const char *name) { + fuse_log(FUSE_LOG_DEBUG, "bcachefs_fuse_rmdir(%llu, %s)\n", dir, name); + dir = map_root_ino(dir); bcachefs_fuse_unlink(req, dir, name); @@ -291,11 +317,15 @@ static void bcachefs_fuse_rename(fuse_req_t req, struct qstr src_name = QSTR(dstname); int ret; + fuse_log(FUSE_LOG_DEBUG, + "bcachefs_fuse_rename(%llu, %s, %llu, %s, %x)\n", + src_dir, srcname, dst_dir, dstname, flags); + src_dir = map_root_ino(src_dir); dst_dir = map_root_ino(dst_dir); /* XXX handle overwrites */ - ret = bch2_trans_do(c, NULL, BTREE_INSERT_ATOMIC, + ret = bch2_trans_do(c, NULL, NULL, 0, bch2_rename_trans(&trans, src_dir, &src_dir_u, dst_dir, &dst_dir_u, @@ -310,15 +340,18 @@ static void bcachefs_fuse_link(fuse_req_t req, fuse_ino_t inum, fuse_ino_t newparent, const char *newname) { struct bch_fs *c = fuse_req_userdata(req); - struct bch_inode_unpacked inode_u; + struct bch_inode_unpacked dir_u, inode_u; struct qstr qstr = QSTR(newname); int ret; + fuse_log(FUSE_LOG_DEBUG, "bcachefs_fuse_link(%llu, %llu, %s)\n", + inum, newparent, newname); + newparent = map_root_ino(newparent); - ret = bch2_trans_do(c, NULL, BTREE_INSERT_ATOMIC, + ret = bch2_trans_do(c, NULL, NULL, 0, bch2_link_trans(&trans, newparent, - inum, &inode_u, &qstr)); + inum, &dir_u, &inode_u, &qstr)); if (!ret) { struct fuse_entry_param e = inode_to_entry(c, &inode_u); @@ -375,19 +408,23 @@ struct fuse_align_io { /* Handle unaligned start and end */ /* TODO: align to block_bytes, sector size, or page size? */ -static void align_io(struct fuse_align_io *align, const struct bch_fs *c, - size_t size, off_t offset) +static struct fuse_align_io align_io(const struct bch_fs *c, size_t size, + off_t offset) { + struct fuse_align_io align; + BUG_ON(offset < 0); - align->start = round_down(offset, block_bytes(c)); - align->pad_start = offset - align->start; + align.start = round_down(offset, block_bytes(c)); + align.pad_start = offset - align.start; off_t end = offset + size; - align->end = round_up(end, block_bytes(c)); - align->pad_end = align->end - end; + align.end = round_up(end, block_bytes(c)); + align.pad_end = align.end - end; + + align.size = align.end - align.start; - align->size = align->end - align->start; + return align; } /* @@ -445,7 +482,6 @@ static void bcachefs_fuse_read(fuse_req_t req, fuse_ino_t inum, struct fuse_file_info *fi) { struct bch_fs *c = fuse_req_userdata(req); - struct fuse_align_io align; fuse_log(FUSE_LOG_DEBUG, "bcachefs_fuse_read(%llu, %zd, %lld)\n", inum, size, offset); @@ -465,7 +501,7 @@ static void bcachefs_fuse_read(fuse_req_t req, fuse_ino_t inum, } size = end - offset; - align_io(&align, c, size, offset); + struct fuse_align_io align = align_io(c, size, offset); void *buf = aligned_alloc(PAGE_SIZE, align.size); if (!buf) { @@ -483,7 +519,7 @@ static void bcachefs_fuse_read(fuse_req_t req, fuse_ino_t inum, free(buf); } -static int write_set_inode(struct bch_fs *c, fuse_ino_t inum, off_t new_size) +static int inode_update_times(struct bch_fs *c, fuse_ino_t inum) { struct btree_trans trans; struct btree_iter *iter; @@ -501,7 +537,6 @@ retry: if (ret) goto err; - inode_u.bi_size = max_t(u64, inode_u.bi_size, new_size); inode_u.bi_mtime = now; inode_u.bi_ctime = now; @@ -510,7 +545,7 @@ retry: goto err; ret = bch2_trans_commit(&trans, NULL, NULL, - BTREE_INSERT_ATOMIC|BTREE_INSERT_NOFAIL); + BTREE_INSERT_NOFAIL); err: if (ret == -EINTR) @@ -523,7 +558,7 @@ err: static int write_aligned(struct bch_fs *c, fuse_ino_t inum, struct bch_io_opts io_opts, void *buf, size_t aligned_size, off_t aligned_offset, - size_t *written_out) + off_t new_i_size, size_t *written_out) { struct bch_write_op op = { 0 }; struct bio_vec bv; @@ -541,6 +576,7 @@ static int write_aligned(struct bch_fs *c, fuse_ino_t inum, op.nr_replicas = io_opts.data_replicas; op.target = io_opts.foreground_target; op.pos = POS(inum, aligned_offset >> 9); + op.new_i_size = new_i_size; userbio_init(&op.wbio.bio, &bv, buf, aligned_size); bio_set_op_attrs(&op.wbio.bio, REQ_OP_WRITE, REQ_SYNC); @@ -567,14 +603,15 @@ static void bcachefs_fuse_write(fuse_req_t req, fuse_ino_t inum, { struct bch_fs *c = fuse_req_userdata(req); struct bch_io_opts io_opts; - struct fuse_align_io align; size_t aligned_written; int ret = 0; fuse_log(FUSE_LOG_DEBUG, "bcachefs_fuse_write(%llu, %zd, %lld)\n", inum, size, offset); - align_io(&align, c, size, offset); + struct fuse_align_io align = align_io(c, size, offset); + void *aligned_buf = aligned_alloc(PAGE_SIZE, align.size); + BUG_ON(!aligned_buf); if (get_inode_io_opts(c, inum, &io_opts)) { ret = -ENOENT; @@ -582,7 +619,6 @@ static void bcachefs_fuse_write(fuse_req_t req, fuse_ino_t inum, } /* Realign the data and read in start and end, if needed */ - void *aligned_buf = aligned_alloc(PAGE_SIZE, align.size); /* Read partial start data. */ if (align.pad_start) { @@ -616,7 +652,8 @@ static void bcachefs_fuse_write(fuse_req_t req, fuse_ino_t inum, /* Actually write. */ ret = write_aligned(c, inum, io_opts, aligned_buf, - align.size, align.start, &aligned_written); + align.size, align.start, + offset + size, &aligned_written); /* Figure out how many unaligned bytes were written. */ size_t written = align_fix_up_bytes(&align, aligned_written); @@ -629,20 +666,22 @@ static void bcachefs_fuse_write(fuse_req_t req, fuse_ino_t inum, ret = 0; /* - * Update inode data. + * Update inode times. * TODO: Integrate with bch2_extent_update() */ if (!ret) - ret = write_set_inode(c, inum, offset + written); + ret = inode_update_times(c, inum); if (!ret) { BUG_ON(written == 0); fuse_reply_write(req, written); + free(aligned_buf); return; } err: fuse_reply_err(req, -ret); + free(aligned_buf); } static void bcachefs_fuse_symlink(fuse_req_t req, const char *link, @@ -653,6 +692,9 @@ static void bcachefs_fuse_symlink(fuse_req_t req, const char *link, size_t link_len = strlen(link); int ret; + fuse_log(FUSE_LOG_DEBUG, "bcachefs_fuse_symlink(%s, %llu, %s)\n", + link, dir, name); + dir = map_root_ino(dir); ret = do_create(c, dir, name, S_IFLNK|S_IRWXUGO, 0, &new_inode); @@ -664,16 +706,18 @@ static void bcachefs_fuse_symlink(fuse_req_t req, const char *link, if (ret) goto err; - struct fuse_align_io align; - align_io(&align, c, link_len + 1, 0); + struct fuse_align_io align = align_io(c, link_len + 1, 0); void *aligned_buf = aligned_alloc(PAGE_SIZE, align.size); + BUG_ON(!aligned_buf); + memset(aligned_buf, 0, align.size); memcpy(aligned_buf, link, link_len); /* already terminated */ size_t aligned_written; ret = write_aligned(c, new_inode.bi_inum, io_opts, aligned_buf, - align.size, align.start, &aligned_written); + align.size, align.start, link_len + 1, + &aligned_written); free(aligned_buf); if (ret) @@ -682,7 +726,7 @@ static void bcachefs_fuse_symlink(fuse_req_t req, const char *link, size_t written = align_fix_up_bytes(&align, aligned_written); BUG_ON(written != link_len + 1); // TODO: handle short - ret = write_set_inode(c, new_inode.bi_inum, written); + ret = inode_update_times(c, new_inode.bi_inum); if (ret) goto err; @@ -701,13 +745,14 @@ static void bcachefs_fuse_readlink(fuse_req_t req, fuse_ino_t inum) struct bch_fs *c = fuse_req_userdata(req); char *buf = NULL; + fuse_log(FUSE_LOG_DEBUG, "bcachefs_fuse_readlink(%llu)\n", inum); + struct bch_inode_unpacked bi; int ret = bch2_inode_find_by_inum(c, inum, &bi); if (ret) goto err; - struct fuse_align_io align; - align_io(&align, c, bi.bi_size, 0); + struct fuse_align_io align = align_io(c, bi.bi_size, 0); ret = -ENOMEM; buf = aligned_alloc(PAGE_SIZE, align.size); @@ -762,43 +807,44 @@ static void bcachefs_fuse_opendir(fuse_req_t req, fuse_ino_t inum, } #endif -struct fuse_dir_entry { - u64 ino; - unsigned type; - char name[0]; -}; - struct fuse_dir_context { struct dir_context ctx; fuse_req_t req; char *buf; size_t bufsize; - - struct fuse_dir_entry *prev; }; -static int fuse_send_dir_entry(struct fuse_dir_context *ctx, loff_t pos) -{ - struct fuse_dir_entry *de = ctx->prev; - ctx->prev = NULL; +struct fuse_dirent { + uint64_t ino; + uint64_t off; + uint32_t namelen; + uint32_t type; + char name[]; +}; - struct stat statbuf = { - .st_ino = unmap_root_ino(de->ino), - .st_mode = de->type << 12, - }; +#define FUSE_NAME_OFFSET offsetof(struct fuse_dirent, name) +#define FUSE_DIRENT_ALIGN(x) \ + (((x) + sizeof(uint64_t) - 1) & ~(sizeof(uint64_t) - 1)) - size_t len = fuse_add_direntry(ctx->req, ctx->buf, ctx->bufsize, - de->name, &statbuf, pos); +static size_t fuse_add_direntry2(char *buf, size_t bufsize, + const char *name, int namelen, + const struct stat *stbuf, off_t off) +{ + size_t entlen = FUSE_NAME_OFFSET + namelen; + size_t entlen_padded = FUSE_DIRENT_ALIGN(entlen); + struct fuse_dirent *dirent = (struct fuse_dirent *) buf; - free(de); + if ((buf == NULL) || (entlen_padded > bufsize)) + return entlen_padded; - if (len > ctx->bufsize) - return -EINVAL; + dirent->ino = stbuf->st_ino; + dirent->off = off; + dirent->namelen = namelen; + dirent->type = (stbuf->st_mode & S_IFMT) >> 12; + memcpy(dirent->name, name, namelen); + memset(dirent->name + namelen, 0, entlen_padded - entlen); - ctx->buf += len; - ctx->bufsize -= len; - - return 0; + return entlen_padded; } static int fuse_filldir(struct dir_context *_ctx, @@ -808,47 +854,42 @@ static int fuse_filldir(struct dir_context *_ctx, struct fuse_dir_context *ctx = container_of(_ctx, struct fuse_dir_context, ctx); - fuse_log(FUSE_LOG_DEBUG, "fuse_filldir(ctx={.ctx={.pos=%llu}}, " - "name=%s, namelen=%d, pos=%lld, dir=%llu, type=%u)\n", - ctx->ctx.pos, name, namelen, pos, ino, type); + struct stat statbuf = { + .st_ino = unmap_root_ino(ino), + .st_mode = type << 12, + }; - /* - * We have to emit directory entries after reading the next entry, - * because the previous entry contains a pointer to next. - */ - if (ctx->prev) { - int ret = fuse_send_dir_entry(ctx, pos); - if (ret) - return ret; - } + fuse_log(FUSE_LOG_DEBUG, "fuse_filldir(name=%s inum=%llu pos=%llu)\n", + name, statbuf.st_ino, pos); + + size_t len = fuse_add_direntry2(ctx->buf, + ctx->bufsize, + name, + namelen, + &statbuf, + pos + 1); - struct fuse_dir_entry *cur = malloc(sizeof *cur + namelen + 1); - cur->ino = ino; - cur->type = type; - memcpy(cur->name, name, namelen); - cur->name[namelen] = 0; + if (len > ctx->bufsize) + return -1; - ctx->prev = cur; + ctx->buf += len; + ctx->bufsize -= len; return 0; } static bool handle_dots(struct fuse_dir_context *ctx, fuse_ino_t dir) { - int ret = 0; - if (ctx->ctx.pos == 0) { - ret = fuse_filldir(&ctx->ctx, ".", 1, ctx->ctx.pos, - unmap_root_ino(dir), DT_DIR); - if (ret < 0) + if (fuse_filldir(&ctx->ctx, ".", 1, ctx->ctx.pos, + dir, DT_DIR) < 0) return false; ctx->ctx.pos = 1; } if (ctx->ctx.pos == 1) { - ret = fuse_filldir(&ctx->ctx, "..", 2, ctx->ctx.pos, - /*TODO: parent*/ 1, DT_DIR); - if (ret < 0) + if (fuse_filldir(&ctx->ctx, "..", 2, ctx->ctx.pos, + /*TODO: parent*/ 1, DT_DIR) < 0) return false; ctx->ctx.pos = 2; } @@ -890,20 +931,7 @@ static void bcachefs_fuse_readdir(fuse_req_t req, fuse_ino_t dir, goto reply; ret = bch2_readdir(c, dir, &ctx.ctx); - reply: - /* - * If we have something to send, the error above doesn't matter. - * - * Alternatively, if this send fails, but we previously sent something, - * then this is a success. - */ - if (ctx.prev) { - ret = fuse_send_dir_entry(&ctx, ctx.ctx.pos); - if (ret && ctx.buf != buf) - ret = 0; - } - if (!ret) { fuse_log(FUSE_LOG_DEBUG, "bcachefs_fuse_readdir reply %zd\n", ctx.buf - buf); @@ -991,6 +1019,9 @@ static void bcachefs_fuse_create(fuse_req_t req, fuse_ino_t dir, struct bch_inode_unpacked new_inode; int ret; + fuse_log(FUSE_LOG_DEBUG, "bcachefs_fuse_create(%llu, %s, %x)\n", + dir, name, mode); + ret = do_create(c, dir, name, mode, 0, &new_inode); if (ret) goto err; @@ -1213,6 +1244,9 @@ int cmd_fusemount(int argc, char *argv[]) if (fuse_session_mount(se, fuse_opts.mountpoint)) die("fuse_mount err: %m"); + /* This print statement is a trigger for tests. */ + printf("Fuse mount initialized.\n"); + fuse_daemonize(fuse_opts.foreground); ret = fuse_session_loop(se); @@ -1229,3 +1263,5 @@ out: return ret ? 1 : 0; } + +#endif /* BCACHEFS_FUSE */