12037: Pull default arvados/jobs:latest image as needed.
[arvados.git] / services / fuse / arvados_fuse / __init__.py
index 8a80950b45646f14efc668037e88ac31140143e8..a43a556866d524920b04303aea252ff127ac8c44 100644 (file)
@@ -1,3 +1,7 @@
+# Copyright (C) The Arvados Authors. All rights reserved.
+#
+# SPDX-License-Identifier: AGPL-3.0
+
 """FUSE driver for Arvados Keep
 
 Architecture:
@@ -74,7 +78,14 @@ import Queue
 # unlimited to avoid deadlocks, see https://arvados.org/issues/3198#note-43 for
 # details.
 
-llfuse.capi._notify_queue = Queue.Queue()
+if hasattr(llfuse, 'capi'):
+    # llfuse < 0.42
+    llfuse.capi._notify_queue = Queue.Queue()
+else:
+    # llfuse >= 0.42
+    llfuse._notify_queue = Queue.Queue()
+
+LLFUSE_VERSION_0 = llfuse.__version__.startswith('0')
 
 from fusedir import sanitize_filename, Directory, CollectionDirectory, TmpCollectionDirectory, MagicDirectory, TagsDirectory, ProjectDirectory, SharedDirectory, CollectionDirectoryBase
 from fusefile import StringFile, FuseArvadosFile
@@ -100,14 +111,16 @@ class Handle(object):
         self.obj.dec_use()
 
     def flush(self):
-        if self.obj.writable():
-            return self.obj.flush()
+        pass
 
 
 class FileHandle(Handle):
     """Connects a numeric file handle to a File  object that has
     been opened by the client."""
-    pass
+
+    def flush(self):
+        if self.obj.writable():
+            return self.obj.flush()
 
 
 class DirectoryHandle(Handle):
@@ -355,12 +368,19 @@ class Operations(llfuse.Operations):
 
     @catch_exceptions
     def destroy(self):
-        with llfuse.lock:
-            self._shutdown_started.set()
-            if self.events:
-                self.events.close()
-                self.events = None
-
+        self._shutdown_started.set()
+        if self.events:
+            self.events.close()
+            self.events = None
+
+        # Different versions of llfuse require and forbid us to
+        # acquire the lock here. See #8345#note-37, #10805#note-9.
+        if LLFUSE_VERSION_0 and llfuse.lock.acquire():
+            # llfuse < 0.42
+            self.inodes.clear()
+            llfuse.lock.release()
+        else:
+            # llfuse >= 0.42
             self.inodes.clear()
 
     def access(self, inode, mode, ctx):
@@ -400,10 +420,7 @@ class Operations(llfuse.Operations):
                 parent.update()
 
     @catch_exceptions
-    def getattr(self, inode, ctx):
-        return self._getattr(inode)
-
-    def _getattr(self, inode):
+    def getattr(self, inode, ctx=None):
         if inode not in self.inodes:
             raise llfuse.FUSEError(errno.ENOENT)
 
@@ -435,19 +452,36 @@ class Operations(llfuse.Operations):
 
         entry.st_blksize = 512
         entry.st_blocks = (entry.st_size/512)+1
-        entry.st_atime_ns = int(e.atime())
-        entry.st_mtime_ns = int(e.mtime())
-        entry.st_ctime_ns = int(e.mtime())
+        if hasattr(entry, 'st_atime_ns'):
+            # llfuse >= 0.42
+            entry.st_atime_ns = int(e.atime() * 1000000000)
+            entry.st_mtime_ns = int(e.mtime() * 1000000000)
+            entry.st_ctime_ns = int(e.mtime() * 1000000000)
+        else:
+            # llfuse < 0.42
+            entry.st_atime = int(e.atime)
+            entry.st_mtime = int(e.mtime)
+            entry.st_ctime = int(e.mtime)
 
         return entry
 
     @catch_exceptions
-    def setattr(self, inode, attr, ctx):
-        entry = self._getattr(inode)
+    def setattr(self, inode, attr, fields=None, fh=None, ctx=None):
+        entry = self.getattr(inode)
 
-        e = self.inodes[inode]
+        if fh is not None and fh in self._filehandles:
+            handle = self._filehandles[fh]
+            e = handle.obj
+        else:
+            e = self.inodes[inode]
 
-        if attr.st_size is not None and isinstance(e, FuseArvadosFile):
+        if fields is None:
+            # llfuse < 0.42
+            update_size = attr.st_size is not None
+        else:
+            # llfuse >= 0.42
+            update_size = fields.update_size
+        if update_size and isinstance(e, FuseArvadosFile):
             with llfuse.lock_released:
                 e.arvfile.truncate(attr.st_size)
                 entry.st_size = e.arvfile.size()
@@ -455,7 +489,7 @@ class Operations(llfuse.Operations):
         return entry
 
     @catch_exceptions
-    def lookup(self, parent_inode, name, ctx):
+    def lookup(self, parent_inode, name, ctx=None):
         name = unicode(name, self.inodes.encoding)
         inode = None
 
@@ -474,7 +508,7 @@ class Operations(llfuse.Operations):
             _logger.debug("arv-mount lookup: parent_inode %i name '%s' inode %i",
                       parent_inode, name, inode)
             self.inodes[inode].inc_ref()
-            return self._getattr(inode)
+            return self.getattr(inode)
         else:
             _logger.debug("arv-mount lookup: parent_inode %i name '%s' not found",
                       parent_inode, name)
@@ -491,7 +525,7 @@ class Operations(llfuse.Operations):
                 self.inodes.del_entry(ent)
 
     @catch_exceptions
-    def open(self, inode, flags, ctx):
+    def open(self, inode, flags, ctx=None):
         if inode in self.inodes:
             p = self.inodes[inode]
         else:
@@ -565,6 +599,7 @@ class Operations(llfuse.Operations):
     @catch_exceptions
     def release(self, fh):
         if fh in self._filehandles:
+            _logger.debug("arv-mount release fh %i", fh)
             try:
                 self._filehandles[fh].flush()
             except Exception:
@@ -578,7 +613,7 @@ class Operations(llfuse.Operations):
         self.release(fh)
 
     @catch_exceptions
-    def opendir(self, inode, ctx):
+    def opendir(self, inode, ctx=None):
         _logger.debug("arv-mount opendir: inode %i", inode)
 
         if inode in self.inodes:
@@ -613,11 +648,11 @@ class Operations(llfuse.Operations):
         e = off
         while e < len(handle.entries):
             if handle.entries[e][1].inode in self.inodes:
-                yield (handle.entries[e][0].encode(self.inodes.encoding), self._getattr(handle.entries[e][1].inode), e+1)
+                yield (handle.entries[e][0].encode(self.inodes.encoding), self.getattr(handle.entries[e][1].inode), e+1)
             e += 1
 
     @catch_exceptions
-    def statfs(self, ctx):
+    def statfs(self, ctx=None):
         st = llfuse.StatvfsData()
         st.f_bsize = 128 * 1024
         st.f_blocks = 0
@@ -650,7 +685,7 @@ class Operations(llfuse.Operations):
         return p
 
     @catch_exceptions
-    def create(self, inode_parent, name, mode, flags, ctx):
+    def create(self, inode_parent, name, mode, flags, ctx=None):
         _logger.debug("arv-mount create: parent_inode %i '%s' %o", inode_parent, name, mode)
 
         p = self._check_writable(inode_parent)
@@ -663,10 +698,10 @@ class Operations(llfuse.Operations):
         self.inodes.touch(p)
 
         f.inc_ref()
-        return (fh, self._getattr(f.inode))
+        return (fh, self.getattr(f.inode))
 
     @catch_exceptions
-    def mkdir(self, inode_parent, name, mode, ctx):
+    def mkdir(self, inode_parent, name, mode, ctx=None):
         _logger.debug("arv-mount mkdir: parent_inode %i '%s' %o", inode_parent, name, mode)
 
         p = self._check_writable(inode_parent)
@@ -676,22 +711,22 @@ class Operations(llfuse.Operations):
         d = p[name]
 
         d.inc_ref()
-        return self._getattr(d.inode)
+        return self.getattr(d.inode)
 
     @catch_exceptions
-    def unlink(self, inode_parent, name, ctx):
+    def unlink(self, inode_parent, name, ctx=None):
         _logger.debug("arv-mount unlink: parent_inode %i '%s'", inode_parent, name)
         p = self._check_writable(inode_parent)
         p.unlink(name)
 
     @catch_exceptions
-    def rmdir(self, inode_parent, name, ctx):
+    def rmdir(self, inode_parent, name, ctx=None):
         _logger.debug("arv-mount rmdir: parent_inode %i '%s'", inode_parent, name)
         p = self._check_writable(inode_parent)
         p.rmdir(name)
 
     @catch_exceptions
-    def rename(self, inode_parent_old, name_old, inode_parent_new, name_new, ctx):
+    def rename(self, inode_parent_old, name_old, inode_parent_new, name_new, ctx=None):
         _logger.debug("arv-mount rename: old_parent_inode %i '%s' new_parent_inode %i '%s'", inode_parent_old, name_old, inode_parent_new, name_new)
         src = self._check_writable(inode_parent_old)
         dest = self._check_writable(inode_parent_new)
@@ -705,5 +740,5 @@ class Operations(llfuse.Operations):
     def fsync(self, fh, datasync):
         self.flush(fh)
 
-    def fsyncdir(self, fh, datasync): 
+    def fsyncdir(self, fh, datasync):
         self.flush(fh)