From 3db12b229437b25b099c3ae2f82a6bbb0678a445 Mon Sep 17 00:00:00 2001 From: Denys Smirnov Date: Wed, 11 Jan 2017 18:53:23 +0200 Subject: [PATCH] expose resize --- btrfs.go | 20 ++++++++++++++++ btrfs_test.go | 60 +++++++++++++++++++++++++++++++++++++++++++++++ ioctl_h.go | 9 +++++-- test/btrfstest.go | 28 +++++++++++++--------- 4 files changed, 104 insertions(+), 13 deletions(-) diff --git a/btrfs.go b/btrfs.go index 63e1d87..fc2a483 100644 --- a/btrfs.go +++ b/btrfs.go @@ -6,6 +6,7 @@ import ( "io" "os" "path/filepath" + "strconv" "syscall" ) @@ -242,3 +243,22 @@ func (f *FS) Balance(flags BalanceFlags) (BalanceProgress, error) { err := iocBalanceV2(f.f, &args) return args.stat, err } + +func (f *FS) Resize(size int64) error { + amount := strconv.FormatInt(size, 10) + args := &btrfs_ioctl_vol_args{} + args.SetName(amount) + if err := iocResize(f.f, args); err != nil { + return fmt.Errorf("resize failed: %v", err) + } + return nil +} + +func (f *FS) ResizeToMax() error { + args := &btrfs_ioctl_vol_args{} + args.SetName("max") + if err := iocResize(f.f, args); err != nil { + return fmt.Errorf("resize failed: %v", err) + } + return nil +} diff --git a/btrfs_test.go b/btrfs_test.go index 9e457ca..f31b9c4 100644 --- a/btrfs_test.go +++ b/btrfs_test.go @@ -3,6 +3,7 @@ package btrfs import ( "github.com/dennwc/btrfs/test" "io" + "io/ioutil" "os" "path/filepath" "reflect" @@ -215,3 +216,62 @@ func TestCloneFile(t *testing.T) { t.Fatalf("wrong data returned: %q", string(buf)) } } + +func TestResize(t *testing.T) { + dir, err := ioutil.TempDir("", "btrfs_data_") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + fname := filepath.Join(dir, "data") + if err = btrfstest.Mkfs(fname, sizeDef); err != nil { + t.Fatal(err) + } + mnt := filepath.Join(dir, "mnt") + if err = os.MkdirAll(mnt, 0755); err != nil { + t.Fatal(err) + } + if err = btrfstest.Mount(mnt, fname); err != nil { + t.Fatal(err) + } + defer btrfstest.Unmount(mnt) + + fs, err := Open(mnt, false) + if err != nil { + t.Fatal(err) + } + st, err := fs.Usage() + fs.Close() + if err != nil { + t.Fatal(err) + } + + if err = btrfstest.Unmount(mnt); err != nil { + t.Fatal(err) + } + var newSize int64 = sizeDef + newSize = int64(float64(newSize) * 1.1) + if err = os.Truncate(fname, newSize); err != nil { + t.Fatal(err) + } + if err = btrfstest.Mount(mnt, fname); err != nil { + t.Fatal(err) + } + + fs, err = Open(mnt, false) + if err != nil { + t.Fatal(err) + } + defer fs.Close() + + if err = fs.ResizeToMax(); err != nil { + t.Fatal(err) + } + + st2, err := fs.Usage() + if err != nil { + t.Fatal(err) + } else if st.Total >= st2.Total { + t.Fatal("to resized:", st.Total, st2.Total) + } +} diff --git a/ioctl_h.go b/ioctl_h.go index d21d93a..a35a123 100644 --- a/ioctl_h.go +++ b/ioctl_h.go @@ -60,6 +60,11 @@ type btrfs_ioctl_vol_args struct { name [volNameMax + 1]byte } +func (arg *btrfs_ioctl_vol_args) SetName(name string) { + n := copy(arg.name[:], name) + arg.name[n] = 0 +} + type btrfs_qgroup_limit struct { flags uint64 max_referenced uint64 @@ -625,8 +630,8 @@ func iocDefrag(f *os.File, out *btrfs_ioctl_vol_args) error { return ioctl.Do(f, _BTRFS_IOC_DEFRAG, out) } -func iocResize(f *os.File, out *btrfs_ioctl_vol_args) error { - return ioctl.Do(f, _BTRFS_IOC_RESIZE, out) +func iocResize(f *os.File, in *btrfs_ioctl_vol_args) error { + return ioctl.Do(f, _BTRFS_IOC_RESIZE, in) } func iocScanDev(f *os.File, out *btrfs_ioctl_vol_args) error { diff --git a/test/btrfstest.go b/test/btrfstest.go index bb1cced..f85862d 100644 --- a/test/btrfstest.go +++ b/test/btrfstest.go @@ -52,6 +52,21 @@ func Mount(mount string, file string) error { return nil } +func Unmount(mount string) error { + for i := 0; i < 5; i++ { + if err := run("umount", mount); err == nil { + break + } else { + if strings.Contains(err.Error(), "busy") { + time.Sleep(time.Second) + } else { + break + } + } + } + return nil +} + func New(t testing.TB, size int64) (string, func()) { f, err := ioutil.TempFile("", "btrfs_vol") if err != nil { @@ -85,17 +100,8 @@ func New(t testing.TB, size int64) (string, func()) { if done { return } - for i := 0; i < 5; i++ { - if err := run("umount", mount); err == nil { - break - } else { - log.Println("umount failed:", err) - if strings.Contains(err.Error(), "busy") { - time.Sleep(time.Second) - } else { - break - } - } + if err := Unmount(mount); err != nil { + log.Println("umount failed:", err) } if err := os.Remove(mount); err != nil { log.Println("cleanup failed:", err)