[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: NFS_SUPER_MAGIC portability



On 09/25/2016 03:12 PM, Ole Streicher wrote:
> I have the problem that in a package (casacore) there is basically the
> following code:
> 
> ---------------------------------8<------------------------------------
> #include <sys/vfs.h>
> #include <linux/nfs_fs.h>
> 
> Bool Directory::isNFSMounted() const
> {
>    struct statfs buf;
>    if (statfs (itsFile.path().expandedName().chars(), &buf) < 0) {
>       throw (AipsError ("Directory::isNFSMounted error on " +
>             itsFile.path().expandedName() +
>             ": " + strerror(errno)));
>    }
>    return buf.f_type == NFS_SUPER_MAGIC;
> }
> ---------------------------------8<------------------------------------
> 
> The linux include subdir is obviously only available on Linux archs, not
> on kfreebsd or hurd. From the "statfs" manpage, I had the impression
> that the second include is just not needed; however then NFS_SUPER_MAGIC
> is not available.
> 
> So how do I do this portable (so that I could forward it to upstream as
> well)?

There's no easy way to make that portable. NFS_SUPER_MAGIC is Linux-
specific. statfs() is actually non-portable, and on e.g. FreeBSD
kernels the structure is slightly different (and you need to include
sys/param.h and sys/mount.h instead). Also, at least in a FreeBSD
10.3 VM of mine, the f_type field on an NFS mount is 0x3a - but I
have no idea whether that's guaranteed to be stable or is just some
number assigned dynamically. OTOH, struct statfs on FreeBSD has
f_fstypename, which is "nfs" for NFS mounts. Also, f_flags on
FreeBSD has MNT_LOCAL if it's a local mount, so you might want to
check that instead. On Hurd I have no idea, I've never tried NFS
there (but support exists).

So the only thing you can actually do realistically is to use lots
of #ifdefs, because file system detection is inherently unportable.

Basically, you'd need to do something like (untested, written down
in this email client):

----------------------------------------------------------
static int is_on_nfs (const char *file);

#ifdef __linux__

#include <sys/vfs.h>
#include <linux/nfs_fs.h>

int is_on_nfs (const char *file)
{
  struct statfs buf;
  if (statfs (file, &buf) < 0)
    return -1;
  return buf.f_type == NFS_SUPER_MAGIC;
}

#elif defined(__FreeBSD_kernel__)

#include <sys/mount.h>
#include <sys/param.h>
#include <stdlib.h>

int is_on_nfs (const char *file)
{
  struct statfs buf;
  if (statfs (file, &buf) < 0)
    return -1;
  return strcmp (buf.f_fstypename, "nfs") == 0;
}

#elif defined(__hurd__)

/* something else on Hurd */

#else

/* no idea how to detect NFS on this OS */

int is_on_nfs (const char *file)
{
  (void) file;
  return 0;
}

#endif

Bool Directory::isNFSMounted() const
{
   int result = is_on_nfs(itsFile.path().expandedName().chars());
   if (result < 0)
      throw (AipsError ("Directory::isNFSMounted error on " +
            itsFile.path().expandedName() +
            ": " + strerror(errno)));
   }
   return result != 0;
}
----------------------------------------------------------

The much more important question is: why do need this detection? Because
typically you want to detect NFS for one of the following reasons:

 - network filesystem -> slow -> don't do too much I/O there

 - lacks specific guarantees / features

In either case, NFS is not the only contender for this though. On Linux
there are lots of other possibilities here: there are other network
filesystems in the kernel, there are local filesystems that don't follow
POSIX guarantees (think e.g. vfat), there are a ton of FUSE filesystems
out there that support a varying number of features required by POSIX.
Plus, FUSE filesystems exist for both network (e.g. sshfs) or local
(think ntfs-3g). On Hurd, you can have arbitrary translators provide
the backing of a specific directory, and different translators support
a different degree of POSIX features.

Therefore, it might be a good idea to know _why_ you want to check for
NFS here? What's the use case? Perhaps there's a better and more
portable way to check for that specific thing.

Regards,
Christian


Reply to: