Commit f520193c authored by Kirill Smelkov's avatar Kirill Smelkov Committed by Han-Wen Nienhuys

nodefs: Fix FileNotifyStoreCache to return ENOENT when inode is not known to kernel

nodeMap.Handle(&node) == 0 means the kernel does not currently have an
entry for this node in its dentry cache. And the kernel would return
ENOENT if we would try to send it notify store message with nodeID it
does not currently know.

So return proper ENOENT when we see that currently there is no handle
for the inode, instead of returning EINVAL, which means that call
arguments - e.g. off is invalid.

NOTE contrary to cache retrieve (where we could turn such error into empty OK
read; see previous patch) for cache store we cannot ignore the error.

Fixes bdca0e6a (Add support for store notify).
See also: https://github.com/hanwen/go-fuse/pull/246#discussion_r242050595
parent 9d9c4ddf
......@@ -393,6 +393,9 @@ func (c *FileSystemConnector) FileNotify(node *Inode, off int64, length int64) f
// and will use data from that cache for non direct-IO reads from the inode
// in corresponding data region. After kernel's cache data is evicted, the kernel
// will have to issue new Read calls on user request to get data content.
//
// ENOENT is returned if the kernel does not currently have entry for this
// inode in its dentry cache.
func (c *FileSystemConnector) FileNotifyStoreCache(node *Inode, off int64, data []byte) fuse.Status {
var nID uint64
if node == c.rootNode {
......@@ -402,7 +405,8 @@ func (c *FileSystemConnector) FileNotifyStoreCache(node *Inode, off int64, data
}
if nID == 0 {
return fuse.EINVAL
// the kernel does not currently know about this inode.
return fuse.ENOENT
}
return c.server.InodeNotifyStoreCache(nID, off, data)
}
......
......@@ -565,6 +565,9 @@ func (ms *Server) inodeNotifyStoreCache32(node uint64, offset int64, data []byte
// [offset:offset+len(dest)) and waits for corresponding reply. If kernel cache
// has fewer consecutive data starting at offset, that fewer amount is returned.
// In particular if inode data at offset is not cached (0, OK) is returned.
//
// The kernel returns ENOENT if it does not currently have entry for this inode
// in its dentry cache.
func (ms *Server) InodeRetrieveCache(node uint64, offset int64, dest []byte) (n int, st Status) {
if !ms.kernelSettings.SupportsNotify(NOTIFY_RETRIEVE_CACHE) {
return 0, ENOSYS
......
......@@ -122,8 +122,12 @@ func TestCacheControl(t *testing.T) {
}
// before the kernel has entry for file in its dentry cache, the cache
// should read as empty.
// should read as empty and cache store should fail with ENOENT.
assertCacheRead("before lookup", "")
st := fsconn.FileNotifyStoreCache(file.Inode(), 0, []byte("abc"))
if st != fuse.ENOENT {
t.Fatalf("%s: store cache -> %v; want %v", "before lookup", st, fuse.ENOENT)
}
// lookup on the file - forces to assign inode ID to it
os.Stat(dir + "/hello.txt")
......@@ -171,7 +175,7 @@ func TestCacheControl(t *testing.T) {
assertCacheRead("original", data0)
// store changed data into OS cache
st := fsconn.FileNotifyStoreCache(file.Inode(), 7, []byte("123"))
st = fsconn.FileNotifyStoreCache(file.Inode(), 7, []byte("123"))
if st != fuse.OK {
t.Fatalf("store cache: %s", st)
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment