Skip to contentSkip to conversation

Errors from basic open_by_handle operations

PATCH In review Mark Hills 4 participants 8 messages Apr 9, 2015 – Apr 13, 2015

lore
Share & tools
lore

Mark Hills

author
#0 lore raw

I am having troubles with elementary file handle functions in libhandle.

A basic open_by_handle is giving "Bad file descriptor".

But I am suspicious of a side effect; using path_to_fshandle earlier in the program changes these errors to "Operation not permitted".

Is there a basic mistake in my use of these calls, or a bug/unmaintained code?

I am on an XFS filesystem (otherwise the first call fails with 'inappropriate ioctl'). The only documentation I can find is the man page; no mention about initialising the library, and I wasn't able to find any examples.

I'm on Scientific Linux 6.6 (like RedHat 6, kernel 2.6.32-504.1.3), and also tried updating to the latest xfsprogs from Git, with the same results.

Many thanks

Signature · 104 lines
Mark


$ ./test-xfs ~/scratch/tmp/xfs/file.c; echo $?
Handle 24 bytes: bd2c94ba959858e0000000870000000
readlink_by_handle: Bad file descriptor
open_by_handle: Bad file descriptor
0


$ ./test-xfs ~/scratch/tmp/xfs/file.c; echo $?
Handle 8 bytes: bd2c94ba959858
Handle 24 bytes: bd2c94ba959858e0000000870000000
readlink_by_handle: Operation not permitted
open_by_handle: Operation not permitted
0


/*
 * xfs file handle test
 *
 * compile with: gcc -o test-xfs test-xfs.c -lhandle -Wall
 */

#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <xfs/handle.h>

static void dump(FILE *f, void *m, size_t len)
{
	fprintf(f, "Handle %zu bytes: ", len);

	while (len--) {
		fprintf(f, "%hhx", *(unsigned char*)m);
		m++;
	}

	putchar('\n');
}

int main(int argc, char *argv[])
{
	int fd;
	char *pathname;
	void *hanp = NULL;
	size_t hlen;
	char buf[PATH_MAX];

	pathname = argv[1];

#if 0
	/*
	 * Switching this section on changes changes the
	 * errors from the later calls
	 */

	if (path_to_fshandle(pathname, &hanp, &hlen) == -1) {
		perror("path_to_fshandle");
		return -1;
	}

	dump(stderr, hanp, hlen);

	free_handle(hanp, hlen);
#endif

	if (path_to_handle(pathname, &hanp, &hlen) == -1) {
		perror("path_to_handle");
		return -1;
	}

	dump(stderr, hanp, hlen);

        /*
	 * The above calls were successful, but the next part always
	 * fails
	 */

	if (readlink_by_handle(hanp, hlen, buf, sizeof buf) == -1)
		perror("readlink_by_handle");
	else
		printf("Link: %s\n", buf);

	fd = open_by_handle(hanp, hlen, O_RDONLY);
	if (fd == -1) {
		perror("open_by_handle");
	} else {
		if (close(fd) == -1)
			abort();
	}

	free_handle(hanp, hlen);

	return 0;
}

_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
#1 lore raw

There's a small gotcha - the filesystem itself has to have been opened:

        void *xfs_handle = 0;
        size_t hlen  = 0;

        /* xfs library needs the filesystem to have been opened */

        if (path_to_fshandle(mountpoint, &xfs_handle, &hlen) < 0) {
                /* error */
                exit(4);
        }

        free(xfs_handle);
Quoted 21 lines · Mark Hills

I am having troubles with elementary file handle functions in libhandle.

A basic open_by_handle is giving "Bad file descriptor".

But I am suspicious of a side effect; using path_to_fshandle earlier in the program changes these errors to "Operation not permitted".

Is there a basic mistake in my use of these calls, or a bug/unmaintained code?

I am on an XFS filesystem (otherwise the first call fails with 'inappropriate ioctl'). The only documentation I can find is the man page; no mention about initialising the library, and I wasn't able to find any examples.

I'm on Scientific Linux 6.6 (like RedHat 6, kernel 2.6.32-504.1.3), and also tried updating to the latest xfsprogs from Git, with the same results.

Many thanks

Signature · 6 lines
Roger Willcocks <[email protected]>

_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
author
#2 lore raw
Quoted 13 lines · Roger Willcocks

There's a small gotcha - the filesystem itself has to have been opened:

        void *xfs_handle = 0;
        size_t hlen  = 0;

        /* xfs library needs the filesystem to have been opened */

        if (path_to_fshandle(mountpoint, &xfs_handle, &hlen) < 0) {
                /* error */
                exit(4);
        }

        free(xfs_handle);

Thank you Roger, that moves me one step but not to success

Now I know "Operation not permitted" is the correct message I assume that use of XFS file handles requires root.

But even as root, I cannot open a file with O_RDONLY:

  $ sudo ./test-xfs ~/scratch/tmp/xfs/file.c ; echo $?
  Handle 8 bytes: bd2c94ba959858
  Handle 24 bytes: bd2c94ba959858e0000000870000000
  readlink_by_handle: Not a directory
  open_by_handle: Not a directory
  0

I am able to do open_by_handle(O_RDONLY) on a directory though:

  $ sudo ./test-xfs ~/scratch/tmp/xfs/directory ; echo $?
  Handle 8 bytes: bd2c94ba959858
  Handle 24 bytes: bd2c94ba959858e0000000880000000
  readlink_by_handle: Invalid argument
  0

and a readlink_by_handle on a symlink works:

  $ sudo ./test-xfs ~/scratch/tmp/xfs/link.c ; echo $?
  Handle 8 bytes: bd2c94ba959858
  Handle 24 bytes: bd2c94ba959858e0000000860000000
  Link: fortress.c
  open_by_handle: Operation not permitted
  0

Switching to O_RDWR does not succeed in opening a file either, and also stops the directory case.

It seems possible flags are getting mangled and are not what I think they mean. The docs state the call as analogous to open(); is the 'oflags' argument actually ready to accept O_RDONLY etc. or some other set of flags? Because it seems like I can't actually open a file here.

Many thanks

Signature · 6 lines
Mark

_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
#3 lore raw
In reply to Mark Hills
Quoted 6 lines · Mark Hills

I am having troubles with elementary file handle functions in libhandle.

A basic open_by_handle is giving "Bad file descriptor".

But I am suspicious of a side effect; using path_to_fshandle earlier in the program changes these errors to "Operation not permitted".

EPERM. Root permissions are required to convert file handles back to file descriptors, as the handle could have been passed to anyone and open_by_handle has no directory based access/permission checks to determine if the user actually has permission to access the inode behind the filehandle.

Cheers,

Dave.

Signature · 7 lines
Dave Chinner
[email protected]

_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
#4 lore raw

PATCH 1/1 libhandle: document the need for path_to_handle

In reply to Mark Hills

The handle ioctls require an open file descriptor to the XFS mount directory. This file descriptor is found and supplied in the libhandle code by matching the entry added with a path_to_handle() call. Document the requirement and supply a simple example.

---
 man/man3/handle.3 |   70 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 69 insertions(+), 1 deletion(-)
man/man3/handle.3 +69 -1
Index: b/man/man3/handle.3
===================================================================
@@ -74,6 +74,12 @@ The
 function returns the handle for the filesystem in which the object given by the
 .I path
 argument resides.
+.I path
+must be the path to the mount point or
+.BR open_by_handle ()
+will return the
+.B ENOTDIR
+error.
 .PP
 The
 .BR fd_to_handle ()
@@ -95,7 +101,16 @@ The
 function opens a file descriptor for the object referenced by a handle.
 It is analogous and identical to
 .BR open (2)
-with the exception of accepting handles instead of path names.
+with the exception of accepting handles instead of path names. The returned
+file descriptor is opened to do invisible IO. Internally,
+.BR open_by_handle ()
+uses the mount point file descriptor that was saved by
+.BR path_to_fshandle ().
+Therefore,
+.BR path_to_fshandle ().
+must be called before calling
+.BR open_by_handle ().
+See below for an example.
 .PP
 The
 .BR readlink_by_handle ()
@@ -192,6 +207,59 @@ does not exist.
 .TP
 .B EPERM
 The caller does not have sufficient privileges.
+.SH EXAMPLE
+Example of
+.BR open_by_handle ().
+.PP
+.Vb 1
+\& main()
+.br
+\& {
+.br
+\&	int fd;
+.br
+\&	size_t hlen;
+.br
+\&	void *han;
+.br
+\&	size_t sz_int_used;
+.br
+\&	void *hdl_int_used;
+.br
+\&	char *mount_path = "/mnt/";
+.br
+\&	char *file = "file_to_open";
+.br
+\&	if (path_to_handle(file, &han, &hlen) < 0) {
+.br
+\&		perror("path-to-handle");
+.br
+\&		exit(1);
+.br
+\&	}
+.br
+\&	/*
+.br
+\&	 * path_to_fshandle saves an internal copy of the mount point's
+.br
+\&	 * (/mnt in this example) file descriptor. The open_by_handle call
+.br
+\&	 * looks up this internal file descriptor and uses it in the
+.br
+\&	 * xfsctl call to the kernel. Once path_to_fshandle is called,
+.br
+\&	 * this internal file descriptor remains open for the remaining
+.br
+\&	 * life of the application.
+.br
+\&	 */
+.br
+\&	path_to_fshandle(mount_path, &hdl_int_used, &sz_int_used);
+.br
+\&	fd = open_by_handle(han, hlen, O_RDWR);
+.br
+\&}
+.Ve
 .SH SEE ALSO
 .BR open (2),
 .BR readlink (2),

_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs

#5 lore raw

Re: [PATCH] libhandle: document the need for path_to_handle

Quoted 17 lines · On Thu, Apr 09, 2015 at 08:31:04AM -0500, [email protected] wrote:

The handle ioctls require an open file descriptor to the XFS mount directory. This file descriptor is found and supplied in the libhandle code by matching the entry added with a path_to_handle() call. Document the requirement and supply a simple example.

---
 man/man3/handle.3 |   70 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 69 insertions(+), 1 deletion(-)

Index: b/man/man3/handle.3
===================================================================

man/man3/handle.3 The · line 82

Quoted 9 lines
man/man3/handle.3 +6 -0
@@ -74,6 +74,12 @@ The
 function returns the handle for the filesystem in which the object given by the
 .I path
 argument resides.
+.I path
+must be the path to the mount point or
+.BR open_by_handle ()
+will return the
+.B ENOTDIR
+error.

This is wrong. ENOTDIR is only returned by open_by_handle if the cached fsfd is not a directory - it does not check if it's the root of a mount point at all. i.e, filesystem root is /mnt/scratch:

$ ls -l /mnt/scratch
total 4
-rw-r--r--.   1 root root    0 Apr 13 09:57 foo
drwxr-xr-x. 102 root root 4096 Apr 11 01:49 quota_dir
$
$ sudo ./fhtest /mnt/scratch /mnt/scratch/foo
open_by_handle: Success
$ sudo ./fhtest /mnt/scratch/foo /mnt/scratch/foo
open_by_handle: Not a directory
$ sudo ./fhtest /mnt/scratch/quota_dir/ /mnt/scratch/foo
open_by_handle: Success

So, as long as the fs path points to a directory on the filesystem in question, open_by_handle (and all the other handle functions) works just fine.

man/man3/handle.3 The · line 105

Quoted 10 lines
man/man3/handle.3 +2 -1
 .PP
 The
 .BR fd_to_handle ()
@@ -95,7 +101,16 @@ The
 function opens a file descriptor for the object referenced by a handle.
 It is analogous and identical to
 .BR open (2)
-with the exception of accepting handles instead of path names.
+with the exception of accepting handles instead of path names. The returned
+file descriptor is opened to do invisible IO. Internally,

Invisible IO is not defined anywhere in the man page, and most people will have no idea what it means. Either don't mention it, or define it properly first. For simplicity, I'd just omit it.

man/man3/handle.3 The · line 111

Quoted 6 lines
man/man3/handle.3 +6 -0
+.BR open_by_handle ()
+uses the mount point file descriptor that was saved by
+.BR path_to_fshandle ().
+Therefore,
+.BR path_to_fshandle ().
+must be called before calling

I don't think you need to mention anything about internal implemenation of libhandle, just that a call to path_to_fshandle() is required first.

Quoted 45 lines
man/man3/handle.3 +38 -0
+.BR open_by_handle ().
+See below for an example.
 .PP
 The
 .BR readlink_by_handle ()
@@ -192,6 +207,59 @@ does not exist.
 .TP
 .B EPERM
 The caller does not have sufficient privileges.
+.SH EXAMPLE
+Example of
+.BR open_by_handle ().
+.PP
+.Vb 1
+\& main()
+.br
+\& {
+.br
+\&	int fd;
+.br
+\&	size_t hlen;
+.br
+\&	void *han;
+.br
+\&	size_t sz_int_used;
+.br
+\&	void *hdl_int_used;
+.br
+\&	char *mount_path = "/mnt/";
+.br
+\&	char *file = "file_to_open";
+.br
+\&	if (path_to_handle(file, &han, &hlen) < 0) {
+.br
+\&		perror("path-to-handle");
+.br
+\&		exit(1);
+.br
+\&	}
+.br
+\&	/*
+.br
+\&	 * path_to_fshandle saves an internal copy of the mount point's
+.br
+\&	 * (/mnt in this example) file descriptor. The open_by_handle call

man/man3/handle.3 does not exist. · line 255

Quoted 10 lines
man/man3/handle.3 +10 -0
+.br
+\&	 * looks up this internal file descriptor and uses it in the
+.br
+\&	 * xfsctl call to the kernel. Once path_to_fshandle is called,
+.br
+\&	 * this internal file descriptor remains open for the remaining
+.br
+\&	 * life of the application.
+.br
+\&	 */

Again, this is internal implementation details, so isn't appropriate for a man page documenting an API.

Cheers,

Dave.

Signature · 7 lines
Dave Chinner
[email protected]

_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
#6 lore raw
In reply to Mark Hills

The code below works here on a CentOS 6.4 box ('test' is a file at the root of the volume):

$ ./a.out
hlen = 24
fd = -1
$ sudo ./a.out
hlen = 24
fd = 4

/* g++ handle_test.cpp -lhandle */

#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <xfs/handle.h>

int main(int argc, char *argv[])
{
void *xfs_handle = 0;
size_t hlen = 0;

  if (path_to_fshandle("/mnt/disk1", &xfs_handle, &hlen) < 0)
    exit(4);

  if (path_to_handle("/mnt/disk1/test", &xfs_handle, &hlen) < 0)
    exit(5);

  printf("hlen = %d\n", (int)hlen);

  int fd = open_by_handle(xfs_handle, hlen, O_RDWR);

printf("fd = %d\n", fd);
return 0;
}

Quoted 21 lines · Mark Hills

I am having troubles with elementary file handle functions in libhandle.

A basic open_by_handle is giving "Bad file descriptor".

But I am suspicious of a side effect; using path_to_fshandle earlier in the program changes these errors to "Operation not permitted".

Is there a basic mistake in my use of these calls, or a bug/unmaintained code?

I am on an XFS filesystem (otherwise the first call fails with 'inappropriate ioctl'). The only documentation I can find is the man page; no mention about initialising the library, and I wasn't able to find any examples.

I'm on Scientific Linux 6.6 (like RedHat 6, kernel 2.6.32-504.1.3), and also tried updating to the latest xfsprogs from Git, with the same results.

Many thanks

Signature · 6 lines
Roger Willcocks <[email protected]>

_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
author
#7 lore raw
Quoted 9 lines · Roger Willcocks

The code below works here on a CentOS 6.4 box ('test' is a file at the root of the volume):

$ ./a.out
hlen = 24
fd = -1
$ sudo ./a.out
hlen = 24
fd = 4

Yup, and I can reproduce that here on my system, thanks.

It seems the subtlety is rooted here:

Quoted 5 lines
  if (path_to_fshandle("/mnt/disk1", &xfs_handle, &hlen) < 0)
    exit(4);

  if (path_to_handle("/mnt/disk1/test", &xfs_handle, &hlen) < 0)
    exit(5);

This code is correct, and it looks like it's necessary to do path_to_fshandle on the file system root, otherwise it does not satisfy the precondition of open_by_handle().

So what I was doing:

  path_to_fshandle("/mnt/disk1/test-file" ... );
  ...
  path_to_handle("/mnt/disk1/test-file" ... );

even though it reports the expected success (and returns the right file handles), is not enough to allow open_by_handle() to work on a file.

It does leave me needing to have prior knowledge of the mounted filesystem root (or look it up); handle_to_fshandle() doesn't achieve the same.

Definitely some oddities here -- but now I have enough to get me started though I hope.

Thanks for all the help, and perhaps I can look at some patches to the man page as I go.

Thanks

Signature · 6 lines
Mark

_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs