Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
J
jacobsa-fuse
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
jacobsa-fuse
Commits
4ee295e3
Commit
4ee295e3
authored
Nov 30, 2017
by
Srdjan Rilak
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add tests for hard link
parent
1b4a34cc
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
313 additions
and
20 deletions
+313
-20
fusetesting/parallel.go
fusetesting/parallel.go
+68
-0
samples/memfs/memfs.go
samples/memfs/memfs.go
+40
-0
samples/memfs/memfs_test.go
samples/memfs/memfs_test.go
+201
-20
samples/memfs/posix_test.go
samples/memfs/posix_test.go
+4
-0
No files found.
fusetesting/parallel.go
View file @
4ee295e3
...
...
@@ -365,3 +365,71 @@ func RunSymlinkInParallelTest(
AssertEq
(
nil
,
err
)
}
}
// Run an ogletest test that checks expectations for parallel calls to
// link(2).
func
RunHardlinkInParallelTest
(
ctx
context
.
Context
,
dir
string
)
{
// Ensure that we get parallelism for this test.
defer
runtime
.
GOMAXPROCS
(
runtime
.
GOMAXPROCS
(
runtime
.
NumCPU
()))
// Create a file.
originalFile
:=
path
.
Join
(
dir
,
"original_file"
)
const
contents
=
"Hello
\x00
world"
err
:=
ioutil
.
WriteFile
(
originalFile
,
[]
byte
(
contents
),
0444
)
AssertEq
(
nil
,
err
)
// Try for awhile to see if anything breaks.
const
duration
=
500
*
time
.
Millisecond
startTime
:=
time
.
Now
()
for
time
.
Since
(
startTime
)
<
duration
{
filename
:=
path
.
Join
(
dir
,
"foo"
)
// Set up a function that creates the symlink, ignoring EEXIST errors.
worker
:=
func
(
id
byte
)
(
err
error
)
{
err
=
os
.
Link
(
originalFile
,
filename
)
if
os
.
IsExist
(
err
)
{
err
=
nil
}
if
err
!=
nil
{
err
=
fmt
.
Errorf
(
"Worker %d: Link: %v"
,
id
,
err
)
return
}
return
}
// Run several workers in parallel.
const
numWorkers
=
16
b
:=
syncutil
.
NewBundle
(
ctx
)
for
i
:=
0
;
i
<
numWorkers
;
i
++
{
id
:=
byte
(
i
)
b
.
Add
(
func
(
ctx
context
.
Context
)
(
err
error
)
{
err
=
worker
(
id
)
return
})
}
err
:=
b
.
Join
()
AssertEq
(
nil
,
err
)
// The symlink should have been created, once.
entries
,
err
:=
ReadDirPicky
(
dir
)
AssertEq
(
nil
,
err
)
AssertEq
(
2
,
len
(
entries
))
AssertEq
(
"foo"
,
entries
[
0
]
.
Name
())
AssertEq
(
"original_file"
,
entries
[
1
]
.
Name
())
// Remove the link.
err
=
os
.
Remove
(
filename
)
AssertEq
(
nil
,
err
)
}
// Clean up the original file at the end.
err
=
os
.
Remove
(
originalFile
)
AssertEq
(
nil
,
err
)
}
samples/memfs/memfs.go
View file @
4ee295e3
...
...
@@ -424,6 +424,46 @@ func (fs *memFS) CreateSymlink(
return
}
func
(
fs
*
memFS
)
CreateLink
(
ctx
context
.
Context
,
op
*
fuseops
.
CreateLinkOp
)
(
err
error
)
{
fs
.
mu
.
Lock
()
defer
fs
.
mu
.
Unlock
()
// Grab the parent, which we will update shortly.
parent
:=
fs
.
getInodeOrDie
(
op
.
Parent
)
// Ensure that the name doesn't already exist, so we don't wind up with a
// duplicate.
_
,
_
,
exists
:=
parent
.
LookUpChild
(
op
.
Name
)
if
exists
{
err
=
fuse
.
EEXIST
return
}
// Get the target inode to be linked
target
:=
fs
.
getInodeOrDie
(
op
.
Target
)
// Update the attributes
now
:=
time
.
Now
()
target
.
attrs
.
Nlink
++
target
.
attrs
.
Ctime
=
now
// Add an entry in the parent.
parent
.
AddChild
(
op
.
Target
,
op
.
Name
,
fuseutil
.
DT_File
)
// Return the response.
op
.
Entry
.
Child
=
op
.
Target
op
.
Entry
.
Attributes
=
target
.
attrs
// We don't spontaneously mutate, so the kernel can cache as long as it wants
// (since it also handles invalidation).
op
.
Entry
.
AttributesExpiration
=
time
.
Now
()
.
Add
(
365
*
24
*
time
.
Hour
)
op
.
Entry
.
EntryExpiration
=
op
.
Entry
.
EntryExpiration
return
}
func
(
fs
*
memFS
)
Rename
(
ctx
context
.
Context
,
op
*
fuseops
.
RenameOp
)
(
err
error
)
{
...
...
samples/memfs/memfs_test.go
View file @
4ee295e3
...
...
@@ -21,6 +21,7 @@ import (
"os"
"os/user"
"path"
"reflect"
"runtime"
"strconv"
"syscall"
...
...
@@ -1088,26 +1089,6 @@ func (t *MemFSTest) ReadDirWhileModifying() {
ExpectTrue
(
namesSeen
[
"qux"
])
}
func
(
t
*
MemFSTest
)
HardLinks
()
{
var
err
error
// Create a file and a directory.
fileName
:=
path
.
Join
(
t
.
Dir
,
"foo"
)
err
=
ioutil
.
WriteFile
(
fileName
,
[]
byte
{},
0400
)
AssertEq
(
nil
,
err
)
dirName
:=
path
.
Join
(
t
.
Dir
,
"bar"
)
err
=
os
.
Mkdir
(
dirName
,
0700
)
AssertEq
(
nil
,
err
)
// Attempt to link each. Neither should work, but for different reasons.
err
=
os
.
Link
(
fileName
,
path
.
Join
(
t
.
Dir
,
"baz"
))
ExpectThat
(
err
,
Error
(
HasSubstr
(
"not implemented"
)))
err
=
os
.
Link
(
dirName
,
path
.
Join
(
t
.
Dir
,
"baz"
))
ExpectThat
(
err
,
Error
(
HasSubstr
(
"not permitted"
)))
}
func
(
t
*
MemFSTest
)
CreateSymlink
()
{
var
fi
os
.
FileInfo
var
err
error
...
...
@@ -1225,6 +1206,202 @@ func (t *MemFSTest) DeleteSymlink() {
ExpectThat
(
entries
,
ElementsAre
())
}
func
(
t
*
MemFSTest
)
CreateHardlink
()
{
var
fi
os
.
FileInfo
var
err
error
// Create a file.
fileName
:=
path
.
Join
(
t
.
Dir
,
"regular_file"
)
const
contents
=
"Hello
\x00
world"
err
=
ioutil
.
WriteFile
(
fileName
,
[]
byte
(
contents
),
0444
)
AssertEq
(
nil
,
err
)
// Clean up the file at the end.
defer
func
()
{
err
:=
os
.
Remove
(
fileName
)
AssertEq
(
nil
,
err
)
}()
// Create a link to the file.
linkName
:=
path
.
Join
(
t
.
Dir
,
"foo"
)
err
=
os
.
Link
(
fileName
,
linkName
)
AssertEq
(
nil
,
err
)
// Clean up the file at the end.
defer
func
()
{
err
:=
os
.
Remove
(
linkName
)
AssertEq
(
nil
,
err
)
}()
// Stat the link.
fi
,
err
=
os
.
Lstat
(
linkName
)
AssertEq
(
nil
,
err
)
ExpectEq
(
"foo"
,
fi
.
Name
())
ExpectEq
(
0444
,
fi
.
Mode
())
// Read the parent directory.
entries
,
err
:=
fusetesting
.
ReadDirPicky
(
t
.
Dir
)
AssertEq
(
nil
,
err
)
AssertEq
(
2
,
len
(
entries
))
fi
=
entries
[
0
]
ExpectEq
(
"foo"
,
fi
.
Name
())
ExpectEq
(
0444
,
fi
.
Mode
())
fi
=
entries
[
1
]
ExpectEq
(
"regular_file"
,
fi
.
Name
())
ExpectEq
(
0444
,
fi
.
Mode
())
}
func
(
t
*
MemFSTest
)
CreateHardlink_AlreadyExists
()
{
var
err
error
// Create a file and a directory.
fileName
:=
path
.
Join
(
t
.
Dir
,
"foo"
)
err
=
ioutil
.
WriteFile
(
fileName
,
[]
byte
{},
0400
)
AssertEq
(
nil
,
err
)
dirName
:=
path
.
Join
(
t
.
Dir
,
"bar"
)
err
=
os
.
Mkdir
(
dirName
,
0700
)
AssertEq
(
nil
,
err
)
// Create an existing symlink.
symlinkName
:=
path
.
Join
(
t
.
Dir
,
"baz"
)
err
=
os
.
Symlink
(
"blah"
,
symlinkName
)
AssertEq
(
nil
,
err
)
// Create another link to the file.
hardlinkName
:=
path
.
Join
(
t
.
Dir
,
"qux"
)
err
=
os
.
Link
(
fileName
,
hardlinkName
)
AssertEq
(
nil
,
err
)
// Symlinking on top of any of them should fail.
names
:=
[]
string
{
fileName
,
dirName
,
symlinkName
,
hardlinkName
,
}
for
_
,
n
:=
range
names
{
err
=
os
.
Link
(
fileName
,
n
)
ExpectThat
(
err
,
Error
(
HasSubstr
(
"exists"
)))
}
}
func
(
t
*
MemFSTest
)
DeleteHardlink
()
{
var
fi
os
.
FileInfo
var
err
error
// Create a file.
fileName
:=
path
.
Join
(
t
.
Dir
,
"regular_file"
)
const
contents
=
"Hello
\x00
world"
err
=
ioutil
.
WriteFile
(
fileName
,
[]
byte
(
contents
),
0444
)
AssertEq
(
nil
,
err
)
// Step #1: We will create and remove a link and verify that
// after removal everything is as expected.
// Create a link to the file.
linkName
:=
path
.
Join
(
t
.
Dir
,
"foo"
)
err
=
os
.
Link
(
fileName
,
linkName
)
AssertEq
(
nil
,
err
)
// Remove the link.
err
=
os
.
Remove
(
linkName
)
AssertEq
(
nil
,
err
)
// Stat the link.
fi
,
err
=
os
.
Lstat
(
linkName
)
AssertEq
(
nil
,
fi
)
ExpectThat
(
err
,
Error
(
HasSubstr
(
"no such file"
)))
// Read the parent directory.
entries
,
err
:=
fusetesting
.
ReadDirPicky
(
t
.
Dir
)
AssertEq
(
nil
,
err
)
AssertEq
(
1
,
len
(
entries
))
fi
=
entries
[
0
]
ExpectEq
(
"regular_file"
,
fi
.
Name
())
ExpectEq
(
0444
,
fi
.
Mode
())
// Step #2: We will create a link and remove the original file subsequently
// and verify that after removal everything is as expected.
// Create a link to the file.
linkName
=
path
.
Join
(
t
.
Dir
,
"bar"
)
err
=
os
.
Link
(
fileName
,
linkName
)
AssertEq
(
nil
,
err
)
// Remove the original file.
err
=
os
.
Remove
(
fileName
)
AssertEq
(
nil
,
err
)
// Stat the link.
fi
,
err
=
os
.
Lstat
(
linkName
)
AssertEq
(
nil
,
err
)
ExpectEq
(
"bar"
,
fi
.
Name
())
ExpectEq
(
0444
,
fi
.
Mode
())
// Stat the original file.
fi
,
err
=
os
.
Lstat
(
fileName
)
AssertEq
(
nil
,
fi
)
ExpectThat
(
err
,
Error
(
HasSubstr
(
"no such file"
)))
// Read the parent directory.
entries
,
err
=
fusetesting
.
ReadDirPicky
(
t
.
Dir
)
AssertEq
(
nil
,
err
)
AssertEq
(
1
,
len
(
entries
))
fi
=
entries
[
0
]
ExpectEq
(
"bar"
,
fi
.
Name
())
ExpectEq
(
0444
,
fi
.
Mode
())
// Cleanup.
err
=
os
.
Remove
(
linkName
)
AssertEq
(
nil
,
err
)
}
func
(
t
*
MemFSTest
)
ReadHardlink
()
{
var
err
error
// Create a file.
fileName
:=
path
.
Join
(
t
.
Dir
,
"regular_file"
)
const
contents
=
"Hello
\x00
world"
err
=
ioutil
.
WriteFile
(
fileName
,
[]
byte
(
contents
),
0444
)
AssertEq
(
nil
,
err
)
// Clean up the file at the end.
defer
func
()
{
err
:=
os
.
Remove
(
fileName
)
AssertEq
(
nil
,
err
)
}()
// Create a link to the file.
linkName
:=
path
.
Join
(
t
.
Dir
,
"foo"
)
err
=
os
.
Link
(
fileName
,
linkName
)
AssertEq
(
nil
,
err
)
// Clean up the file at the end.
defer
func
()
{
err
:=
os
.
Remove
(
linkName
)
AssertEq
(
nil
,
err
)
}()
// Read files.
original
,
err
:=
ioutil
.
ReadFile
(
fileName
)
AssertEq
(
nil
,
err
)
linked
,
err
:=
ioutil
.
ReadFile
(
linkName
)
AssertEq
(
nil
,
err
)
// Check if the bytes are the same.
AssertEq
(
true
,
reflect
.
DeepEqual
(
original
,
linked
))
}
func
(
t
*
MemFSTest
)
CreateInParallel_NoTruncate
()
{
fusetesting
.
RunCreateInParallelTest_NoTruncate
(
t
.
Ctx
,
t
.
Dir
)
}
...
...
@@ -1245,6 +1422,10 @@ func (t *MemFSTest) SymlinkInParallel() {
fusetesting
.
RunSymlinkInParallelTest
(
t
.
Ctx
,
t
.
Dir
)
}
func
(
t
*
MemFSTest
)
HardlinkInParallel
()
{
fusetesting
.
RunHardlinkInParallelTest
(
t
.
Ctx
,
t
.
Dir
)
}
func
(
t
*
MemFSTest
)
RenameWithinDir_File
()
{
var
err
error
...
...
samples/memfs/posix_test.go
View file @
4ee295e3
...
...
@@ -445,3 +445,7 @@ func (t *PosixTest) MkdirInParallel() {
func
(
t
*
PosixTest
)
SymlinkInParallel
()
{
fusetesting
.
RunSymlinkInParallelTest
(
t
.
ctx
,
t
.
dir
)
}
func
(
t
*
PosixTest
)
HardlinkInParallel
()
{
fusetesting
.
RunHardlinkInParallelTest
(
t
.
ctx
,
t
.
dir
)
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment