- Fix mount point property race condition causing segmentation fault failures
This commit is contained in:
		
							parent
							
								
									4dcea86954
								
							
						
					
					
						commit
						7c7ef79611
					
				| 
						 | 
				
			
			@ -22,6 +22,9 @@ func Test(t *testing.T) {
 | 
			
		|||
 | 
			
		||||
	zfsTestDatasetCreate(t)
 | 
			
		||||
	zfsTestDatasetOpen(t)
 | 
			
		||||
	// zfsTestMountPointConcurrency(t)
 | 
			
		||||
	// time.Sleep(15 * time.Second)
 | 
			
		||||
 | 
			
		||||
	zfsTestDatasetSnapshot(t)
 | 
			
		||||
	zfsTestDatasetOpenAll(t)
 | 
			
		||||
	zfsTestDatasetSetProperty(t)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										34
									
								
								zfs.go
								
								
								
								
							
							
						
						
									
										34
									
								
								zfs.go
								
								
								
								
							| 
						 | 
				
			
			@ -125,13 +125,12 @@ func DatasetOpenSingle(path string) (d Dataset, err error) {
 | 
			
		|||
	if d.list == nil || d.list.zh == nil {
 | 
			
		||||
		err = LastError()
 | 
			
		||||
		if err == nil {
 | 
			
		||||
			err = fmt.Errorf("dataset not found.")
 | 
			
		||||
			err = fmt.Errorf("dataset not found")
 | 
			
		||||
		}
 | 
			
		||||
		err = fmt.Errorf("%s - %s", err.Error(), path)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	d.Type = DatasetType(C.dataset_type(d.list))
 | 
			
		||||
	d.Properties = make(map[Prop]Property)
 | 
			
		||||
	err = d.ReloadProperties()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
| 
						 | 
				
			
			@ -317,11 +316,17 @@ func (d *Dataset) ReloadProperties() (err error) {
 | 
			
		|||
		return
 | 
			
		||||
	}
 | 
			
		||||
	d.Properties = make(map[Prop]Property)
 | 
			
		||||
	Global.Mtx.Lock()
 | 
			
		||||
	defer Global.Mtx.Unlock()
 | 
			
		||||
	C.zfs_refresh_properties(d.list.zh)
 | 
			
		||||
	for prop := DatasetPropType; prop < DatasetNumProps; prop++ {
 | 
			
		||||
		plist := C.read_dataset_property(d.list, C.int(prop))
 | 
			
		||||
		var plist *C.property_list_t
 | 
			
		||||
		if prop == DatasetPropMounted || prop == DatasetPropMountpoint {
 | 
			
		||||
			// prevent zfs mountpoint race conditions
 | 
			
		||||
			Global.Mtx.Lock()
 | 
			
		||||
			plist = C.read_dataset_property(d.list, C.int(prop))
 | 
			
		||||
			Global.Mtx.Unlock()
 | 
			
		||||
		} else {
 | 
			
		||||
			plist = C.read_dataset_property(d.list, C.int(prop))
 | 
			
		||||
		}
 | 
			
		||||
		if plist == nil {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -339,8 +344,11 @@ func (d *Dataset) GetProperty(p Prop) (prop Property, err error) {
 | 
			
		|||
		err = errors.New(msgDatasetIsNil)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	Global.Mtx.Lock()
 | 
			
		||||
	defer Global.Mtx.Unlock()
 | 
			
		||||
	if p == DatasetPropMounted || p == DatasetPropMountpoint {
 | 
			
		||||
		// prevent zfs mountpoint race conditions
 | 
			
		||||
		Global.Mtx.Lock()
 | 
			
		||||
		defer Global.Mtx.Unlock()
 | 
			
		||||
	}
 | 
			
		||||
	plist := C.read_dataset_property(d.list, C.int(p))
 | 
			
		||||
	if plist == nil {
 | 
			
		||||
		err = LastError()
 | 
			
		||||
| 
						 | 
				
			
			@ -381,6 +389,11 @@ func (d *Dataset) SetProperty(p Prop, value string) (err error) {
 | 
			
		|||
		return
 | 
			
		||||
	}
 | 
			
		||||
	csValue := C.CString(value)
 | 
			
		||||
	if p == DatasetPropMounted || p == DatasetPropMountpoint {
 | 
			
		||||
		// prevent zfs mountpoint race conditions
 | 
			
		||||
		Global.Mtx.Lock()
 | 
			
		||||
		defer Global.Mtx.Unlock()
 | 
			
		||||
	}
 | 
			
		||||
	errcode := C.dataset_prop_set(d.list, C.zfs_prop_t(p), csValue)
 | 
			
		||||
	C.free(unsafe.Pointer(csValue))
 | 
			
		||||
	if errcode != 0 {
 | 
			
		||||
| 
						 | 
				
			
			@ -388,9 +401,14 @@ func (d *Dataset) SetProperty(p Prop, value string) (err error) {
 | 
			
		|||
		return
 | 
			
		||||
	}
 | 
			
		||||
	// Update Properties member with change made
 | 
			
		||||
	if _, err = d.GetProperty(p); err != nil {
 | 
			
		||||
	plist := C.read_dataset_property(d.list, C.int(p))
 | 
			
		||||
	if plist == nil {
 | 
			
		||||
		err = LastError()
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	defer C.free_properties(plist)
 | 
			
		||||
	d.Properties[p] = Property{Value: C.GoString(&(*plist).value[0]),
 | 
			
		||||
		Source: C.GoString(&(*plist).source[0])}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										34
									
								
								zfs_test.go
								
								
								
								
							
							
						
						
									
										34
									
								
								zfs_test.go
								
								
								
								
							| 
						 | 
				
			
			@ -4,7 +4,7 @@ import (
 | 
			
		|||
	"fmt"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/bicomsystems/go-libzfs"
 | 
			
		||||
	zfs "github.com/bicomsystems/go-libzfs"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
/* ------------------------------------------------------------------------- */
 | 
			
		||||
| 
						 | 
				
			
			@ -203,6 +203,38 @@ func zfsTestDatasetDestroy(t *testing.T) {
 | 
			
		|||
	print("PASS\n\n")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func zfsTestMountPointConcurrency(t *testing.T) {
 | 
			
		||||
	println("TEST DATASET MountPointConcurrency( ", TSTDatasetPath, " ) ... ")
 | 
			
		||||
	d, err := zfs.DatasetOpen(TSTDatasetPath)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Error(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	defer d.Close()
 | 
			
		||||
	gr1 := make(chan bool)
 | 
			
		||||
	gr2 := make(chan bool)
 | 
			
		||||
	go func() {
 | 
			
		||||
		for i := 0; i < 30; i++ {
 | 
			
		||||
			println("reload properties:", i)
 | 
			
		||||
			// d.SetProperty(zfs.DatasetPropMountpoint, "/TEST")
 | 
			
		||||
			d.ReloadProperties()
 | 
			
		||||
		}
 | 
			
		||||
		gr1 <- true
 | 
			
		||||
	}()
 | 
			
		||||
	go func() {
 | 
			
		||||
		for i := 0; i < 100; i++ {
 | 
			
		||||
			println("set mountpoint:", i)
 | 
			
		||||
			d.SetProperty(zfs.DatasetPropMountpoint, "/TEST")
 | 
			
		||||
			// d.GetProperty(zfs.DatasetPropMountpoint)
 | 
			
		||||
		}
 | 
			
		||||
		gr2 <- true
 | 
			
		||||
	}()
 | 
			
		||||
	d.SetProperty(zfs.DatasetPropMountpoint, "none")
 | 
			
		||||
 | 
			
		||||
	<-gr1
 | 
			
		||||
	<-gr2
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* ------------------------------------------------------------------------- */
 | 
			
		||||
// EXAMPLES:
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue