2

currently i have a setup with two hardrives, one with xfs, the other one with btrfs on it. The root fs is mounted on the xfs, and the btrfs under /data. For verious reasons, the directory /var/www on the xfs was replaced by a bind mount to /data/var/www. (mount -o bind /data/var/www /var/www) So if you look in both directories (/var/www & /data/var/www) its exactly the same content.

To my surprise some btrfs tools cannot handle bind mounted pathes, so whatever i i do i need for certain situations that the given path "/var/ww" is canonicalized to "/data/var/www" How can i do that with a shell tool? something like resolve /var/www which would then return /data/var/www (or if there is more than one bind mount, it would return the proper path.

Mandragor
  • 1,060
  • What do you mean by “cannot handle bind mounted pathes (sic)”? Bind mounts are like hard links: the two (or more) mount points are equivalent, there ins't one that's “proper”. What is the real problem? – Gilles 'SO- stop being evil' Feb 06 '16 at 23:20
  • btrfs show (btrfs-progs-3.19.1) cannot handle bind mounts. try it. it works on /data/var/www, but not on the bind mounted /var/www. As soon as you start to work on a "real filesystem" (meaning looking up snapshots in btrfs, or simple volume data of btrfs) it fails. Especially the setup i have described up there (which i cannot change), a lot of workarounds need to be done to make everything work properly. E.g. if you bind mount, snapshot under bind mount, bind again under the snapshot... You think this is crazy? Run docker in a docker container on btrfs ;) – Mandragor Feb 07 '16 at 08:27
  • Once again, there's no such thing as a “bind mount”. Is the problem maybe that btrfs doesn't work on submounts? A submount is mounting a subtree of a file system, and it's usually done with mount --bind. Is /var/www itself a mount point? If not, you have a submount, and that might be what btrfs tools have trouble with. If the problem is submounts, finding a mount point for the original can't be done in general, because it might not even exist. But something might work for your setup. Explain your setup instead of focusing on the wrong issue. – Gilles 'SO- stop being evil' Feb 07 '16 at 13:51
  • ;) Google ist your friend. please inform yourself about bind mounts link or bindMounts . Once you understood this, read the C code of the btrfs tools (which i did to investigate the issue). Fact 1: Bind mounts exist. Fact 2: There is no code in btrfs progrs, which deals with bind mounts. Fact 3: Try to run it btrfs and falsify any facts stated here. – Mandragor Feb 07 '16 at 15:06

2 Answers2

1
df --output=source /var/www

Gives you the device. In case of btrfs is does not give you the subvolume, though. But maybe the device is enough for you.

If there is only one mount for the device then you can get it with this command:

awk -v dev=/dev/mapper/backup '$1==dev { count++; path=$2; } END { if(count==1) print path; else exit 1; }' /proc/mounts
Hauke Laging
  • 90,279
  • nice idea, seems my environment is a little bit harder, it has more than one bind mount from the /data device to the original. Therefore your idea would work, if only one mount would be there (but count becomes actually 3 here) – Mandragor Feb 06 '16 at 17:50
0

This what i came up with. It resolves the "bind mount". if you run resolve.sh /var/www , it will return "/data/var/www". Probably this should be done recursively from bottom up for any given path, if there is more than one bind mount in the pat. But i leave that to somebody who needs it. Now you can throw the result (/data/var/www) at btrfs. btrfs show /data/var/www works, while the bind mounted /var/www still returns no result with btrfs show /var/www.

#!/bin/sh
# Script name: resolve.sh path
function find_bind_mount
{
  RESULT=$(findmnt -c -n "$1"|grep "\[.*\]")
  RET=$?

  # Did we check "/" and did not find any bind mounts
  if [ "$1" == "/"  -a $RET != 0 ]; then
    return 1
  fi

  # so if we didn't find a bind mount check parent directory
  if [ $RET != 0 ]; then
    find_bind_mount $(dirname "$1")
    return $?
  else
    echo "$RESULT"|sed -r "s:^([^ ]+) ([^\[]+)\[([^]]+)(.*)$:\1\t\2\t\3:g"
    return 0
  fi
}

function resolve_bind_mount
{
  local TARGET="$1"

  local RESULT=$(find_bind_mount "$TARGET")
  local PARENT_DIR_ORIG=$(awk '{ print $1;}' <<<"$RESULT")
  local PARENT=$(awk '{ print $2;}' <<<"$RESULT")
  local PARENT_DIR1=$(awk '{ print $3;}' <<<"$RESULT")
  local PARENT_DIR2=$(findmnt -c -n  "$PARENT"  |grep -v "\[.*\]"|awk '{ print $1;}')
  local PARENT_DIR_NEW="$PARENT_DIR2$PARENT_DIR1"

  echo $(sed "s:$PARENT_DIR_ORIG:$PARENT_DIR_NEW:" <<<"$TARGET")

}

resolve_bind_mount "$1"
Mandragor
  • 1,060