]> git.sesse.net Git - bcachefs-tools-debian/blob - cmd_fusemount.c
f07edb5abff877cc9f7d38ed2a5e63abb7d25f38
[bcachefs-tools-debian] / cmd_fusemount.c
1 #ifdef BCACHEFS_FUSE
2
3 #include <errno.h>
4 #include <float.h>
5 #include <getopt.h>
6 #include <stdio.h>
7 #include <sys/statvfs.h>
8
9 #include <fuse_lowlevel.h>
10
11 #include "cmds.h"
12 #include "libbcachefs.h"
13 #include "tools-util.h"
14
15 #include "libbcachefs/bcachefs.h"
16 #include "libbcachefs/alloc_foreground.h"
17 #include "libbcachefs/btree_iter.h"
18 #include "libbcachefs/buckets.h"
19 #include "libbcachefs/dirent.h"
20 #include "libbcachefs/errcode.h"
21 #include "libbcachefs/error.h"
22 #include "libbcachefs/fs-common.h"
23 #include "libbcachefs/inode.h"
24 #include "libbcachefs/io.h"
25 #include "libbcachefs/opts.h"
26 #include "libbcachefs/super.h"
27
28 /* mode_to_type(): */
29 #include "libbcachefs/fs.h"
30
31 #include <linux/dcache.h>
32
33 /* XXX cut and pasted from fsck.c */
34 #define QSTR(n) { { { .len = strlen(n) } }, .name = n }
35
36 static inline subvol_inum map_root_ino(u64 ino)
37 {
38         return (subvol_inum) { 1, ino == 1 ? 4096 : ino };
39 }
40
41 static inline u64 unmap_root_ino(u64 ino)
42 {
43         return ino == 4096 ? 1 : ino;
44 }
45
46 static struct stat inode_to_stat(struct bch_fs *c,
47                                  struct bch_inode_unpacked *bi)
48 {
49         return (struct stat) {
50                 .st_ino         = unmap_root_ino(bi->bi_inum),
51                 .st_size        = bi->bi_size,
52                 .st_mode        = bi->bi_mode,
53                 .st_uid         = bi->bi_uid,
54                 .st_gid         = bi->bi_gid,
55                 .st_nlink       = bch2_inode_nlink_get(bi),
56                 .st_rdev        = bi->bi_dev,
57                 .st_blksize     = block_bytes(c),
58                 .st_blocks      = bi->bi_sectors,
59                 .st_atim        = bch2_time_to_timespec(c, bi->bi_atime),
60                 .st_mtim        = bch2_time_to_timespec(c, bi->bi_mtime),
61                 .st_ctim        = bch2_time_to_timespec(c, bi->bi_ctime),
62         };
63 }
64
65 static struct fuse_entry_param inode_to_entry(struct bch_fs *c,
66                                               struct bch_inode_unpacked *bi)
67 {
68         return (struct fuse_entry_param) {
69                 .ino            = unmap_root_ino(bi->bi_inum),
70                 .generation     = bi->bi_generation,
71                 .attr           = inode_to_stat(c, bi),
72                 .attr_timeout   = DBL_MAX,
73                 .entry_timeout  = DBL_MAX,
74         };
75 }
76
77 static void bcachefs_fuse_init(void *arg, struct fuse_conn_info *conn)
78 {
79         if (conn->capable & FUSE_CAP_WRITEBACK_CACHE) {
80                 fuse_log(FUSE_LOG_DEBUG, "fuse_init: activating writeback\n");
81                 conn->want |= FUSE_CAP_WRITEBACK_CACHE;
82         } else
83                 fuse_log(FUSE_LOG_DEBUG, "fuse_init: writeback not capable\n");
84
85         //conn->want |= FUSE_CAP_POSIX_ACL;
86 }
87
88 static void bcachefs_fuse_destroy(void *arg)
89 {
90         struct bch_fs *c = arg;
91
92         bch2_fs_stop(c);
93 }
94
95 static void bcachefs_fuse_lookup(fuse_req_t req, fuse_ino_t dir_ino,
96                                  const char *name)
97 {
98         subvol_inum dir = map_root_ino(dir_ino);
99         struct bch_fs *c = fuse_req_userdata(req);
100         struct bch_inode_unpacked bi;
101         struct qstr qstr = QSTR(name);
102         subvol_inum inum;
103         int ret;
104
105         fuse_log(FUSE_LOG_DEBUG, "fuse_lookup(dir=%llu name=%s)\n",
106                  dir.inum, name);
107
108         ret = bch2_inode_find_by_inum(c, dir, &bi);
109         if (ret) {
110                 fuse_reply_err(req, -ret);
111                 return;
112         }
113
114         struct bch_hash_info hash_info = bch2_hash_info_init(c, &bi);
115
116         ret = bch2_dirent_lookup(c, dir, &hash_info, &qstr, &inum);
117         if (ret) {
118                 struct fuse_entry_param e = {
119                         .attr_timeout   = DBL_MAX,
120                         .entry_timeout  = DBL_MAX,
121                 };
122                 fuse_reply_entry(req, &e);
123                 return;
124         }
125
126         ret = bch2_inode_find_by_inum(c, inum, &bi);
127         if (ret)
128                 goto err;
129
130         fuse_log(FUSE_LOG_DEBUG, "fuse_lookup ret(inum=%llu)\n",
131                  bi.bi_inum);
132
133         struct fuse_entry_param e = inode_to_entry(c, &bi);
134         fuse_reply_entry(req, &e);
135         return;
136 err:
137         fuse_log(FUSE_LOG_DEBUG, "fuse_lookup error %i\n", ret);
138         fuse_reply_err(req, -ret);
139 }
140
141 static void bcachefs_fuse_getattr(fuse_req_t req, fuse_ino_t ino,
142                                   struct fuse_file_info *fi)
143 {
144         subvol_inum inum = map_root_ino(ino);
145         struct bch_fs *c = fuse_req_userdata(req);
146         struct bch_inode_unpacked bi;
147         struct stat attr;
148
149         fuse_log(FUSE_LOG_DEBUG, "fuse_getattr(inum=%llu)\n", inum.inum);
150
151         int ret = bch2_inode_find_by_inum(c, inum, &bi);
152         if (ret) {
153                 fuse_log(FUSE_LOG_DEBUG, "fuse_getattr error %i\n", ret);
154                 fuse_reply_err(req, -ret);
155                 return;
156         }
157
158         fuse_log(FUSE_LOG_DEBUG, "fuse_getattr success\n");
159
160         attr = inode_to_stat(c, &bi);
161         fuse_reply_attr(req, &attr, DBL_MAX);
162 }
163
164 static void bcachefs_fuse_setattr(fuse_req_t req, fuse_ino_t ino,
165                                   struct stat *attr, int to_set,
166                                   struct fuse_file_info *fi)
167 {
168         struct bch_fs *c = fuse_req_userdata(req);
169         struct bch_inode_unpacked inode_u;
170         struct btree_trans trans;
171         struct btree_iter iter;
172         u64 now;
173         int ret;
174
175         subvol_inum inum = map_root_ino(ino);
176
177         fuse_log(FUSE_LOG_DEBUG, "bcachefs_fuse_setattr(%llu, %x)\n", inum.inum, to_set);
178
179         bch2_trans_init(&trans, c, 0, 0);
180 retry:
181         bch2_trans_begin(&trans);
182         now = bch2_current_time(c);
183
184         ret = bch2_inode_peek(&trans, &iter, &inode_u, inum, BTREE_ITER_INTENT);
185         if (ret)
186                 goto err;
187
188         if (to_set & FUSE_SET_ATTR_MODE)
189                 inode_u.bi_mode = attr->st_mode;
190         if (to_set & FUSE_SET_ATTR_UID)
191                 inode_u.bi_uid  = attr->st_uid;
192         if (to_set & FUSE_SET_ATTR_GID)
193                 inode_u.bi_gid  = attr->st_gid;
194         if (to_set & FUSE_SET_ATTR_SIZE)
195                 inode_u.bi_size = attr->st_size;
196         if (to_set & FUSE_SET_ATTR_ATIME)
197                 inode_u.bi_atime = timespec_to_bch2_time(c, attr->st_atim);
198         if (to_set & FUSE_SET_ATTR_MTIME)
199                 inode_u.bi_mtime = timespec_to_bch2_time(c, attr->st_mtim);
200         if (to_set & FUSE_SET_ATTR_ATIME_NOW)
201                 inode_u.bi_atime = now;
202         if (to_set & FUSE_SET_ATTR_MTIME_NOW)
203                 inode_u.bi_mtime = now;
204         /* TODO: CTIME? */
205
206         ret   = bch2_inode_write(&trans, &iter, &inode_u) ?:
207                 bch2_trans_commit(&trans, NULL, NULL,
208                                   BTREE_INSERT_NOFAIL);
209 err:
210         bch2_trans_iter_exit(&trans, &iter);
211         if (ret == -EINTR)
212                 goto retry;
213
214         bch2_trans_exit(&trans);
215
216         if (!ret) {
217                 *attr = inode_to_stat(c, &inode_u);
218                 fuse_reply_attr(req, attr, DBL_MAX);
219         } else {
220                 fuse_reply_err(req, -ret);
221         }
222 }
223
224 static int do_create(struct bch_fs *c, subvol_inum dir,
225                      const char *name, mode_t mode, dev_t rdev,
226                      struct bch_inode_unpacked *new_inode)
227 {
228         struct qstr qstr = QSTR(name);
229         struct bch_inode_unpacked dir_u;
230         uid_t uid = 0;
231         gid_t gid = 0;
232
233         bch2_inode_init_early(c, new_inode);
234
235         return bch2_trans_do(c, NULL, NULL, 0,
236                         bch2_create_trans(&trans,
237                                 dir, &dir_u,
238                                 new_inode, &qstr,
239                                 uid, gid, mode, rdev, NULL, NULL,
240                                 (subvol_inum) { 0 }, 0));
241 }
242
243 static void bcachefs_fuse_mknod(fuse_req_t req, fuse_ino_t dir_ino,
244                                 const char *name, mode_t mode,
245                                 dev_t rdev)
246 {
247         subvol_inum dir = map_root_ino(dir_ino);
248         struct bch_fs *c = fuse_req_userdata(req);
249         struct bch_inode_unpacked new_inode;
250         int ret;
251
252         fuse_log(FUSE_LOG_DEBUG, "bcachefs_fuse_mknod(%llu, %s, %x, %x)\n",
253                  dir.inum, name, mode, rdev);
254
255         ret = do_create(c, dir, name, mode, rdev, &new_inode);
256         if (ret)
257                 goto err;
258
259         struct fuse_entry_param e = inode_to_entry(c, &new_inode);
260         fuse_reply_entry(req, &e);
261         return;
262 err:
263         fuse_reply_err(req, -ret);
264 }
265
266 static void bcachefs_fuse_mkdir(fuse_req_t req, fuse_ino_t dir,
267                                 const char *name, mode_t mode)
268 {
269         fuse_log(FUSE_LOG_DEBUG, "bcachefs_fuse_mkdir(%llu, %s, %x)\n",
270                  dir, name, mode);
271
272         BUG_ON(mode & S_IFMT);
273
274         mode |= S_IFDIR;
275         bcachefs_fuse_mknod(req, dir, name, mode, 0);
276 }
277
278 static void bcachefs_fuse_unlink(fuse_req_t req, fuse_ino_t dir_ino,
279                                  const char *name)
280 {
281         struct bch_fs *c = fuse_req_userdata(req);
282         struct bch_inode_unpacked dir_u, inode_u;
283         struct qstr qstr = QSTR(name);
284         subvol_inum dir = map_root_ino(dir_ino);
285
286         fuse_log(FUSE_LOG_DEBUG, "bcachefs_fuse_unlink(%llu, %s)\n", dir.inum, name);
287
288         int ret = bch2_trans_do(c, NULL, NULL, BTREE_INSERT_NOFAIL,
289                             bch2_unlink_trans(&trans, dir, &dir_u,
290                                               &inode_u, &qstr, false));
291
292         fuse_reply_err(req, -ret);
293 }
294
295 static void bcachefs_fuse_rmdir(fuse_req_t req, fuse_ino_t dir,
296                                 const char *name)
297 {
298         fuse_log(FUSE_LOG_DEBUG, "bcachefs_fuse_rmdir(%llu, %s)\n", dir, name);
299
300         bcachefs_fuse_unlink(req, dir, name);
301 }
302
303 static void bcachefs_fuse_rename(fuse_req_t req,
304                                  fuse_ino_t src_dir_ino, const char *srcname,
305                                  fuse_ino_t dst_dir_ino, const char *dstname,
306                                  unsigned flags)
307 {
308         struct bch_fs *c = fuse_req_userdata(req);
309         struct bch_inode_unpacked dst_dir_u, src_dir_u;
310         struct bch_inode_unpacked src_inode_u, dst_inode_u;
311         struct qstr dst_name = QSTR(srcname);
312         struct qstr src_name = QSTR(dstname);
313         subvol_inum src_dir = map_root_ino(src_dir_ino);
314         subvol_inum dst_dir = map_root_ino(dst_dir_ino);
315         int ret;
316
317         fuse_log(FUSE_LOG_DEBUG,
318                  "bcachefs_fuse_rename(%llu, %s, %llu, %s, %x)\n",
319                  src_dir.inum, srcname, dst_dir.inum, dstname, flags);
320
321         /* XXX handle overwrites */
322         ret = bch2_trans_do(c, NULL, NULL, 0,
323                 bch2_rename_trans(&trans,
324                                   src_dir, &src_dir_u,
325                                   dst_dir, &dst_dir_u,
326                                   &src_inode_u, &dst_inode_u,
327                                   &src_name, &dst_name,
328                                   BCH_RENAME));
329
330         fuse_reply_err(req, -ret);
331 }
332
333 static void bcachefs_fuse_link(fuse_req_t req, fuse_ino_t ino,
334                                fuse_ino_t newparent_ino, const char *newname)
335 {
336         struct bch_fs *c = fuse_req_userdata(req);
337         struct bch_inode_unpacked dir_u, inode_u;
338         struct qstr qstr = QSTR(newname);
339         subvol_inum newparent   = map_root_ino(newparent_ino);
340         subvol_inum inum        = map_root_ino(ino);
341         int ret;
342
343         fuse_log(FUSE_LOG_DEBUG, "bcachefs_fuse_link(%llu, %llu, %s)\n",
344                  inum, newparent.inum, newname);
345
346         ret = bch2_trans_do(c, NULL, NULL, 0,
347                             bch2_link_trans(&trans, newparent, &dir_u,
348                                             inum, &inode_u, &qstr));
349
350         if (!ret) {
351                 struct fuse_entry_param e = inode_to_entry(c, &inode_u);
352                 fuse_reply_entry(req, &e);
353         } else {
354                 fuse_reply_err(req, -ret);
355         }
356 }
357
358 static void bcachefs_fuse_open(fuse_req_t req, fuse_ino_t inum,
359                                struct fuse_file_info *fi)
360 {
361         fi->direct_io           = false;
362         fi->keep_cache          = true;
363         fi->cache_readdir       = true;
364
365         fuse_reply_open(req, fi);
366 }
367
368 static void userbio_init(struct bio *bio, struct bio_vec *bv,
369                          void *buf, size_t size)
370 {
371         bio_init(bio, NULL, bv, 1, 0);
372         bio->bi_iter.bi_size    = size;
373         bv->bv_page             = buf;
374         bv->bv_len              = size;
375         bv->bv_offset           = 0;
376 }
377
378 static int get_inode_io_opts(struct bch_fs *c, subvol_inum inum, struct bch_io_opts *opts)
379 {
380         struct bch_inode_unpacked inode;
381         if (bch2_inode_find_by_inum(c, inum, &inode))
382                 return -EINVAL;
383
384         bch2_inode_opts_get(opts, c, &inode);
385         return 0;
386 }
387
388 static void bcachefs_fuse_read_endio(struct bio *bio)
389 {
390         closure_put(bio->bi_private);
391 }
392
393 struct fuse_align_io {
394         off_t           start;
395         size_t          pad_start;
396         off_t           end;
397         size_t          pad_end;
398         size_t          size;
399 };
400
401 /* Handle unaligned start and end */
402 /* TODO: align to block_bytes, sector size, or page size? */
403 static struct fuse_align_io align_io(const struct bch_fs *c, size_t size,
404                                      off_t offset)
405 {
406         struct fuse_align_io align;
407
408         BUG_ON(offset < 0);
409
410         align.start = round_down(offset, block_bytes(c));
411         align.pad_start = offset - align.start;
412
413         off_t end = offset + size;
414         align.end = round_up(end, block_bytes(c));
415         align.pad_end = align.end - end;
416
417         align.size = align.end - align.start;
418
419         return align;
420 }
421
422 /*
423  * Given an aligned number of bytes transferred, figure out how many unaligned
424  * bytes were transferred.
425  */
426 static size_t align_fix_up_bytes(const struct fuse_align_io *align,
427                                  size_t align_bytes)
428 {
429         size_t bytes = 0;
430
431         if (align_bytes > align->pad_start) {
432                 bytes = align_bytes - align->pad_start;
433                 bytes = bytes > align->pad_end ? bytes - align->pad_end : 0;
434         }
435
436         return bytes;
437 }
438
439 /*
440  * Read aligned data.
441  */
442 static int read_aligned(struct bch_fs *c, subvol_inum inum, size_t aligned_size,
443                         off_t aligned_offset, void *buf)
444 {
445         BUG_ON(aligned_size & (block_bytes(c) - 1));
446         BUG_ON(aligned_offset & (block_bytes(c) - 1));
447
448         struct bch_io_opts io_opts;
449         if (get_inode_io_opts(c, inum, &io_opts))
450                 return -ENOENT;
451
452         struct bch_read_bio rbio;
453         struct bio_vec bv;
454         userbio_init(&rbio.bio, &bv, buf, aligned_size);
455         bio_set_op_attrs(&rbio.bio, REQ_OP_READ, REQ_SYNC);
456         rbio.bio.bi_iter.bi_sector      = aligned_offset >> 9;
457
458         struct closure cl;
459         closure_init_stack(&cl);
460
461         closure_get(&cl);
462         rbio.bio.bi_end_io              = bcachefs_fuse_read_endio;
463         rbio.bio.bi_private             = &cl;
464
465         bch2_read(c, rbio_init(&rbio.bio, io_opts), inum);
466
467         closure_sync(&cl);
468
469         return -blk_status_to_errno(rbio.bio.bi_status);
470 }
471
472 static void bcachefs_fuse_read(fuse_req_t req, fuse_ino_t ino,
473                                size_t size, off_t offset,
474                                struct fuse_file_info *fi)
475 {
476         subvol_inum inum = map_root_ino(ino);
477         struct bch_fs *c = fuse_req_userdata(req);
478
479         fuse_log(FUSE_LOG_DEBUG, "bcachefs_fuse_read(%llu, %zd, %lld)\n",
480                  inum, size, offset);
481
482         /* Check inode size. */
483         struct bch_inode_unpacked bi;
484         int ret = bch2_inode_find_by_inum(c, inum, &bi);
485         if (ret) {
486                 fuse_reply_err(req, -ret);
487                 return;
488         }
489
490         off_t end = min_t(u64, bi.bi_size, offset + size);
491         if (end <= offset) {
492                 fuse_reply_buf(req, NULL, 0);
493                 return;
494         }
495         size = end - offset;
496
497         struct fuse_align_io align = align_io(c, size, offset);
498
499         void *buf = aligned_alloc(PAGE_SIZE, align.size);
500         if (!buf) {
501                 fuse_reply_err(req, ENOMEM);
502                 return;
503         }
504
505         ret = read_aligned(c, inum, align.size, align.start, buf);
506
507         if (likely(!ret))
508                 fuse_reply_buf(req, buf + align.pad_start, size);
509         else
510                 fuse_reply_err(req, -ret);
511
512         free(buf);
513 }
514
515 static int inode_update_times(struct bch_fs *c, subvol_inum inum)
516 {
517         struct btree_trans trans;
518         struct btree_iter iter;
519         struct bch_inode_unpacked inode_u;
520         int ret = 0;
521         u64 now;
522
523         bch2_trans_init(&trans, c, 0, 0);
524 retry:
525         bch2_trans_begin(&trans);
526         now = bch2_current_time(c);
527
528         ret = bch2_inode_peek(&trans, &iter, &inode_u, inum, BTREE_ITER_INTENT);
529         if (ret)
530                 goto err;
531
532         inode_u.bi_mtime = now;
533         inode_u.bi_ctime = now;
534
535         ret = bch2_inode_write(&trans, &iter, &inode_u);
536         if (ret)
537                 goto err;
538
539         ret = bch2_trans_commit(&trans, NULL, NULL,
540                                 BTREE_INSERT_NOFAIL);
541
542 err:
543         bch2_trans_iter_exit(&trans, &iter);
544         if (ret == -EINTR)
545                 goto retry;
546
547         bch2_trans_exit(&trans);
548         return ret;
549 }
550
551 static int write_aligned(struct bch_fs *c, subvol_inum inum,
552                          struct bch_io_opts io_opts, void *buf,
553                          size_t aligned_size, off_t aligned_offset,
554                          off_t new_i_size, size_t *written_out)
555 {
556         struct bch_write_op     op = { 0 };
557         struct bio_vec          bv;
558         struct closure          cl;
559
560         BUG_ON(aligned_size & (block_bytes(c) - 1));
561         BUG_ON(aligned_offset & (block_bytes(c) - 1));
562
563         *written_out = 0;
564
565         closure_init_stack(&cl);
566
567         bch2_write_op_init(&op, c, io_opts); /* XXX reads from op?! */
568         op.write_point  = writepoint_hashed(0);
569         op.nr_replicas  = io_opts.data_replicas;
570         op.target       = io_opts.foreground_target;
571         op.subvol       = inum.subvol;
572         op.pos          = POS(inum.inum, aligned_offset >> 9);
573         op.new_i_size   = new_i_size;
574
575         userbio_init(&op.wbio.bio, &bv, buf, aligned_size);
576         bio_set_op_attrs(&op.wbio.bio, REQ_OP_WRITE, REQ_SYNC);
577
578         if (bch2_disk_reservation_get(c, &op.res, aligned_size >> 9,
579                                       op.nr_replicas, 0)) {
580                 /* XXX: use check_range_allocated like dio write path */
581                 return -ENOSPC;
582         }
583
584         closure_call(&op.cl, bch2_write, NULL, &cl);
585         closure_sync(&cl);
586
587         if (!op.error)
588                 *written_out = op.written << 9;
589
590         return op.error;
591 }
592
593 static void bcachefs_fuse_write(fuse_req_t req, fuse_ino_t ino,
594                                 const char *buf, size_t size,
595                                 off_t offset,
596                                 struct fuse_file_info *fi)
597 {
598         subvol_inum inum = map_root_ino(ino);
599         struct bch_fs *c        = fuse_req_userdata(req);
600         struct bch_io_opts      io_opts;
601         size_t                  aligned_written;
602         int                     ret = 0;
603
604         fuse_log(FUSE_LOG_DEBUG, "bcachefs_fuse_write(%llu, %zd, %lld)\n",
605                  inum, size, offset);
606
607         struct fuse_align_io align = align_io(c, size, offset);
608         void *aligned_buf = aligned_alloc(PAGE_SIZE, align.size);
609         BUG_ON(!aligned_buf);
610
611         if (get_inode_io_opts(c, inum, &io_opts)) {
612                 ret = -ENOENT;
613                 goto err;
614         }
615
616         /* Realign the data and read in start and end, if needed */
617
618         /* Read partial start data. */
619         if (align.pad_start) {
620                 memset(aligned_buf, 0, block_bytes(c));
621
622                 ret = read_aligned(c, inum, block_bytes(c), align.start,
623                                    aligned_buf);
624                 if (ret)
625                         goto err;
626         }
627
628         /*
629          * Read partial end data. If the whole write fits in one block, the
630          * start data and the end data are the same so this isn't needed.
631          */
632         if (align.pad_end &&
633             !(align.pad_start && align.size == block_bytes(c))) {
634                 off_t partial_end_start = align.end - block_bytes(c);
635                 size_t buf_offset = align.size - block_bytes(c);
636
637                 memset(aligned_buf + buf_offset, 0, block_bytes(c));
638
639                 ret = read_aligned(c, inum, block_bytes(c), partial_end_start,
640                                    aligned_buf + buf_offset);
641                 if (ret)
642                         goto err;
643         }
644
645         /* Overlay what we want to write. */
646         memcpy(aligned_buf + align.pad_start, buf, size);
647
648         /* Actually write. */
649         ret = write_aligned(c, inum, io_opts, aligned_buf,
650                             align.size, align.start,
651                             offset + size, &aligned_written);
652
653         /* Figure out how many unaligned bytes were written. */
654         size_t written = align_fix_up_bytes(&align, aligned_written);
655         BUG_ON(written > size);
656
657         fuse_log(FUSE_LOG_DEBUG, "bcachefs_fuse_write: wrote %zd bytes\n",
658                  written);
659
660         if (written > 0)
661                 ret = 0;
662
663         /*
664          * Update inode times.
665          * TODO: Integrate with bch2_extent_update()
666          */
667         if (!ret)
668                 ret = inode_update_times(c, inum);
669
670         if (!ret) {
671                 BUG_ON(written == 0);
672                 fuse_reply_write(req, written);
673                 free(aligned_buf);
674                 return;
675         }
676
677 err:
678         fuse_reply_err(req, -ret);
679         free(aligned_buf);
680 }
681
682 static void bcachefs_fuse_symlink(fuse_req_t req, const char *link,
683                                   fuse_ino_t dir_ino, const char *name)
684 {
685         subvol_inum dir = map_root_ino(dir_ino);
686         struct bch_fs *c = fuse_req_userdata(req);
687         struct bch_inode_unpacked new_inode;
688         size_t link_len = strlen(link);
689         int ret;
690
691         fuse_log(FUSE_LOG_DEBUG, "bcachefs_fuse_symlink(%s, %llu, %s)\n",
692                  link, dir.inum, name);
693
694         ret = do_create(c, dir, name, S_IFLNK|S_IRWXUGO, 0, &new_inode);
695         if (ret)
696                 goto err;
697
698         struct bch_io_opts io_opts;
699         ret = get_inode_io_opts(c, dir, &io_opts);
700         if (ret)
701                 goto err;
702
703         struct fuse_align_io align = align_io(c, link_len + 1, 0);
704
705         void *aligned_buf = aligned_alloc(PAGE_SIZE, align.size);
706         BUG_ON(!aligned_buf);
707
708         memset(aligned_buf, 0, align.size);
709         memcpy(aligned_buf, link, link_len); /* already terminated */
710
711         subvol_inum inum = (subvol_inum) { dir.subvol, new_inode.bi_inum };
712
713         size_t aligned_written;
714         ret = write_aligned(c, inum, io_opts, aligned_buf,
715                             align.size, align.start, link_len + 1,
716                             &aligned_written);
717         free(aligned_buf);
718
719         if (ret)
720                 goto err;
721
722         size_t written = align_fix_up_bytes(&align, aligned_written);
723         BUG_ON(written != link_len + 1); // TODO: handle short
724
725         ret = inode_update_times(c, inum);
726         if (ret)
727                 goto err;
728
729         new_inode.bi_size = written;
730
731         struct fuse_entry_param e = inode_to_entry(c, &new_inode);
732         fuse_reply_entry(req, &e);
733         return;
734
735 err:
736         fuse_reply_err(req, -ret);
737 }
738
739 static void bcachefs_fuse_readlink(fuse_req_t req, fuse_ino_t ino)
740 {
741         subvol_inum inum = map_root_ino(ino);
742         struct bch_fs *c = fuse_req_userdata(req);
743         char *buf = NULL;
744
745         fuse_log(FUSE_LOG_DEBUG, "bcachefs_fuse_readlink(%llu)\n", inum.inum);
746
747         struct bch_inode_unpacked bi;
748         int ret = bch2_inode_find_by_inum(c, inum, &bi);
749         if (ret)
750                 goto err;
751
752         struct fuse_align_io align = align_io(c, bi.bi_size, 0);
753
754         ret = -ENOMEM;
755         buf = aligned_alloc(PAGE_SIZE, align.size);
756         if (!buf)
757                 goto err;
758
759         ret = read_aligned(c, inum, align.size, align.start, buf);
760         if (ret)
761                 goto err;
762
763         BUG_ON(buf[align.size - 1] != 0);
764
765         fuse_reply_readlink(req, buf);
766
767 err:
768         if (ret)
769                 fuse_reply_err(req, -ret);
770
771         free(buf);
772 }
773
774 #if 0
775 /*
776  * FUSE flush is essentially the close() call, however it is not guaranteed
777  * that one flush happens per open/create.
778  *
779  * It doesn't have to do anything, and is mostly relevant for NFS-style
780  * filesystems where close has some relationship to caching.
781  */
782 static void bcachefs_fuse_flush(fuse_req_t req, fuse_ino_t inum,
783                                 struct fuse_file_info *fi)
784 {
785         struct bch_fs *c = fuse_req_userdata(req);
786 }
787
788 static void bcachefs_fuse_release(fuse_req_t req, fuse_ino_t inum,
789                                   struct fuse_file_info *fi)
790 {
791         struct bch_fs *c = fuse_req_userdata(req);
792 }
793
794 static void bcachefs_fuse_fsync(fuse_req_t req, fuse_ino_t inum, int datasync,
795                                 struct fuse_file_info *fi)
796 {
797         struct bch_fs *c = fuse_req_userdata(req);
798 }
799
800 static void bcachefs_fuse_opendir(fuse_req_t req, fuse_ino_t inum,
801                                   struct fuse_file_info *fi)
802 {
803         struct bch_fs *c = fuse_req_userdata(req);
804 }
805 #endif
806
807 struct fuse_dir_context {
808         struct dir_context      ctx;
809         fuse_req_t              req;
810         char                    *buf;
811         size_t                  bufsize;
812 };
813
814 struct fuse_dirent {
815         uint64_t        ino;
816         uint64_t        off;
817         uint32_t        namelen;
818         uint32_t        type;
819         char name[];
820 };
821
822 #define FUSE_NAME_OFFSET offsetof(struct fuse_dirent, name)
823 #define FUSE_DIRENT_ALIGN(x) \
824         (((x) + sizeof(uint64_t) - 1) & ~(sizeof(uint64_t) - 1))
825
826 static size_t fuse_add_direntry2(char *buf, size_t bufsize,
827                                  const char *name, int namelen,
828                                  const struct stat *stbuf, off_t off)
829 {
830         size_t entlen           = FUSE_NAME_OFFSET + namelen;
831         size_t entlen_padded    = FUSE_DIRENT_ALIGN(entlen);
832         struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
833
834         if ((buf == NULL) || (entlen_padded > bufsize))
835                 return entlen_padded;
836
837         dirent->ino = stbuf->st_ino;
838         dirent->off = off;
839         dirent->namelen = namelen;
840         dirent->type = (stbuf->st_mode & S_IFMT) >> 12;
841         memcpy(dirent->name, name, namelen);
842         memset(dirent->name + namelen, 0, entlen_padded - entlen);
843
844         return entlen_padded;
845 }
846
847 static int fuse_filldir(struct dir_context *_ctx,
848                         const char *name, int namelen,
849                         loff_t pos, u64 ino, unsigned type)
850 {
851         struct fuse_dir_context *ctx =
852                 container_of(_ctx, struct fuse_dir_context, ctx);
853
854         struct stat statbuf = {
855                 .st_ino         = unmap_root_ino(ino),
856                 .st_mode        = type << 12,
857         };
858
859         fuse_log(FUSE_LOG_DEBUG, "fuse_filldir(name=%s inum=%llu pos=%llu)\n",
860                  name, statbuf.st_ino, pos);
861
862         size_t len = fuse_add_direntry2(ctx->buf,
863                                         ctx->bufsize,
864                                         name,
865                                         namelen,
866                                         &statbuf,
867                                         pos + 1);
868
869         if (len > ctx->bufsize)
870                 return -1;
871
872         ctx->buf        += len;
873         ctx->bufsize    -= len;
874
875         return 0;
876 }
877
878 static bool handle_dots(struct fuse_dir_context *ctx, fuse_ino_t dir)
879 {
880         if (ctx->ctx.pos == 0) {
881                 if (fuse_filldir(&ctx->ctx, ".", 1, ctx->ctx.pos,
882                                  dir, DT_DIR) < 0)
883                         return false;
884                 ctx->ctx.pos = 1;
885         }
886
887         if (ctx->ctx.pos == 1) {
888                 if (fuse_filldir(&ctx->ctx, "..", 2, ctx->ctx.pos,
889                                  /*TODO: parent*/ 1, DT_DIR) < 0)
890                         return false;
891                 ctx->ctx.pos = 2;
892         }
893
894         return true;
895 }
896
897 static void bcachefs_fuse_readdir(fuse_req_t req, fuse_ino_t dir_ino,
898                                   size_t size, off_t off,
899                                   struct fuse_file_info *fi)
900 {
901         subvol_inum dir = map_root_ino(dir_ino);
902         struct bch_fs *c = fuse_req_userdata(req);
903         struct bch_inode_unpacked bi;
904         char *buf = calloc(size, 1);
905         struct fuse_dir_context ctx = {
906                 .ctx.actor      = fuse_filldir,
907                 .ctx.pos        = off,
908                 .req            = req,
909                 .buf            = buf,
910                 .bufsize        = size,
911         };
912         int ret = 0;
913
914         fuse_log(FUSE_LOG_DEBUG, "bcachefs_fuse_readdir(dir=%llu, size=%zu, "
915                  "off=%lld)\n", dir.inum, size, off);
916
917         ret = bch2_inode_find_by_inum(c, dir, &bi);
918         if (ret)
919                 goto reply;
920
921         if (!S_ISDIR(bi.bi_mode)) {
922                 ret = -ENOTDIR;
923                 goto reply;
924         }
925
926         if (!handle_dots(&ctx, dir.inum))
927                 goto reply;
928
929         ret = bch2_readdir(c, dir, &ctx.ctx);
930 reply:
931         if (!ret) {
932                 fuse_log(FUSE_LOG_DEBUG, "bcachefs_fuse_readdir reply %zd\n",
933                                         ctx.buf - buf);
934                 fuse_reply_buf(req, buf, ctx.buf - buf);
935         } else {
936                 fuse_reply_err(req, -ret);
937         }
938
939         free(buf);
940 }
941
942 #if 0
943 static void bcachefs_fuse_readdirplus(fuse_req_t req, fuse_ino_t dir,
944                                       size_t size, off_t off,
945                                       struct fuse_file_info *fi)
946 {
947
948 }
949
950 static void bcachefs_fuse_releasedir(fuse_req_t req, fuse_ino_t inum,
951                                      struct fuse_file_info *fi)
952 {
953         struct bch_fs *c = fuse_req_userdata(req);
954 }
955
956 static void bcachefs_fuse_fsyncdir(fuse_req_t req, fuse_ino_t inum, int datasync,
957                                    struct fuse_file_info *fi)
958 {
959         struct bch_fs *c = fuse_req_userdata(req);
960 }
961 #endif
962
963 static void bcachefs_fuse_statfs(fuse_req_t req, fuse_ino_t inum)
964 {
965         struct bch_fs *c = fuse_req_userdata(req);
966         struct bch_fs_usage_short usage = bch2_fs_usage_read_short(c);
967         unsigned shift = c->block_bits;
968         struct statvfs statbuf = {
969                 .f_bsize        = block_bytes(c),
970                 .f_frsize       = block_bytes(c),
971                 .f_blocks       = usage.capacity >> shift,
972                 .f_bfree        = (usage.capacity - usage.used) >> shift,
973                 //.f_bavail     = statbuf.f_bfree,
974                 .f_files        = usage.nr_inodes,
975                 .f_ffree        = U64_MAX,
976                 .f_namemax      = BCH_NAME_MAX,
977         };
978
979         fuse_reply_statfs(req, &statbuf);
980 }
981
982 #if 0
983 static void bcachefs_fuse_setxattr(fuse_req_t req, fuse_ino_t inum,
984                                    const char *name, const char *value,
985                                    size_t size, int flags)
986 {
987         struct bch_fs *c = fuse_req_userdata(req);
988 }
989
990 static void bcachefs_fuse_getxattr(fuse_req_t req, fuse_ino_t inum,
991                                    const char *name, size_t size)
992 {
993         struct bch_fs *c = fuse_req_userdata(req);
994
995         fuse_reply_xattr(req, );
996 }
997
998 static void bcachefs_fuse_listxattr(fuse_req_t req, fuse_ino_t inum, size_t size)
999 {
1000         struct bch_fs *c = fuse_req_userdata(req);
1001 }
1002
1003 static void bcachefs_fuse_removexattr(fuse_req_t req, fuse_ino_t inum,
1004                                       const char *name)
1005 {
1006         struct bch_fs *c = fuse_req_userdata(req);
1007 }
1008 #endif
1009
1010 static void bcachefs_fuse_create(fuse_req_t req, fuse_ino_t dir_ino,
1011                                  const char *name, mode_t mode,
1012                                  struct fuse_file_info *fi)
1013 {
1014         subvol_inum dir = map_root_ino(dir_ino);
1015         struct bch_fs *c = fuse_req_userdata(req);
1016         struct bch_inode_unpacked new_inode;
1017         int ret;
1018
1019         fuse_log(FUSE_LOG_DEBUG, "bcachefs_fuse_create(%llu, %s, %x)\n",
1020                  dir.inum, name, mode);
1021
1022         ret = do_create(c, dir, name, mode, 0, &new_inode);
1023         if (ret)
1024                 goto err;
1025
1026         struct fuse_entry_param e = inode_to_entry(c, &new_inode);
1027         fuse_reply_create(req, &e, fi);
1028         return;
1029 err:
1030         fuse_reply_err(req, -ret);
1031 }
1032
1033 #if 0
1034 static void bcachefs_fuse_write_buf(fuse_req_t req, fuse_ino_t inum,
1035                                     struct fuse_bufvec *bufv, off_t off,
1036                                     struct fuse_file_info *fi)
1037 {
1038         struct bch_fs *c = fuse_req_userdata(req);
1039 }
1040
1041 static void bcachefs_fuse_fallocate(fuse_req_t req, fuse_ino_t inum, int mode,
1042                                     off_t offset, off_t length,
1043                                     struct fuse_file_info *fi)
1044 {
1045         struct bch_fs *c = fuse_req_userdata(req);
1046 }
1047 #endif
1048
1049 static const struct fuse_lowlevel_ops bcachefs_fuse_ops = {
1050         .init           = bcachefs_fuse_init,
1051         .destroy        = bcachefs_fuse_destroy,
1052         .lookup         = bcachefs_fuse_lookup,
1053         .getattr        = bcachefs_fuse_getattr,
1054         .setattr        = bcachefs_fuse_setattr,
1055         .readlink       = bcachefs_fuse_readlink,
1056         .mknod          = bcachefs_fuse_mknod,
1057         .mkdir          = bcachefs_fuse_mkdir,
1058         .unlink         = bcachefs_fuse_unlink,
1059         .rmdir          = bcachefs_fuse_rmdir,
1060         .symlink        = bcachefs_fuse_symlink,
1061         .rename         = bcachefs_fuse_rename,
1062         .link           = bcachefs_fuse_link,
1063         .open           = bcachefs_fuse_open,
1064         .read           = bcachefs_fuse_read,
1065         .write          = bcachefs_fuse_write,
1066         //.flush        = bcachefs_fuse_flush,
1067         //.release      = bcachefs_fuse_release,
1068         //.fsync        = bcachefs_fuse_fsync,
1069         //.opendir      = bcachefs_fuse_opendir,
1070         .readdir        = bcachefs_fuse_readdir,
1071         //.readdirplus  = bcachefs_fuse_readdirplus,
1072         //.releasedir   = bcachefs_fuse_releasedir,
1073         //.fsyncdir     = bcachefs_fuse_fsyncdir,
1074         .statfs         = bcachefs_fuse_statfs,
1075         //.setxattr     = bcachefs_fuse_setxattr,
1076         //.getxattr     = bcachefs_fuse_getxattr,
1077         //.listxattr    = bcachefs_fuse_listxattr,
1078         //.removexattr  = bcachefs_fuse_removexattr,
1079         .create         = bcachefs_fuse_create,
1080
1081         /* posix locks: */
1082 #if 0
1083         .getlk          = bcachefs_fuse_getlk,
1084         .setlk          = bcachefs_fuse_setlk,
1085 #endif
1086         //.write_buf    = bcachefs_fuse_write_buf,
1087         //.fallocate    = bcachefs_fuse_fallocate,
1088
1089 };
1090
1091 /*
1092  * Setup and command parsing.
1093  */
1094
1095 struct bf_context {
1096         char            *devices_str;
1097         char            **devices;
1098         int             nr_devices;
1099 };
1100
1101 static void bf_context_free(struct bf_context *ctx)
1102 {
1103         int i;
1104
1105         free(ctx->devices_str);
1106         for (i = 0; i < ctx->nr_devices; ++i)
1107                 free(ctx->devices[i]);
1108         free(ctx->devices);
1109 }
1110
1111 static struct fuse_opt bf_opts[] = {
1112         FUSE_OPT_END
1113 };
1114
1115 /*
1116  * Fuse option parsing helper -- returning 0 means we consumed the argument, 1
1117  * means we did not.
1118  */
1119 static int bf_opt_proc(void *data, const char *arg, int key,
1120     struct fuse_args *outargs)
1121 {
1122         struct bf_context *ctx = data;
1123
1124         switch (key) {
1125         case FUSE_OPT_KEY_NONOPT:
1126                 /* Just extract the first non-option string. */
1127                 if (!ctx->devices_str) {
1128                         ctx->devices_str = strdup(arg);
1129                         return 0;
1130                 }
1131                 return 1;
1132         }
1133
1134         return 1;
1135 }
1136
1137 /*
1138  * dev1:dev2 -> [ dev1, dev2 ]
1139  * dev       -> [ dev ]
1140  */
1141 static void tokenize_devices(struct bf_context *ctx)
1142 {
1143         char *devices_str = strdup(ctx->devices_str);
1144         char *devices_tmp = devices_str;
1145         char **devices = NULL;
1146         int nr = 0;
1147         char *dev = NULL;
1148
1149         while ((dev = strsep(&devices_tmp, ":"))) {
1150                 if (strlen(dev) > 0) {
1151                         devices = realloc(devices, (nr + 1) * sizeof *devices);
1152                         devices[nr] = strdup(dev);
1153                         nr++;
1154                 }
1155         }
1156
1157         if (!devices) {
1158                 devices = malloc(sizeof *devices);
1159                 devices[0] = strdup(ctx->devices_str);
1160                 nr = 1;
1161         }
1162
1163         ctx->devices = devices;
1164         ctx->nr_devices = nr;
1165
1166         free(devices_str);
1167 }
1168
1169 static void usage(char *argv[])
1170 {
1171         printf("Usage: %s fusemount [options] <dev>[:dev2:...] <mountpoint>\n",
1172                argv[0]);
1173         printf("\n");
1174 }
1175
1176 int cmd_fusemount(int argc, char *argv[])
1177 {
1178         struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
1179         struct bch_opts bch_opts = bch2_opts_empty();
1180         struct bf_context ctx = { 0 };
1181         struct bch_fs *c = NULL;
1182         int ret = 0, i;
1183
1184         /* Parse arguments. */
1185         if (fuse_opt_parse(&args, &ctx, bf_opts, bf_opt_proc) < 0)
1186                 die("fuse_opt_parse err: %m");
1187
1188         struct fuse_cmdline_opts fuse_opts;
1189         if (fuse_parse_cmdline(&args, &fuse_opts) < 0)
1190                 die("fuse_parse_cmdline err: %m");
1191
1192         if (fuse_opts.show_help) {
1193                 usage(argv);
1194                 fuse_cmdline_help();
1195                 fuse_lowlevel_help();
1196                 ret = 0;
1197                 goto out;
1198         }
1199         if (fuse_opts.show_version) {
1200                 /* TODO: Show bcachefs version. */
1201                 printf("FUSE library version %s\n", fuse_pkgversion());
1202                 fuse_lowlevel_version();
1203                 ret = 0;
1204                 goto out;
1205         }
1206         if (!fuse_opts.mountpoint) {
1207                 usage(argv);
1208                 printf("Please supply a mountpoint.\n");
1209                 ret = 1;
1210                 goto out;
1211         }
1212         if (!ctx.devices_str) {
1213                 usage(argv);
1214                 printf("Please specify a device or device1:device2:...\n");
1215                 ret = 1;
1216                 goto out;
1217         }
1218         tokenize_devices(&ctx);
1219
1220         /* Open bch */
1221         printf("Opening bcachefs filesystem on:\n");
1222         for (i = 0; i < ctx.nr_devices; ++i)
1223                 printf("\t%s\n", ctx.devices[i]);
1224
1225         c = bch2_fs_open(ctx.devices, ctx.nr_devices, bch_opts);
1226         if (IS_ERR(c))
1227                 die("error opening %s: %s", ctx.devices_str,
1228                     bch2_err_str(PTR_ERR(c)));
1229
1230         /* Fuse */
1231         struct fuse_session *se =
1232                 fuse_session_new(&args, &bcachefs_fuse_ops,
1233                                  sizeof(bcachefs_fuse_ops), c);
1234         if (!se)
1235                 die("fuse_lowlevel_new err: %m");
1236
1237         if (fuse_set_signal_handlers(se) < 0)
1238                 die("fuse_set_signal_handlers err: %m");
1239
1240         if (fuse_session_mount(se, fuse_opts.mountpoint))
1241                 die("fuse_mount err: %m");
1242
1243         /* This print statement is a trigger for tests. */
1244         printf("Fuse mount initialized.\n");
1245
1246         fuse_daemonize(fuse_opts.foreground);
1247
1248         ret = fuse_session_loop(se);
1249
1250         /* Cleanup */
1251         fuse_session_unmount(se);
1252         fuse_remove_signal_handlers(se);
1253         fuse_session_destroy(se);
1254
1255 out:
1256         free(fuse_opts.mountpoint);
1257         fuse_opt_free_args(&args);
1258         bf_context_free(&ctx);
1259
1260         return ret ? 1 : 0;
1261 }
1262
1263 #endif /* BCACHEFS_FUSE */