プログラマーのメモ書き

伊勢在住のプログラマーが気になることを気ままにメモったブログです

Android エミュレータを複数ディスプレイのメイン以外に移動させるとフリーズする

タイトルの通り、 Android のエミュレータを起動して、メインのディスプレイ以外に移動させようとすると、隣の画面に映ったとたんにエミュレータがフリーズします。

こちらの記事で3画面化の話を書きましたが、それ以前から問題は起きていたので、グラボ関係とは別問題だと思います。

まあ、今までは一度フリーズしても、次にエミュレータを起動するときに Cold boot をさせれば、メインディスプレイに表示されてそのまま動いていたので、若干不便でしたが使ってきてました。

ところが、先日エミュレータを起動したままディスプレイの電源を切ったか何かのタイミングで、エミュレータがメイン以外のディスプレイに表示されました。後日、このエミュレータを起動しようとすると、どうにもメインディスプレイに戻りません。

ということで、これへの対応方法を検討しなくてはならなくなったので、調べてみたことをメモっておきます。

環境は下記のとおりでした。

  • Windows 10 21H2
  • Android Studio 4.1.3

解決方法

ググったら、割とすぐに解決方法が見つかりました(ずばり、下記記事です)。

android - AVD Crash on second monitor - Stack Overflow

なるほど、 Open GS EL renderer の設定の問題なんですね。

デフォルトでは、

f:id:junichim:20220203115741p:plain

のように、 host で検出したものを使うとなっているのを

f:id:junichim:20220203115858p:plain

ANGLE(D3D11) に変更するとよいとのことです(要エミュレータの再起動)。

試してみると、メインディスプレイ以外でも問題なく表示できるようになりました。

起動しないエミュレータの場合

上記のやり方は、エミュレータが起動している場合にしか使えません。今回のように、メインディスプレイに持ってくることができなくてエミュレータが起動しない場合は、設定そのものが変更できません。

この場合、問題のあるエミュレータのディレクトリ直下にある『 hardware-qemu.ini 』ファイルをテキストエディタで開いて、

hw.gpu.mode = host

となっている個所を

hw.gpu.mode = angle_indirect

に変更してから、エミュレータを起動( Cold boot )したら、無事立ち上がりました。

これが、正しい設定方法かどうかはわかりませんが、お困りの方、何かのご参考にしていただければと思います。

QNAP NetBak Replicator によるバックアップ

先日、第24回伊勢IT交流会にて、こちらの記事で書いた、 cron + rsnapshot による Windows のバックアップの話をしたら、 QNAP の NAS なら同期アプリかバックアップツールがあったはずだよ、と教えてもらいました。

一度、調べてみる価値ありそうだと思い、早速みてみると、2つほどバックアップに使えそうなツールがありました。

NetBak Replicator は Windows にインストールして使うツールで、ローカルドライブのデータをバックアップするツールになります。以前あきらめた Windows のファイル履歴に代わるようなツールのイメージです。

Qsync は NAS 上のデータ領域をクライアント側で同期するというのが本来の目的のようです。プライベートな dropbox を作るイメージですかね。クライアントが1つなら、データのバックアップツールと同じように使うことができます。

前に設定した cron + rsnapshot によるバックアップでは、バックアップ実行中での PC シャットダウンが運用上のネックになっていたので、 NetBak Replicator を使ったバックアップに切り替えることで、それを回避できないか試してみましたので、それについてメモっておきます。

なお、 QNAP でのバックアップ全般については、 QNAP の記事 なども参考にしてください。

NetBak Replicator のインストール

NetBak Replicator は QNAP NAS 上で動作するのではなく、Windows などにインストールして使うツールになります(QNAP が NAS を有効利用するため配布しているツールなんでしょうね)。

なので、インストールは、QNAP のサイトより NetBak Replicator をダウンロードして、 Windows にインストールする形になります。

基本的には、画面の説明通りに進めればOKです。 NetBak Replicator のマニュアル(PDF)もありましたので、ご参考にどうぞ。

インストールを進めると、最後のほうで、下記のように

f:id:junichim:20220117225854p:plain

起動オプションを決めるように求められるのですが、今回はデフォルトのままとしました。

初回起動

インストールが問題なく終わり、最初に NetBak Replicator を起動すると、下記のような画面が表示されます。

f:id:junichim:20220117225932p:plain

ここでは、地域情報としてグローバルを選択します。

でも、これってどういうことだろうと思って、画面のリンクをたどると、

QNAP モバイルアプリおよびユーティリティが現在の位置を確認する必要があるのはなぜですか? | QNAP

中国への対応とのことです。なんだかなー。

このあと、下記のような設定ウィザードが出るのですが、ここはキャンセルします。

f:id:junichim:20220118102300p:plain

最後に、シンプルモードの開始画面が表示されて、 NetBak Replicator が起動した状態になります。

f:id:junichim:20220118102347p:plain

画面下部の『拡張モード』を選択して、拡張モードで設定を進めます。

設定

無事にインストールが完了して、 NetBak Replicator が起動したら、バックアップを設定します。 が、その前に、どのバックアップ種類を使うか決定します。

どのバックアップを使うか

NetBak Replicator は3種類のバックアップがあります。

  • オートバックアップ
  • スケジュールバックアップ
  • インスタントバックアップ

オートバックアップは、指定したフォルダに変更があった際に自動的にバックアップを取るものです。 スケジュールバックアップは文字通り、設定したスケジュールでバックアップを取る機能です。 インスタントバックアップは、ボタンを押して手作業でバックアップを取る機能です。

スケジュールバックアップが望ましいかなと思ったのですが、

  • 日次・週次・月次のような形の世代管理の形ではバックアップデータを管理できない(バックアップごとに別フォルダにデータを貯めていくことはできる)
  • 古いデータの自動削除は行ってくれないので、どこかで手作業で削除作業を行う必要がある

ということのようなので、断念しました

Windows 上の作業データのバックアップが主な目的なので、

  • Windows での作業中はオートバックアップでデータを保護するようにして、
  • 作業完了後、夜中に NAS 側でスナップショットをとる( cron + rsnapshot でやったのと同様に、バックアップ先は NAS の iSCSI ターゲットをマウントしたドライブにする予定)

という形で、過去データをカバーするようにしてみました。こういった世代管理や重複データをハードリンクを使って使用量を減らすという点では、 rsnapshot のほうがいいですね。

オートバックアップの設定

オートバックアップを使うことに決めたので、 NetBak Replicator を起動して、拡張モードに切り替えて、『オートバックアップ』タブを選択します。

f:id:junichim:20220118102645p:plain

左側のツリーからバックアップ対象(画面上は『自動バックアップソース』となっています)を選択します。

右側のドロップダウンリストでバックアップ先(画面上は『宛先を選択してください』となっています)を指定します。今回はローカルドライブを指定していますが、任意のフォルダやネットワークドライブ等も指定できるようです。

あと、画面下部の『オプション』から、

f:id:junichim:20220118105839p:plain

のように、ログとして表示するものを『警告とエラーログのみを表示』に切り替えておきます。

参考:バックアップ先指定時のエラー

なお、『宛先を選択してください』のドロップダウンリストより、

f:id:junichim:20220118092346p:plain

『その他の場所』を選択すると、

f:id:junichim:20220118092131p:plain

のようなダイアログが表示されます。ここの説明の例で、ドライブ内のフォルダを指定することができる、ように書いているので、その通りに入力すると、

f:id:junichim:20220118092054p:plain

というエラーが表示されて、設定できないことがありました。指定したドライブが iSCSI ターゲットをマウントしたドライブだったためかもしれませんが、再度試したときはうまく指定できたので根本的な理由はよくわかりません。ま、ご参考までに。

バックアップ実行

設定ができれば、画面右下の『自動バックアップを開始』ボタンを押します。すると、下記のようなダイアログが表示され、

f:id:junichim:20220118102946p:plain

その場でバックアップが始まります。

なお、バックアップ先は、下記の記事などでも書かれているように、

指定したバックアップ先に

NetBakData\ユーザー名@マシン名

というフォルダが作成され、その内部に『Disk C』などのドライブ名のフォルダが作成され、その内部にドライブ名以下のパス付でデータが保存されていきます。

参考:ユーザーフォルダを指定した場合

バックアップ対象を指定する際に、下図のようにユーザー名のフォルダ以下を指定した場合、

f:id:junichim:20220118110849p:plain

バックアップ先は、 VistaProfileData というフォルダが作られて、その中に、指定したフォルダ以下のデータが保存されました。

f:id:junichim:20220118093708p:plain

一方、バックアップ対象として、直接、C:\Users\ユーザー名\指定フォルダ名 を指定した場合は、

f:id:junichim:20220118093856p:plain

のように『Disk C』フォルダが作られ、その内部に Users 以下のパスを保持して保存されました。

Windows のバージョンでユーザーフォルダの位置がいろいろと変わるので、それへの対応なんでしょうね、きっと。いずれにせよ、バックアップ対象の指定の仕方で保存先フォルダ名が変わるようですので、ご注意ください。

参考:長いファイル名について

バックアップの際に、長いファイル名についてはバックアップできないようです。スクリーンショットは取れなかったのですが、260文字以上のパス名がある場合は、エラーとして表示されていました。

オートバックアップのテスト

最初に指定したバックアップ元のデータをすべて保存できたら、

f:id:junichim:20220118094310p:plain

こんな感じの画面になり、『ステータス』が『開始』になります。

これで、自動バックアップが動作しているはずです。確認のために NetBak Replicator の画面をいったん閉じます。

テストしてみます。バックアップ元フォルダで、ファイルを追加します。

f:id:junichim:20220118094505p:plain

その後、バックアップ先フォルダを開くと、

f:id:junichim:20220118094537p:plain

おお、ちゃんとコピーされてますね。

PCを再起動してから、もう一度同じテストを行ってみましたが、あれ?なぜかうまくいきません。バックアップ対象フォルダにファイルを追加しても、バックアップが取られません。なんでだろうか?

PC 再起動時の動作確認

実は、PC 再起動時、上記で示したものと同じエラー画面が表示されていました。この時は、バックアップ先として NAS の iSCSI ターゲットをローカルドライブとしてマウントしたドライブを指定していました。

また、この時、タスクトレイのアイコンを見ると、 NetBak Replicator 自体は自動起動していますが、 NetBak Replicator を起動して確認すると、ステータスが『停止』に変更されていました。

このため、iSCSI 絡みで問題が起きているのかもと思い、バックアップ先を D ドライブ( PC の SSD 上のドライブ)内のフォルダに切り替えて、同じテストをすると、この時は問題なくバックアップが取られます。

ということで、改めてエラーメッセージの内容を考えると、PC再起動により NetBak Replicator が起動された時点で iSCSI ドライブのマウントが完了していないため、バックアップ保存先が利用できなくて、自動バックアップそのものも正常に動作しなかった、のではないかと推測されます。

起動タイミングの調整

もし、この推測の通りだとすると、 NetBak Replicator が iSCSI マウント完了後に起動すれば、正しく動作しそうです。 NetBak Replicator はどこで起動されているのかと調べてみると、タスクスケジューラにありました。

f:id:junichim:20220118104820p:plain

起動タイミングは、ログオン時になっています。

f:id:junichim:20220118105018p:plain

iSCSI はログオンするとわりとすぐに再接続されている(ドライブが有効になった旨の通知が表示されている)ので、ログオン時に若干待ってから、 NetBak Replicator の起動タスクを実行すればいいんじゃないかと思います。

そこで、タスクスケジューラのこのタスク上で右クリックして、『プロパティ』を選択し、『トリガー』タブを選択して、起動トリガーを選択して『編集』を押します。

f:id:junichim:20220118105343p:plain

『詳細設定』で『遅延時間を指定する』にチェックを入れて、遅延時間として『30秒間』を選択します。

設定を変更したら、一度PCを再起動して、 NetBack Replicator が正しく起動されるか確認すると、先ほど出ていたエラーがでません。 さらに、 NetBak Replicator を表示してステータスを確認すると『開始』になっていました。 また、実際にファイルを追加すると、即座にバックアップ先にも保存されており、問題ありませんでした。

にらんだ通り、iSCSIドライブのマウントのタイミングが原因だったようです。

まとめ

このツールとオートバックアップ機能を使うと、 PC のシャットダウン時のバックアップ停止などを考えなくてよさそうなので、気軽に使えそうです。

前回試した cron + rsnapshot は無駄だったかな?と思ったのですが、よくよく考えると wsl 側のホームディレクトリは NetBak Replicator では扱えません。

ということで、最終的には、

  • Windows 側のデータ: NetBak Replicator
  • wsl 側のホームディレクトリ:cron + rsnapshot

として、両者を組み合わせてバックアップを取るようにしました。

wsl のホームディレクトリ部分だけなら、大して処理に時間がかからないので、運用上大きな問題にならないと見込んだためです。

これで、しばらくバックアップに悩まされなくて済むかな?

WSL2 経由での cron + rsnapshot によるバックアップ

こちらの記事で書いたように、手元の環境では Windows のファイル履歴が今一つうまく動いてくれませんでした。

ということで、代替案として、 wsl2 があるので、 rsync (結果的に rsnapshot を使いました)を使って作業フォルダのバックアップを取ればいいやと考えたので、それを実現する方法を試したのをメモっておきます。

cron の自動実行

何はともあれ rsync ( rsnapshot ) を使うには、 wsl で cron が動いてくれないと話になりません。で、wsl2 の cron を調べてみると、残念ながら自動起動してくれないようです。

mor@DESKTOP-DE7IL4F:/etc$ sudo service cron status
 * cron is not running
mor@DESKTOP-DE7IL4F:/etc$

手作業で起動すれば動きます。

mor@DESKTOP-DE7IL4F:/$ sudo service cron start
 * Starting periodic command scheduler cron                                                                      [ OK ]
mor@DESKTOP-DE7IL4F:/$
mor@DESKTOP-DE7IL4F:/$ sudo service cron status
 * cron is running
mor@DESKTOP-DE7IL4F:/$

でも、これだと、PCを起動するたびに、手作業で動かさないといけないので、いまいちです。

同じことで困っている人はたくさんいるようで、ググるとすぐに解決策が見つかりました。

バッチファイル+スタートアップによる起動

こちらの

WSL上cronをwindows起動時に自動実行する - Qiita

を参考に試してみました。

cron を起動するためのバッチファイルを作成します。例えば、こんな感じ。

wsl -u root -- service cron start

これを以下の場所に保存します(Windowsキー + R で shell:startup を指定すると一発で開きます)。

C:\Users\ユーザー名\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup

一度、Windows を再起動して、wslを開いて確認すると

mor@DESKTOP-DE7IL4F:/$ sudo service cron status
 * cron is running
mor@DESKTOP-DE7IL4F:/$

おぉ、起動していますね。

ただ、これだと、バッチファイル実行時に黒い画面が一瞬表示されるのがいまいちです。ということで、最終的には、下記記事を参考にして、黒い画面が表示されないように VBScript のファイルにしました。

バッチファイルを実行する時に黒いコマンドプロンプト画面を表示しない方法 | パソコンが便利で楽になるものを紹介しています

スタートアップフォルダに保存するファイルは拡張子を .vbs にしておきます。ここでは start_cron.vbs としました。中身はこんな感じです。

Set ws = CreateObject("Wscript.Shell")
ws.run "cmd /c wsl -u root -- service cron start", vbhide

こちらをさきほどのスタートアップフォルダに保存し、 Windows を再起動すると黒い画面が表示されずに、 cron が起動されることになります。

参考:sudoers を用いる方法

ちなみに、wsl -u root を使わずに、 sudoers を指定してパスワードを回避する方法もあるようです。

WSL2 で cron を有効にして OpenSSH server を走らせる - Qiita

参考:タスクスケジューラによる起動

今回は試していませんが、同じことをタスクスケジューラで行うこともできます。

WSLでCronを自動的に起動する方法 Windows 10 そして、11

こちらの方法だと、 Windows にログオンする前に起動させることもできますね。好きな方法で起動させればよいかと思います。

rsnapshot によるバックアップ

ここからが本題です。wsl2 で rsync によるバックアップを行います。と思ったのですが、 rsync だと保存対象と同じ1セットを更新する形になります(『同期』がとられます)。

バックアップ先のディスクは NAS の iSCSI を想定しており、この部分は NAS側で毎日スナップショットを取っているので、これでも問題ないといえば問題ないですが、どうせなら世代バックアップをやりたいと思います。

Linux だと、 rsnapshot というツールを使えば、 rsync をはじめとする標準的なツールを組み合わせて、世代間バックアップを実現してくれるそうです。

なので、下記の記事などを参考にして、 wsl 上でも rsnapshot によるバックアップができないか試していきます。

インストール

毎度なじみですね。

mor@DESKTOP-DE7IL4F:~$ sudo apt install rsnapshot

ちなみに、バージョンは

  • rsnapshot 1.4.3-2
  • rsync 3.1.3-8

でした。

設定

/etc/rsnapshot.conf が設定ファイルになるので、これを編集していきます。編集の前に、元のファイルを残しておきます。

mor@DESKTOP-DE7IL4F:/etc$ sudo cp -p rsnapshot.conf rsnapshot.conf.org

configファイルの設定内容は、基本的には上記のリンク先を参照してもらえればよいと思います。デフォルトから変更した点は以下になります。

mor@DESKTOP-DE7IL4F:/etc$ diff rsnapshot.conf.org rsnapshot.conf
23c23
< snapshot_root /var/cache/rsnapshot/
---
> snapshot_root /mnt/e/backup/
63c63
< #cmd_du               /usr/bin/du
---
> cmd_du                /usr/bin/du
67c67
< #cmd_rsnapshot_diff   /usr/bin/rsnapshot-diff
---
> cmd_rsnapshot_diff    /usr/bin/rsnapshot-diff
93,95c93,95
< retain        alpha   6
< retain        beta    7
< retain        gamma   4
---
> #retain       alpha   6
> #retain       beta    7
> #retain       gamma   4
96a97,99
> retain        hourly  4
> retain        daily   5
> retain        weekly  14
121c124
< #logfile      /var/log/rsnapshot.log
---
> logfile       /var/log/rsnapshot.log
227,229c230,235
< backup        /home/          localhost/
< backup        /etc/           localhost/
< backup        /usr/local/     localhost/
---
> #backup       /home/          localhost/
> #backup       /etc/           localhost/
> #backup       /usr/local/     localhost/
> backup        /home/mor/              localhost/
> backup        /mnt/c/Users/mor/bin/   localhost/
> backup        /mnt/d/                 localhost/
mor@DESKTOP-DE7IL4F:/etc$

retain で残す世代数を指定しますが、名称が alpha, beta, ・・・というのが分かりにくいので、 hourly, daily, weekly に変えています。 また、世代数は、詳しくは自動化で後述するように、今回のバックアップ対象のPCが常時稼働ではないので、少なめの世代数にしています。

あと、バックアップ対象として

backup        /home/mor/              localhost/
backup        /mnt/c/Users/mor/bin/   localhost/
backup        /mnt/d/                 localhost/

のようにしています。これは、

  • WSL のホームディレクトリ
  • C:\Users\ユーザー名\bin
  • D:\

を指定しており、 WSL 側のホームディレクトリと Windows 側のユーザーデータとデータドライブ( C の一部と D 全体)をまとめてバックアップをとるようにしました。

設定ファイルを記述できたら、構文があっているかテストします。

mor@DESKTOP-DE7IL4F:/etc$ rsnapshot configtest
Syntax OK
mor@DESKTOP-DE7IL4F:/etc$

問題なければテスト実行してみます。

mor@DESKTOP-DE7IL4F:/etc$ rsnapshot -t hourly
echo 1920 > /var/run/rsnapshot.pid
mkdir -m 0700 -p /mnt/e/backup/
mkdir -m 0755 -p /mnt/e/backup/hourly.0/
/usr/bin/rsync -a --delete --numeric-ids --relative --delete-excluded \
    /home/mor/ /mnt/e/backup/hourly.0/localhost/
mkdir -m 0755 -p /mnt/e/backup/hourly.0/
/usr/bin/rsync -a --delete --numeric-ids --relative --delete-excluded \
    /mnt/c/Users/mor/bin/ /mnt/e/backup/hourly.0/localhost/
mkdir -m 0755 -p /mnt/e/backup/hourly.0/
/usr/bin/rsync -a --delete --numeric-ids --relative --delete-excluded \
    /mnt/d/ /mnt/e/backup/hourly.0/localhost/
touch /mnt/e/backup/hourly.0/
mor@DESKTOP-DE7IL4F:/etc$

大丈夫そうですね。

ちなみに、 daily をテストすると

mor@DESKTOP-DE7IL4F:/etc$ rsnapshot -t daily
echo 1956 > /var/run/rsnapshot.pid
mkdir -m 0700 -p /mnt/e/backup/
/mnt/e/backup/hourly.3 not present (yet), nothing to copy
mor@DESKTOP-DE7IL4F:/etc$

となります。hourly.3 (4世代前のバックアップ)がないので、これも妥当ですね。

自動化

rsnapshot の自動化は cron を使うようです。rsnapshot をインストールすると /etc/cron.d に rsnapshot ファイルが作成されますので、これをもとに変更していきます。

さて、前述したように、作業 PC のデータフォルダのバックアップを取ることが目的のためなのですが、作業PCという性格のため、仕事終わりには電源を落としていきます。なので、常にPCが動作しているとは限りません。その点を考慮して、設定内容を検討しました。

rsnapshot の説明を読むと、 rsnapshot.conf の BACKUP LEVELS / INTERVALS セクションは保持する世代を表しており、 cron.d/rsnapshot の内容はrsnapshot を実行するタイミングを表しているようです。

サンプルなどを見ると、通常、この2つは対応しており、デフォルトだと

retain alpha   6
retain beta    7
retain gamma   4
retain delta   3

に対して、

0 */4         * * *           root    /usr/bin/rsnapshot alpha
30 3          * * *           root    /usr/bin/rsnapshot beta
0  3          * * 1           root    /usr/bin/rsnapshot gamma
30 2          1 * *           root    /usr/bin/rsnapshot delta

となっています。

内容を確認すると、

  • alpha は 4 時間おきにcronを実行しして、24 / 4 = 6、で 6 回実行し、6 世代分保持
  • beta は daily に該当し、毎日決められた時間( 3 時半)に実行して、一週間分の 7 世代を保持
  • weekly に相当する gamma は月曜日の 3 時に実行し、 4 世代( 4 週間分)
  • delta が毎月 1 日の 2 時半に実行し、 3 世代分( 3 か月分)を保持

となっています。つまり、 1 日当たりのバックアップ回数、 1 週間当たりの日ごとのバックアップ数、 1 月あたりの週ごとのバックアップ数と保持する世代数が対応する形です。

しかし、上述したように今回の対象は Windows の作業用 PC であるため電源をつけっぱなしではないので、作業データを保持するために、

rsnapshot の世代数 < cron で指定する rsnapshot の実行回数

となるようにしてみました。

こうすると、PCが起動されていれば各世代は順次上書きされていき、hourly のもっとも古いものが daily に付け替えられて、その時点で最も古い世代を残していくことになります。

微妙な点としては、PCの稼働時間によって、 hourly のもっとも古いものが必ずその日のもっとも古いデータである保証がない点です。例えば、

  • 一日の作業時間が長い場合は、その日の最初のバックアップがその日のバックアップとして取られるのではなく、その日のどこか作業途中のタイミングのバックアップになります
  • 一方、一日の作業時間が短い場合は、同じ日のバックアップでデータが更新されずに、前日より前のデータが、その日のバックアップとして取られるケースも出てきます

という感じです。とはいえ、過去の作業データがある程度の時間間隔で残っているほうが重要なので、この点は目をつぶることにします。

また、cronの実行タイミングは仕事しているときなら、昼頃は電源を入れている場合が多いだろうからとして、日中を指定しました。

ということで設定内容を下記のようにしました。

4 */2           * * *           root    /usr/bin/rsnapshot hourly
32 11           * * *           root    /usr/bin/rsnapshot daily
2  11           * * 1           root    /usr/bin/rsnapshot weekly

バックアップの実施とトラブルシューティング

これで、設定ファイルがOKと思い、実際に動かしてみます。すると、予想外にいろいろと問題がでてきてしまいました。

トラブル1

テストではなく、実際に動かしてみると、下記のwarningがでてきました。

[2022-01-07T22:07:42] WARNING: Some files and/or directories in /mnt/d/ only transferred partially during rsync operation

調べてみると、類似の現象があるようです。

[rsnapshot-discuss] rsync file partially transferred

ファイルを開いたままの場合などにエラーが出ることがあるようです。

ただ、この時は特にファイルを開いていたものもなかったので、解決策はちょっと見えません。

とりあえず、

  • ログレベルを 3 -> 5 に変更
  • /mnt/d/ としてドライブ全体を対象にすると、 Windows が作ったシステムフォルダ( $RECYCLE.BIN や System Volume Information など)もバックアップ対象になってたので、必要なデータフォルダのみを明示的に指定するように変更(システムディレクトリを対象外にする)

としてみました。具体的には、 rsnapshot.conf の backup の部分を

backup  /home/mor/              localhost/
backup  /mnt/c/Users/mor/bin/   localhost/
#backup /mnt/d/                 localhost/
backup  /mnt/d/avd/                     localhost/
backup  /mnt/d/work/                    localhost/
backup  /mnt/d/VirtualBox VMs/          localhost/

のように、 D ドライブ以下の必要なデータフォルダを指定する形としました。

この状態で、もう一度、rsnapshotを試してみると、無事エラーなくコピー処理が完了しました。どうも、システムフォルダ関係が何かしていたようです。

トラブル2

上記でバックアップ作成後、2回目の hourly 実行時に下記のようなエラーが出てきました。

[2022-01-11T14:04:01] /bin/cp -al /mnt/e/backup/hourly.0 /mnt/e/backup/hourly.1
[2022-01-11T15:37:35] /usr/bin/rsnapshot hourly: ERROR: /bin/cp -al /mnt/e/backup/hourly.0 /mnt/e/backup/hourly.1 failed (result 256, exit status 1).
[2022-01-11T15:37:35] /usr/bin/rsnapshot hourly: ERROR: Error! cp_al("/mnt/e/backup/hourly.0/", "/mnt/e/backup/hourly.1/")
[2022-01-11T15:37:35] rm -f /var/run/rsnapshot.pid

これについては、ググるといろいろと出てくるのですが、コピー先のディスク容量も inode も十分あるようだし、解決先がよくわからないです。

なので、仕方なく順番にディレクトリごとに比較してみて、何か手掛かりはないか探ってみます。

mor@DESKTOP-DE7IL4F:/mnt/e/backup$ diff -r -q ./hourly.0/localhost/home/ ./hourly.1/localhost/home/
./hourly.0/localhost/home/mor/work/cs50/week4/pset4/filter/less/filter のみに存在: images
./hourly.0/localhost/home/mor/work/cs50/week4/pset4/filter/more/filter のみに存在: images
./hourly.0/localhost/home/mor/work/cs50/week5/pset5/speller のみに存在: dictionaries
./hourly.0/localhost/home/mor/work/cs50/week5/pset5/speller のみに存在: keys
./hourly.0/localhost/home/mor/work/cs50/week5/pset5/speller のみに存在: texts
./hourly.0/localhost/home/mor/work/cs50/week6/pset6/dna/dna のみに存在: databases
./hourly.0/localhost/home/mor/work/cs50/week6/pset6/dna/dna のみに存在: sequences
mor@DESKTOP-DE7IL4F:/mnt/e/backup$
mor@DESKTOP-DE7IL4F:/mnt/e/backup$ diff -r -q ./hourly.0/localhost/mnt/c/ ./hourly.1/localhost/mnt/c/

ん?一部のファイルがコピーされていないのが見つかりました。

見てみると、

mor@DESKTOP-DE7IL4F:/etc$ cd /mnt/e/backup/hourly.0/localhost/home/mor/work/cs50/week4/pset4/filter/less/filter
mor@DESKTOP-DE7IL4F:/mnt/e/backup/hourly.0/localhost/home/mor/work/cs50/week4/pset4/filter/less/filter$ ls -l
合計 2884
-rwxrwxrwx 2 mor mor    330 107 22:00 Makefile
-rwxrwxrwx 2 mor mor   1755  929  2019 bmp.h
-rwxrwxrwx 2 mor mor  55424 107 22:09 filter
-rwxrwxrwx 2 mor mor   3493  929  2019 filter.c
-rwxrwxrwx 2 mor mor   2736 107 22:09 helpers.c
-rwxrwxrwx 2 mor mor    394  929  2019 helpers.h
lrwxrwxrwx 1 mor mor     21 107 16:43 images -> ../filter.org/images/
-rwxrwxrwx 2 mor mor 720054 107 22:09 out_blur.bmp
-rwxrwxrwx 2 mor mor 720054 107 22:01 out_gray.bmp
-rwxrwxrwx 2 mor mor 720054 107 22:02 out_reflect.bmp
-rwxrwxrwx 2 mor mor 720054 107 22:01 out_sepia.bmp
mor@DESKTOP-DE7IL4F:/mnt/e/backup/hourly.0/localhost/home/mor/work/cs50/week4/pset4/filter/less/filter$

cs50.jp の問題をいろいろと試した際、画像ファイルを入れたフォルダへのシンボリックリンクを張ってて、そのシンボリックリンクのコピーで失敗してるっぽいです。

一度、 cp -al をコマンドラインから試してみます。

mor@DESKTOP-DE7IL4F:/mnt/e/backup/hourly.0/localhost/home/mor/work/cs50/week4/pset4/filter/less/filter$ cp -al images /mnt/e/backup/hourly.1/localhost/home/mor/work/cs50/week4/pset4/filter/less/filter/
cp: '/mnt/e/backup/hourly.1/localhost/home/mor/work/cs50/week4/pset4/filter/less/filter/images' から 'images' へのハードリンクを作成できません: ディレクトリです
mor@DESKTOP-DE7IL4F:/mnt/e/backup/hourly.0/localhost/home/mor/work/cs50/week4/pset4/filter/less/filter$

エラーになりました。これが怪しいですね。

早速、調べてみました。 cp -al はハードリンクを生成するので、この場合はシンボリックリンク自体のハードリンクを生成しようとしてるようです。たぶん、 -a オプションがあると、 --no-dereference が有効になるようで、これがあるとシンボリックリンクはたどられないため、シンボリックリンク自体のハードリンクを生成しているんじゃないかなと推測されます。

だけど、NTFS の場合フォルダに対するハードリンクはできないようで、そのためにエラーになっているっぽいです。

これらをキーワードにして調べると、似たようなものが、 wsl の issue としても挙げられていました。

On drvfs 'cp -al' sometimes fails to hard link symlink-to-dir. 'linkat' returns EISDIR · Issue #6171 · microsoft/WSL · GitHub

となると、これに対する対応策は当面なさそうです。

さきほどのフォルダは大して重要でもないので、バックアップ対象から除外して、シンボリックリンクを含まないデータフォルダのみを対象にして実行するようにします。実際の指定方法は下記の通りとしました。

rsnapshot.conf の変更

バックアップ対象にシンボリックリンクを含まないようにするために、シンボリックリンクを含む一部のフォルダをバックアップ対象から除外してやればいいかと思います。

rsnapshot.conf の exclude を指定すると、その値が rsync に渡されて、除外対象になるようです。ただ、 exclude に書くと、すべての backup 対象で exclude オプションが有効になるようです。今回の場合は、問題のあるのは wsl のホームディレクトリ以下のフォルダなので、wsl のホームディレクトリのバックアップ時にのみ除外の条件を付加したいと思います。

rsnapshot.conf の書き方を調べると、backup の指定ごとに、 rsync 用のオプションを追加指定することができるようです。具体的には backup の指定の際に、 4 つ目のパラメータとして +rsync_long_args を書けばよいようです。そして、これに複数の exclude オプションを渡せばOKです。なお、複数の exclude を +rsync_long_args で指定する場合はスペース区切りで書くそうです。

これらを調整したものはこんな形になりました(デフォルトのものとの差分で示します)。

mor@DESKTOP-DE7IL4F:/etc$ diff rsnapshot.conf.org rsnapshot.conf
23c23
< snapshot_root /var/cache/rsnapshot/
---
> snapshot_root /mnt/e/backup/
63c63
< #cmd_du               /usr/bin/du
---
> cmd_du                /usr/bin/du
67c67
< #cmd_rsnapshot_diff   /usr/bin/rsnapshot-diff
---
> cmd_rsnapshot_diff    /usr/bin/rsnapshot-diff
93,95c93,95
< retain        alpha   6
< retain        beta    7
< retain        gamma   4
---
> #retain       alpha   6
> #retain       beta    7
> #retain       gamma   4
96a97,99
> retain        hourly  4
> retain        daily   5
> retain        weekly  14
116c119
< loglevel      3
---
> loglevel      5
121c124
< #logfile      /var/log/rsnapshot.log
---
> logfile       /var/log/rsnapshot.log
227,229c230,237
< backup        /home/          localhost/
< backup        /etc/           localhost/
< backup        /usr/local/     localhost/
---
> #backup       /home/          localhost/
> #backup       /etc/           localhost/
> #backup       /usr/local/     localhost/
> backup        /home/mor/              localhost/      +rsync_long_args=--exclude=/home/mor/work/ --exclude=/home/mor/tmp/ --exclude=/home/mor/.cache/
> backup        /mnt/c/Users/mor/bin/   localhost/
> backup        /mnt/d/avd/                     localhost/
> backup        /mnt/d/work/                    localhost/
> backup        /mnt/d/VirtualBox VMs/          localhost/
mor@DESKTOP-DE7IL4F:/etc$

なお、 rsnapshot のデフォルトだと rsync 呼び出し時のオプションとして --relative がつきます(man rsnapshot の rsync_long_args あたりをご覧ください)。このため、 --exclude オプションは絶対パスで書かないと、うまく除外できませんでした(man rsync の ANCHORING INCLUDE/EXCLUDE PATTERNS あたりのサンプルを見ると参考になります)。

再実行

ここまで調整して、再度実行してみます。 コピーに時間がかかるのはありますが、とりあえず問題なく動くようです。

なお、コピーに時間がかかるので、 cron.d/rsnapshot の hourly は3時間おきに実行するように修正しました。

4 */3           * * *           root    /usr/bin/rsnapshot hourly
32 11           * * *           root    /usr/bin/rsnapshot daily
2  11           * * 1           root    /usr/bin/rsnapshot weekly

なお、ファイルをオープンしていたりすると、トラブル1で示したのと同じ warning が出力されるのですが、これは致し方ないですね。まあ当面はこのままで運用してみようと思います。

残件

上記設定で使い始めるといくつか気になるところが出てきました。備忘録として、ここにまとめておきます。

処理が遅い

上記でも書きましたが、ファイルのコピーが非常に遅いようにも思えます。

  • 一番最初だと、約 600GB をコピーするのに、 4 時間近くかかってました
  • 2 回目以降のコピー時だと、処理全体でおおよそ 2 時間近くかかっており、なかでもハードリンクを生成する cp -al が 1 時間半近くかかってます

こんなものだといえば、こんなものなのかもしれません。

ですが、ちょっと調べてみると、どうも、 wsl2 から Windows 側のファイルを扱う時は、 9p というプロトコルを使っており、これが遅いようです。

StackExchange を見ると、 etx4 に変更すると早くなるようなことが書いてあります。

rsnapshot very slow - Unix & Linux Stack Exchange

フォーマットを NTFS から ext4 に変更しても、 Windows から直接 ext4 をマウントして利用することもできるので、試してみるのもありだと思いますが、今回はいったん保留にしておいて、また時間ができたときに挑戦しようと思います。

warning 発生時に通知が欲しい

再実行のところに書きましたが、ファイルを開いていたりすると warning が発生することがあります。

通常は大きな問題は無いはずなのですが、念のためこのような時は、通知を受け取りたいと思います。

PC 停止時の挙動

バックアップ処理にそれなりに時間がかかっているので、PCの電源を落とす際に、バックアップが動作中ということがあり得ます。例えば、 hourly のバックアップ動作中に、PC をシャットダウンすると

[2022-01-13T21:08:04] /bin/cp -al /mnt/e/backup/hourly.0 /mnt/e/backup/hourly.1
[2022-01-13T22:16:24] /usr/bin/rsnapshot hourly: ERROR: /bin/cp -al /mnt/e/backup/hourly.0 /mnt/e/backup/hourly.1 failed (result 256, exit status 1).
[2022-01-13T22:16:24] /usr/bin/rsnapshot hourly: ERROR: Error! cp_al("/mnt/e/backup/hourly.0/", "/mnt/e/backup/hourly.1/")
[2022-01-13T22:16:24] rm -f /var/run/rsnapshot.pid

のようなログを出して、停止していました。

上記の場合、 hourly.0 を hourly.1 にコピー(ハードリンクでのコピー)している途中でエラーになっています。そうなると、 hourly.1 の中身は不完全になっているので、削除するか手動で再度バックアップを取るかしたほうがよさそうです。

もちろん、いきなりシャットダウンするのでなくても、シグナルを送って停止させた場合でも、 cp -al の途中であれば、コピー先が不完全になるのは同じです。

どう対応するか、ちょっと悩ましいですね。

とりあえずは、運用としてバックアップ実行中にシャットダウンしないようにするぐらいかなー。いい方法がないか改めて検討してみたいと思います。

参考

今回は試しませんでしたが、 lsyncd を使って、リアルタイムにバックアップを作っていくというのもありました。

lsyncd と rsnapshot でリアルタイム Time Machine 風バックアップを組もう - Qiita

ご参考までに。

参考2(2022/1/15 追記)

第24回伊勢IT交流会で、この記事の内容をLT で話しました。その際のスライドも載せておきます。

www.slideshare.net

まとめ

コピーに時間がかかるなど問題もありますが、一応これで Windows のファイル履歴を使わずに、データドライブのバックアップを取ることができるようになりました。しばらく使ってみて、問題があるようなら、また見直したいと思います。