Fix unmounting in Tramp

* doc/misc/tramp.texi (FUSE setup): Add tramp-fuse-unmount-on-cleanup.

* lisp/net/tramp.el (tramp-file-name-unify): New defun.
(tramp-file-name-equal-p):
* lisp/net/tramp-cache.el (tramp-get-connection-property)
(tramp-set-connection-property, tramp-flush-connection-property)
(tramp-flush-connection-properties): Use it.

* lisp/net/tramp-fuse.el (tramp-fuse-get-fusermount): New defun.
(tramp-fuse-mount-points): New defvar.
(tramp-fuse-unmount): Use it.  Delete VEC from
`tramp-fuse-mount-points'.  Delete mount point.
(tramp-fuse-unmount-on-cleanup): New user option.
(tramp-fuse-cleanup, tramp-fuse-cleanup-all): New defuns.
(top): Adapt `tramp-fuse-unload-hook',
`tramp-cleanup-connection-hook',
`tramp-cleanup-all-connections-hook' and `kill-emacs-hook'.

* lisp/net/tramp-rclone.el (tramp-rclone-maybe-open-connection):
* lisp/net/tramp-sshfs.el (tramp-sshfs-maybe-open-connection):
Add VEC to `tramp-fuse-mount-points'.

* test/lisp/net/tramp-tests.el (tramp-fuse-unmount-on-cleanup): Declare.
(tramp-test39-make-lock-file-name): Use it.
This commit is contained in:
Michael Albinus 2021-10-03 18:55:35 +02:00
parent 7a6d34cd1f
commit 3863919a00
7 changed files with 76 additions and 38 deletions

View file

@ -2629,6 +2629,11 @@ Example:
@end group @end group
@end lisp @end lisp
@vindex tramp-fuse-unmount-on-cleanup
The user option @code{tramp-fuse-unmount-on-cleanup}, when set to
non-@code{nil}, controls, whether a mount point is unmounted on
connection cleanup or on Emacs exiting.
@anchor{Setup of rclone method} @anchor{Setup of rclone method}
@subsection @option{rclone} setup @subsection @option{rclone} setup

View file

@ -319,12 +319,7 @@ KEY identifies the connection, it is either a process or a
used to cache connection properties of the local machine. used to cache connection properties of the local machine.
If KEY is `tramp-cache-undefined', or if the value is not set for If KEY is `tramp-cache-undefined', or if the value is not set for
the connection, return DEFAULT." the connection, return DEFAULT."
;; Unify key by removing localname and hop from `tramp-file-name' (setq key (tramp-file-name-unify key))
;; structure. Work with a copy in order to avoid side effects.
(when (tramp-file-name-p key)
(setq key (copy-tramp-file-name key))
(setf (tramp-file-name-localname key) nil
(tramp-file-name-hop key) nil))
(let* ((hash (tramp-get-hash-table key)) (let* ((hash (tramp-get-hash-table key))
(cached (if (hash-table-p hash) (cached (if (hash-table-p hash)
(gethash property hash tramp-cache-undefined) (gethash property hash tramp-cache-undefined)
@ -350,12 +345,7 @@ used to cache connection properties of the local machine. If KEY
is `tramp-cache-undefined', nothing is set. is `tramp-cache-undefined', nothing is set.
PROPERTY is set persistent when KEY is a `tramp-file-name' structure. PROPERTY is set persistent when KEY is a `tramp-file-name' structure.
Return VALUE." Return VALUE."
;; Unify key by removing localname and hop from `tramp-file-name' (setq key (tramp-file-name-unify key))
;; structure. Work with a copy in order to avoid side effects.
(when (tramp-file-name-p key)
(setq key (copy-tramp-file-name key))
(setf (tramp-file-name-localname key) nil
(tramp-file-name-hop key) nil))
(when-let ((hash (tramp-get-hash-table key))) (when-let ((hash (tramp-get-hash-table key)))
(puthash property value hash)) (puthash property value hash))
(setq tramp-cache-data-changed (setq tramp-cache-data-changed
@ -379,12 +369,7 @@ KEY identifies the connection, it is either a process or a
`tramp-file-name' structure. A special case is nil, which is `tramp-file-name' structure. A special case is nil, which is
used to cache connection properties of the local machine. used to cache connection properties of the local machine.
PROPERTY is set persistent when KEY is a `tramp-file-name' structure." PROPERTY is set persistent when KEY is a `tramp-file-name' structure."
;; Unify key by removing localname and hop from `tramp-file-name' (setq key (tramp-file-name-unify key))
;; structure. Work with a copy in order to avoid side effects.
(when (tramp-file-name-p key)
(setq key (copy-tramp-file-name key))
(setf (tramp-file-name-localname key) nil
(tramp-file-name-hop key) nil))
(when-let ((hash (tramp-get-hash-table key))) (when-let ((hash (tramp-get-hash-table key)))
(remhash property hash)) (remhash property hash))
(setq tramp-cache-data-changed (setq tramp-cache-data-changed
@ -397,12 +382,7 @@ PROPERTY is set persistent when KEY is a `tramp-file-name' structure."
KEY identifies the connection, it is either a process or a KEY identifies the connection, it is either a process or a
`tramp-file-name' structure. A special case is nil, which is `tramp-file-name' structure. A special case is nil, which is
used to cache connection properties of the local machine." used to cache connection properties of the local machine."
;; Unify key by removing localname and hop from `tramp-file-name' (setq key (tramp-file-name-unify key))
;; structure. Work with a copy in order to avoid side effects.
(when (tramp-file-name-p key)
(setq key (copy-tramp-file-name key))
(setf (tramp-file-name-localname key) nil
(tramp-file-name-hop key) nil))
(tramp-message (tramp-message
key 7 "%s %s" key key 7 "%s %s" key
(when-let ((hash (gethash key tramp-cache-data))) (when-let ((hash (gethash key tramp-cache-data)))

View file

@ -175,15 +175,30 @@
mount) mount)
(match-string 1 mount))))))) (match-string 1 mount)))))))
(defun tramp-fuse-get-fusermount ()
"Determine the local `fusermount' command."
;; We use key nil for local connection properties.
(with-tramp-connection-property nil "fusermount"
(or (executable-find "fusermount3")
(executable-find "fusermount"))))
(defvar tramp-fuse-mount-points nil
"List of fuse volume determined by a VEC.")
(defun tramp-fuse-unmount (vec) (defun tramp-fuse-unmount (vec)
"Unmount fuse volume determined by VEC." "Unmount fuse volume determined by VEC."
(let ((default-directory tramp-compat-temporary-file-directory) (let* ((default-directory tramp-compat-temporary-file-directory)
(command (format "fusermount3 -u %s" (tramp-fuse-mount-point vec)))) (mount-point (tramp-fuse-mount-point vec))
(command (format "%s -u %s" (tramp-fuse-get-fusermount) mount-point)))
(tramp-message vec 6 "%s\n%s" command (shell-command-to-string command)) (tramp-message vec 6 "%s\n%s" command (shell-command-to-string command))
(tramp-flush-connection-property (tramp-flush-connection-property
(tramp-get-connection-process vec) "mounted") (tramp-get-connection-process vec) "mounted")
(setq tramp-fuse-mount-points
(delete (tramp-file-name-unify vec) tramp-fuse-mount-points))
;; Give the caches a chance to expire. ;; Give the caches a chance to expire.
(sleep-for 1))) (sleep-for 1)
(when (tramp-compat-directory-empty-p mount-point)
(delete-directory mount-point))))
(defun tramp-fuse-local-file-name (filename) (defun tramp-fuse-local-file-name (filename)
"Return local mount name of FILENAME." "Return local mount name of FILENAME."
@ -205,6 +220,36 @@
(substring localname 1) localname) (substring localname 1) localname)
(tramp-fuse-mount-point v))))))) (tramp-fuse-mount-point v)))))))
(defcustom tramp-fuse-unmount-on-cleanup nil
"Whether fuse volumes shall be unmounted on cleanup."
:group 'tramp
:version "28.1"
:type 'boolean)
(defun tramp-fuse-cleanup (vec)
"Cleanup fuse volume determined by VEC."
(and tramp-fuse-unmount-on-cleanup
(member (tramp-file-name-unify vec) tramp-fuse-mount-points)
(tramp-fuse-unmount vec)))
(defun tramp-fuse-cleanup-all ()
"Unmount all fuse volumes used by Tramp."
(and tramp-fuse-unmount-on-cleanup
(mapc #'tramp-fuse-unmount tramp-fuse-mount-points)))
;; Add cleanup hooks.
(add-hook 'tramp-cleanup-connection-hook #'tramp-fuse-cleanup)
(add-hook 'tramp-cleanup-all-connections-hook #'tramp-fuse-cleanup-all)
(add-hook 'kill-emacs-hook #'tramp-fuse-cleanup-all)
(add-hook 'tramp-fuse-unload-hook
(lambda ()
(remove-hook 'tramp-cleanup-connection-hook
#'tramp-fuse-cleanup)
(remove-hook 'tramp-cleanup-all-connections-hook
#'tramp-fuse-cleanup-all)
(remove-hook 'kill-emacs-hook
#'tramp-fuse-cleanup-all)))
(add-hook 'tramp-unload-hook (add-hook 'tramp-unload-hook
(lambda () (lambda ()
(unload-feature 'tramp-fuse 'force))) (unload-feature 'tramp-fuse 'force)))

View file

@ -386,6 +386,7 @@ connection if a previous connection has died for some reason."
(tramp-cleanup-connection vec 'keep-debug 'keep-password)) (tramp-cleanup-connection vec 'keep-debug 'keep-password))
;; Mark it as connected. ;; Mark it as connected.
(add-to-list 'tramp-fuse-mount-points (tramp-file-name-unify vec))
(tramp-set-connection-property (tramp-set-connection-property
(tramp-get-connection-process vec) "connected" t)))) (tramp-get-connection-process vec) "connected" t))))

View file

@ -371,6 +371,7 @@ connection if a previous connection has died for some reason."
vec 'file-error "Error mounting %s" (tramp-fuse-mount-spec vec)))) vec 'file-error "Error mounting %s" (tramp-fuse-mount-spec vec))))
;; Mark it as connected. ;; Mark it as connected.
(add-to-list 'tramp-fuse-mount-points (tramp-file-name-unify vec))
(tramp-set-connection-property (tramp-set-connection-property
(tramp-get-connection-process vec) "connected" t))) (tramp-get-connection-process vec) "connected" t)))

View file

@ -1450,16 +1450,24 @@ If nil, return `tramp-default-port'."
(put #'tramp-file-name-port-or-default 'tramp-suppress-trace t) (put #'tramp-file-name-port-or-default 'tramp-suppress-trace t)
(defun tramp-file-name-unify (vec)
"Unify VEC by removing localname and hop from `tramp-file-name' structure.
Objects returned by this function compare `equal' if they refer to the
same connection. Make a copy in order to avoid side effects."
(when (tramp-file-name-p vec)
(setq vec (copy-tramp-file-name vec))
(setf (tramp-file-name-localname vec) nil
(tramp-file-name-hop vec) nil))
vec)
(put #'tramp-file-name-unify 'tramp-suppress-trace t)
;; Comparison of file names is performed by `tramp-equal-remote'. ;; Comparison of file names is performed by `tramp-equal-remote'.
(defun tramp-file-name-equal-p (vec1 vec2) (defun tramp-file-name-equal-p (vec1 vec2)
"Check, whether VEC1 and VEC2 denote the same `tramp-file-name'." "Check, whether VEC1 and VEC2 denote the same `tramp-file-name'."
(and (tramp-file-name-p vec1) (tramp-file-name-p vec2) (and (tramp-file-name-p vec1) (tramp-file-name-p vec2)
(string-equal (tramp-file-name-method vec1) (equal (tramp-file-name-unify vec1)
(tramp-file-name-method vec2)) (tramp-file-name-unify vec2))))
(string-equal (tramp-file-name-user-domain vec1)
(tramp-file-name-user-domain vec2))
(string-equal (tramp-file-name-host-port vec1)
(tramp-file-name-host-port vec2))))
(defun tramp-get-method-parameter (vec param) (defun tramp-get-method-parameter (vec param)
"Return the method parameter PARAM. "Return the method parameter PARAM.
@ -3846,7 +3854,7 @@ User is always nil."
(delete-file (tramp-make-tramp-file-name v remote-copy 'nohop)))) (delete-file (tramp-make-tramp-file-name v remote-copy 'nohop))))
;; Result. ;; Result.
(cons (expand-file-name filename) (cdr result))))) (cons filename (cdr result)))))
(defun tramp-get-lock-file (file) (defun tramp-get-lock-file (file)
"Read lockfile info of FILE. "Read lockfile info of FILE.

View file

@ -69,6 +69,7 @@
(defvar tramp-connection-properties) (defvar tramp-connection-properties)
(defvar tramp-copy-size-limit) (defvar tramp-copy-size-limit)
(defvar tramp-display-escape-sequence-regexp) (defvar tramp-display-escape-sequence-regexp)
(defvar tramp-fuse-unmount-on-cleanup)
(defvar tramp-inline-compress-start-size) (defvar tramp-inline-compress-start-size)
(defvar tramp-persistency-file-name) (defvar tramp-persistency-file-name)
(defvar tramp-remote-path) (defvar tramp-remote-path)
@ -5884,10 +5885,7 @@ Use direct async.")
tramp-allow-unsafe-temporary-files tramp-allow-unsafe-temporary-files
(inhibit-message t) (inhibit-message t)
;; tramp-rclone.el and tramp-sshfs.el cache the mounted files. ;; tramp-rclone.el and tramp-sshfs.el cache the mounted files.
(tramp-cleanup-connection-hook (tramp-fuse-unmount-on-cleanup t)
(append
(and (tramp--test-fuse-p) '(tramp-fuse-unmount))
tramp-cleanup-connection-hook))
auto-save-default auto-save-default
noninteractive) noninteractive)