aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--weed/mount/filehandle.go16
-rw-r--r--weed/mount/filehandle_map.go79
-rw-r--r--weed/mount/inode_to_path.go1
-rw-r--r--weed/mount/weedfs.go2
-rw-r--r--weed/mount/weedfs_file_io.go131
-rw-r--r--weed/mount/weedfs_file_read.go34
-rw-r--r--weed/mount/weedfs_file_sync.go70
-rw-r--r--weed/mount/weedfs_file_write.go35
8 files changed, 242 insertions, 126 deletions
diff --git a/weed/mount/filehandle.go b/weed/mount/filehandle.go
new file mode 100644
index 000000000..551394262
--- /dev/null
+++ b/weed/mount/filehandle.go
@@ -0,0 +1,16 @@
+package mount
+
+import "github.com/hanwen/go-fuse/v2/fuse"
+
+func (wfs *WFS) AcquireHandle(inode uint64, uid, gid uint32) (fileHandle *FileHandle, code fuse.Status) {
+ _, entry, status := wfs.maybeReadEntry(inode)
+ if status == fuse.OK {
+ fileHandle = wfs.fhmap.GetFileHandle(inode)
+ fileHandle.entry = entry
+ }
+ return
+}
+
+func (wfs *WFS) ReleaseHandle(handleId FileHandleId) {
+ wfs.fhmap.ReleaseByHandle(handleId)
+}
diff --git a/weed/mount/filehandle_map.go b/weed/mount/filehandle_map.go
new file mode 100644
index 000000000..ca010dabb
--- /dev/null
+++ b/weed/mount/filehandle_map.go
@@ -0,0 +1,79 @@
+package mount
+
+import (
+ "github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
+ "sync"
+)
+
+type FileHandleId uint64
+
+type FileHandleToInode struct {
+ sync.RWMutex
+ nextFh FileHandleId
+ inode2fh map[uint64]*FileHandle
+ fh2inode map[FileHandleId]uint64
+}
+type FileHandle struct {
+ fh FileHandleId
+ counter int64
+ entry *filer_pb.Entry
+ inode uint64
+}
+
+func NewFileHandleToInode() *FileHandleToInode {
+ return &FileHandleToInode{
+ inode2fh: make(map[uint64]*FileHandle),
+ fh2inode: make(map[FileHandleId]uint64),
+ nextFh: 0,
+ }
+}
+
+func (i *FileHandleToInode) GetFileHandle(inode uint64) *FileHandle {
+ i.Lock()
+ defer i.Unlock()
+ fh, found := i.inode2fh[inode]
+ if !found {
+ fh = &FileHandle{
+ fh: i.nextFh,
+ counter: 1,
+ inode: inode,
+ }
+ i.nextFh++
+ i.inode2fh[inode] = fh
+ i.fh2inode[fh.fh] = inode
+ } else {
+ fh.counter++
+ }
+ return fh
+}
+
+func (i *FileHandleToInode) ReleaseByInode(inode uint64) {
+ i.Lock()
+ defer i.Unlock()
+ fh, found := i.inode2fh[inode]
+ if found {
+ fh.counter--
+ if fh.counter <= 0 {
+ delete(i.inode2fh, inode)
+ delete(i.fh2inode, fh.fh)
+ }
+ }
+}
+func (i *FileHandleToInode) ReleaseByHandle(fh FileHandleId) {
+ i.Lock()
+ defer i.Unlock()
+ inode, found := i.fh2inode[fh]
+ if found {
+ fhHandle, fhFound := i.inode2fh[inode]
+ if !fhFound {
+ delete(i.fh2inode, fh)
+ } else {
+ fhHandle.counter--
+ if fhHandle.counter <= 0 {
+ delete(i.inode2fh, inode)
+ delete(i.fh2inode, fhHandle.fh)
+ }
+ }
+
+ }
+}
diff --git a/weed/mount/inode_to_path.go b/weed/mount/inode_to_path.go
index 529ecadda..590531397 100644
--- a/weed/mount/inode_to_path.go
+++ b/weed/mount/inode_to_path.go
@@ -37,7 +37,6 @@ func (i *InodeToPath) Lookup(path util.FullPath) uint64 {
i.nextInodeId++
i.path2inode[path] = inode
i.inode2path[inode] = &InodeEntry{path, 1}
- println("add", path, inode)
} else {
i.inode2path[inode].nlookup++
}
diff --git a/weed/mount/weedfs.go b/weed/mount/weedfs.go
index a36e4dc97..1e9f07df9 100644
--- a/weed/mount/weedfs.go
+++ b/weed/mount/weedfs.go
@@ -60,6 +60,7 @@ type WFS struct {
root Directory
signature int32
inodeToPath *InodeToPath
+ fhmap *FileHandleToInode
}
func NewSeaweedFileSystem(option *Option) *WFS {
@@ -68,6 +69,7 @@ func NewSeaweedFileSystem(option *Option) *WFS {
option: option,
signature: util.RandomInt32(),
inodeToPath: NewInodeToPath(),
+ fhmap: NewFileHandleToInode(),
}
wfs.root = Directory{
diff --git a/weed/mount/weedfs_file_io.go b/weed/mount/weedfs_file_io.go
index 0a31c3d70..7c8d1babc 100644
--- a/weed/mount/weedfs_file_io.go
+++ b/weed/mount/weedfs_file_io.go
@@ -5,65 +5,6 @@ import (
)
/**
- * Read data
- *
- * Read should send exactly the number of bytes requested except
- * on EOF or error, otherwise the rest of the data will be
- * substituted with zeroes. An exception to this is when the file
- * has been opened in 'direct_io' mode, in which case the return
- * value of the read system call will reflect the return value of
- * this operation.
- *
- * fi->fh will contain the value set by the open method, or will
- * be undefined if the open method didn't set any value.
- *
- * Valid replies:
- * fuse_reply_buf
- * fuse_reply_iov
- * fuse_reply_data
- * fuse_reply_err
- *
- * @param req request handle
- * @param ino the inode number
- * @param size number of bytes to read
- * @param off offset to read from
- * @param fi file information
- */
-func (wfs *WFS) Read(cancel <-chan struct{}, in *fuse.ReadIn, buf []byte) (fuse.ReadResult, fuse.Status) {
- return nil, fuse.ENOSYS
-}
-
-/**
- * Write data
- *
- * Write should return exactly the number of bytes requested
- * except on error. An exception to this is when the file has
- * been opened in 'direct_io' mode, in which case the return value
- * of the write system call will reflect the return value of this
- * operation.
- *
- * Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is
- * expected to reset the setuid and setgid bits.
- *
- * fi->fh will contain the value set by the open method, or will
- * be undefined if the open method didn't set any value.
- *
- * Valid replies:
- * fuse_reply_write
- * fuse_reply_err
- *
- * @param req request handle
- * @param ino the inode number
- * @param buf data to write
- * @param size number of bytes to write
- * @param off offset to write to
- * @param fi file information
- */
-func (wfs *WFS) Write(cancel <-chan struct{}, in *fuse.WriteIn, data []byte) (written uint32, code fuse.Status) {
- return 0, fuse.ENOSYS
-}
-
-/**
* Open a file
*
* Open flags are available in fi->flags. The following rules
@@ -120,49 +61,11 @@ func (wfs *WFS) Write(cancel <-chan struct{}, in *fuse.WriteIn, data []byte) (wr
* @param fi file information
*/
func (wfs *WFS) Open(cancel <-chan struct{}, in *fuse.OpenIn, out *fuse.OpenOut) (status fuse.Status) {
- return fuse.ENOSYS
-}
-
-/**
- * Flush method
- *
- * This is called on each close() of the opened file.
- *
- * Since file descriptors can be duplicated (dup, dup2, fork), for
- * one open call there may be many flush calls.
- *
- * Filesystems shouldn't assume that flush will always be called
- * after some writes, or that if will be called at all.
- *
- * fi->fh will contain the value set by the open method, or will
- * be undefined if the open method didn't set any value.
- *
- * NOTE: the name of the method is misleading, since (unlike
- * fsync) the filesystem is not forced to flush pending writes.
- * One reason to flush data is if the filesystem wants to return
- * write errors during close. However, such use is non-portable
- * because POSIX does not require [close] to wait for delayed I/O to
- * complete.
- *
- * If the filesystem supports file locking operations (setlk,
- * getlk) it should remove all locks belonging to 'fi->owner'.
- *
- * If this request is answered with an error code of ENOSYS,
- * this is treated as success and future calls to flush() will
- * succeed automatically without being send to the filesystem
- * process.
- *
- * Valid replies:
- * fuse_reply_err
- *
- * @param req request handle
- * @param ino the inode number
- * @param fi file information
- *
- * [close]: http://pubs.opengroup.org/onlinepubs/9699919799/functions/close.html
- */
-func (wfs *WFS) Flush(cancel <-chan struct{}, in *fuse.FlushIn) fuse.Status {
- return fuse.ENOSYS
+ fileHandle, code := wfs.AcquireHandle(in.NodeId, in.Uid, in.Gid)
+ if code == fuse.OK {
+ out.Fh = uint64(fileHandle.fh)
+ }
+ return code
}
/**
@@ -191,27 +94,5 @@ func (wfs *WFS) Flush(cancel <-chan struct{}, in *fuse.FlushIn) fuse.Status {
* @param fi file information
*/
func (wfs *WFS) Release(cancel <-chan struct{}, in *fuse.ReleaseIn) {
-}
-
-/**
- * Synchronize file contents
- *
- * If the datasync parameter is non-zero, then only the user data
- * should be flushed, not the meta data.
- *
- * If this request is answered with an error code of ENOSYS,
- * this is treated as success and future calls to fsync() will
- * succeed automatically without being send to the filesystem
- * process.
- *
- * Valid replies:
- * fuse_reply_err
- *
- * @param req request handle
- * @param ino the inode number
- * @param datasync flag indicating if only data should be flushed
- * @param fi file information
- */
-func (wfs *WFS) Fsync(cancel <-chan struct{}, in *fuse.FsyncIn) (code fuse.Status) {
- return fuse.ENOSYS
+ wfs.ReleaseHandle(FileHandleId(in.Fh))
}
diff --git a/weed/mount/weedfs_file_read.go b/weed/mount/weedfs_file_read.go
new file mode 100644
index 000000000..d9ad1f4ea
--- /dev/null
+++ b/weed/mount/weedfs_file_read.go
@@ -0,0 +1,34 @@
+package mount
+
+import (
+ "github.com/hanwen/go-fuse/v2/fuse"
+)
+
+/**
+ * Read data
+ *
+ * Read should send exactly the number of bytes requested except
+ * on EOF or error, otherwise the rest of the data will be
+ * substituted with zeroes. An exception to this is when the file
+ * has been opened in 'direct_io' mode, in which case the return
+ * value of the read system call will reflect the return value of
+ * this operation.
+ *
+ * fi->fh will contain the value set by the open method, or will
+ * be undefined if the open method didn't set any value.
+ *
+ * Valid replies:
+ * fuse_reply_buf
+ * fuse_reply_iov
+ * fuse_reply_data
+ * fuse_reply_err
+ *
+ * @param req request handle
+ * @param ino the inode number
+ * @param size number of bytes to read
+ * @param off offset to read from
+ * @param fi file information
+ */
+func (wfs *WFS) Read(cancel <-chan struct{}, in *fuse.ReadIn, buf []byte) (fuse.ReadResult, fuse.Status) {
+ return nil, fuse.ENOSYS
+}
diff --git a/weed/mount/weedfs_file_sync.go b/weed/mount/weedfs_file_sync.go
new file mode 100644
index 000000000..1b89c1ecb
--- /dev/null
+++ b/weed/mount/weedfs_file_sync.go
@@ -0,0 +1,70 @@
+package mount
+
+import (
+ "github.com/hanwen/go-fuse/v2/fuse"
+)
+
+/**
+ * Flush method
+ *
+ * This is called on each close() of the opened file.
+ *
+ * Since file descriptors can be duplicated (dup, dup2, fork), for
+ * one open call there may be many flush calls.
+ *
+ * Filesystems shouldn't assume that flush will always be called
+ * after some writes, or that if will be called at all.
+ *
+ * fi->fh will contain the value set by the open method, or will
+ * be undefined if the open method didn't set any value.
+ *
+ * NOTE: the name of the method is misleading, since (unlike
+ * fsync) the filesystem is not forced to flush pending writes.
+ * One reason to flush data is if the filesystem wants to return
+ * write errors during close. However, such use is non-portable
+ * because POSIX does not require [close] to wait for delayed I/O to
+ * complete.
+ *
+ * If the filesystem supports file locking operations (setlk,
+ * getlk) it should remove all locks belonging to 'fi->owner'.
+ *
+ * If this request is answered with an error code of ENOSYS,
+ * this is treated as success and future calls to flush() will
+ * succeed automatically without being send to the filesystem
+ * process.
+ *
+ * Valid replies:
+ * fuse_reply_err
+ *
+ * @param req request handle
+ * @param ino the inode number
+ * @param fi file information
+ *
+ * [close]: http://pubs.opengroup.org/onlinepubs/9699919799/functions/close.html
+ */
+func (wfs *WFS) Flush(cancel <-chan struct{}, in *fuse.FlushIn) fuse.Status {
+ return fuse.ENOSYS
+}
+
+/**
+ * Synchronize file contents
+ *
+ * If the datasync parameter is non-zero, then only the user data
+ * should be flushed, not the meta data.
+ *
+ * If this request is answered with an error code of ENOSYS,
+ * this is treated as success and future calls to fsync() will
+ * succeed automatically without being send to the filesystem
+ * process.
+ *
+ * Valid replies:
+ * fuse_reply_err
+ *
+ * @param req request handle
+ * @param ino the inode number
+ * @param datasync flag indicating if only data should be flushed
+ * @param fi file information
+ */
+func (wfs *WFS) Fsync(cancel <-chan struct{}, in *fuse.FsyncIn) (code fuse.Status) {
+ return fuse.ENOSYS
+}
diff --git a/weed/mount/weedfs_file_write.go b/weed/mount/weedfs_file_write.go
new file mode 100644
index 000000000..72152d72e
--- /dev/null
+++ b/weed/mount/weedfs_file_write.go
@@ -0,0 +1,35 @@
+package mount
+
+import (
+ "github.com/hanwen/go-fuse/v2/fuse"
+)
+
+/**
+ * Write data
+ *
+ * Write should return exactly the number of bytes requested
+ * except on error. An exception to this is when the file has
+ * been opened in 'direct_io' mode, in which case the return value
+ * of the write system call will reflect the return value of this
+ * operation.
+ *
+ * Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is
+ * expected to reset the setuid and setgid bits.
+ *
+ * fi->fh will contain the value set by the open method, or will
+ * be undefined if the open method didn't set any value.
+ *
+ * Valid replies:
+ * fuse_reply_write
+ * fuse_reply_err
+ *
+ * @param req request handle
+ * @param ino the inode number
+ * @param buf data to write
+ * @param size number of bytes to write
+ * @param off offset to write to
+ * @param fi file information
+ */
+func (wfs *WFS) Write(cancel <-chan struct{}, in *fuse.WriteIn, data []byte) (written uint32, code fuse.Status) {
+ return 0, fuse.ENOSYS
+}