1    	/*
2    	 *   Copyright (C) International Business Machines  Corp., 2010
3    	 *   Author(s): Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
4    	 *
5    	 *   This library is free software; you can redistribute it and/or modify
6    	 *   it under the terms of the GNU Lesser General Public License as published
7    	 *   by the Free Software Foundation; either version 2.1 of the License, or
8    	 *   (at your option) any later version.
9    	 *
10   	 *   This library is distributed in the hope that it will be useful,
11   	 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   	 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
13   	 *   the GNU Lesser General Public License for more details.
14   	 *
15   	 *   You should have received a copy of the GNU Lesser General Public License
16   	 *   along with this library; if not, write to the Free Software
17   	 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18   	 */
19   	
20   	/**
21   	 * @file FSAL/FSAL_VFS/os/linux/handle_syscalls.c
22   	 * @brief System calls for the Linux handle calls
23   	 *
24   	 */
25   	
26   	#include "fsal.h"
27   	#include "fsal_api.h"
28   	#include "fsal_convert.h"
29   	#include "FSAL/fsal_commonlib.h"
30   	#include "../../vfs_methods.h"
31   	
32   	/* We can at most support 40 byte handles, which are the largest known.
33   	 * We also expect handles to be at least 4 bytes.
34   	 */
35   	#define VFS_MAX_HANDLE 48
36   	#define VFS_MIN_HANDLE_SIZE 4
37   	
38   	/* Visual handle format
39   	 *
40   	 * 1 byte		handle_len (doesn't go on wire)
41   	 * 1 byte		flags
42   	 *				00xxxxxx fsid_type
43   	 *				01000000 handle_type fits in one byte
44   	 *				10000000 handle_type fits in two bytes
45   	 *				11000000 handle_type fits in four bytes
46   	 */
47   	#define HANDLE_TYPE_8 0x40
48   	#define HANDLE_TYPE_16 0x80
49   	#define HANDLE_TYPE_32 0xC0
50   	#define HANDLE_TYPE_MASK 0xC0
51   	#define HANDLE_DUMMY 0x20
52   	#define HANDLE_FSID_MASK (~(HANDLE_TYPE_MASK | HANDLE_DUMMY))
53   	 /*
54   	 * 0, 8, or 16 bytes	fsid type
55   	 * 1,2 or 4 bytes	handle type
56   	 * 12 to 40 bytes	opaque kernel handle
57   	 *
58   	 * NOTE: if handle type doesn't fit in 2 bytes or less, 40 byte handles
59   	 *	 (BTRFS and GPFS are known file systems that use 40 bytes) are
60   	 *	 incompatible with 16 byte uuid form fsids.
61   	 *	 If VMware clients are concerned, the limit is 8 bytes less...
62   	 */
63   	
64   	int display_vfs_handle(struct display_buffer *dspbuf,
65   			       struct vfs_file_handle *fh)
66   	{
67   		int16_t i16;
68   		int32_t i32;
69   		uint32_t u32[2];
70   		uint64_t u64[2];
71   		uint8_t handle_cursor = 1;
72   		int b_left;
73   	
74   		b_left = display_printf(dspbuf, "Handle len %hhu 0x%02hhx: ",
75   					fh->handle_len, fh->handle_data[0]);
76   	
77   		if (b_left <= 0)
78   			return b_left;
79   	
80   		switch ((enum fsid_type) fh->handle_data[0] & HANDLE_FSID_MASK) {
81   		case FSID_NO_TYPE:
82   			b_left = display_cat(dspbuf, "no fsid");
83   			break;
84   	
85   		case FSID_ONE_UINT64:
86   		case FSID_MAJOR_64:
87   			memcpy(u64,
88   			       fh->handle_data + handle_cursor,
89   			       sizeof(u64[0]));
90   			handle_cursor += sizeof(u64[0]);
91   			b_left = display_printf(dspbuf,
92   						"fsid=0x%016"PRIx64
93   						".0x0000000000000000",
94   						u64[0]);
95   			break;
96   	
97   		case FSID_TWO_UINT64:
98   			memcpy(u64,
99   			       fh->handle_data + handle_cursor,
100  			       sizeof(u64));
101  			handle_cursor += sizeof(u64);
102  			b_left = display_printf(dspbuf,
103  						"fsid=0x%016"PRIx64".0x%016"PRIx64,
104  						u64[0], u64[1]);
105  			break;
106  	
107  		case FSID_TWO_UINT32:
108  		case FSID_DEVICE:
109  			memcpy(u32,
110  			       fh->handle_data + handle_cursor,
111  			       sizeof(u32));
112  			handle_cursor += sizeof(u32);
113  			b_left = display_printf(dspbuf,
114  						"fsid=0x%016"PRIx64".0x%016"PRIx64,
(1) Event invalid_type: Argument "uint32_t[1]" to format specifier "%016lx" was expected to have type "unsigned long" but has type "unsigned int". [details]
115  						u32[0], u32[1]);
116  			break;
117  		}
118  	
119  		if (b_left <= 0)
120  			return b_left;
121  	
122  		if ((fh->handle_data[0] & HANDLE_DUMMY) != 0)
123  			return display_cat(dspbuf, ", DUMMY");
124  	
125  		switch (fh->handle_data[0] & HANDLE_TYPE_MASK) {
126  		case 0:
127  			b_left = display_cat(dspbuf, ", invalid type");
128  			break;
129  	
130  		case HANDLE_TYPE_8:
131  			b_left = display_printf(dspbuf, ", type 0x%02hhx",
132  						fh->handle_data[handle_cursor]);
133  			handle_cursor++;
134  			break;
135  		case HANDLE_TYPE_16:
136  			memcpy(&i16,
137  			       fh->handle_data + handle_cursor,
138  			       sizeof(i16));
139  			handle_cursor += sizeof(i16);
140  			b_left = display_printf(dspbuf, ", type 0x%04h"PRIx16, i16);
141  			break;
142  		case HANDLE_TYPE_32:
143  			memcpy(&i32,
144  			       fh->handle_data + handle_cursor,
145  			       sizeof(i32));
146  			handle_cursor += sizeof(i32);
147  			b_left = display_printf(dspbuf, ", type 0x%04"PRIx32, i32);
148  			break;
149  		}
150  	
151  		if (b_left <= 0)
152  			return b_left;
153  	
154  		b_left = display_cat(dspbuf, ", opaque: ");
155  	
156  		if (b_left <= 0)
157  			return b_left;
158  	
159  		return display_opaque_value(dspbuf,
160  					    fh->handle_data + handle_cursor,
161  					    fh->handle_len - handle_cursor);
162  	}
163  	
164  	#define LogVFSHandle(fh)						\
165  		do {								\
166  			if (isMidDebug(COMPONENT_FSAL)) {			\
167  				char buf[256] = "\0";				\
168  				struct display_buffer dspbuf =			\
169  						{sizeof(buf), buf, buf};	\
170  										\
171  				display_vfs_handle(&dspbuf, fh);		\
172  										\
173  				LogMidDebug(COMPONENT_FSAL, "%s", buf);		\
174  			}							\
175  		} while (0)
176  	
177  	int vfs_map_name_to_handle_at(int fd,
178  				      struct fsal_filesystem *fs,
179  				      const char *path,
180  				      vfs_file_handle_t *fh,
181  				      int flags)
182  	{
183  		struct file_handle *kernel_fh;
184  		int32_t i32;
185  		int rc;
186  		int mnt_id;
187  	
188  		kernel_fh = alloca(sizeof(struct file_handle) + VFS_MAX_HANDLE);
189  	
190  		kernel_fh->handle_bytes = VFS_MAX_HANDLE;
191  	
192  		rc = name_to_handle_at(fd, path, kernel_fh, &mnt_id, flags);
193  	
194  		if (rc < 0) {
195  			int err = errno;
196  	
197  			LogDebug(COMPONENT_FSAL,
198  				 "Error %s (%d) bytes = %d",
199  				 strerror(err), err, (int) kernel_fh->handle_bytes);
200  			errno = err;
201  			return rc;
202  		}
203  	
204  		/* Init flags with fsid type */
205  		fh->handle_data[0] = fs->fsid_type;
206  		fh->handle_len = 1;
207  	
208  		/* Pack fsid into wire handle */
209  		rc = encode_fsid(fh->handle_data + 1,
210  				 sizeof_fsid(fs->fsid_type),
211  				 &fs->fsid,
212  				 fs->fsid_type);
213  	
214  		if (rc < 0) {
215  			errno = EINVAL;
216  			return rc;
217  		}
218  	
219  		fh->handle_len += rc;
220  	
221  		/* Pack handle type into wire handle */
222  		if (kernel_fh->handle_type <= UINT8_MAX) {
223  			/* Copy one byte in and advance cursor */
224  			fh->handle_data[fh->handle_len] =
225  						kernel_fh->handle_type;
226  			fh->handle_len++;
227  			fh->handle_data[0] |= HANDLE_TYPE_8;
228  		} else if (kernel_fh->handle_type <= INT16_MAX &&
229  			   kernel_fh->handle_type >= INT16_MIN) {
230  			/* Type fits in 16 bits */
231  			int16_t handle_type_16 = kernel_fh->handle_type;
232  	
233  			memcpy(fh->handle_data + fh->handle_len,
234  			       &handle_type_16,
235  			       sizeof(handle_type_16));
236  			fh->handle_len += sizeof(handle_type_16);
237  			fh->handle_data[0] |= HANDLE_TYPE_16;
238  		} else  {
239  			/* Type needs whole 32 bits */
240  			i32 = kernel_fh->handle_type;
241  			memcpy(fh->handle_data + fh->handle_len,
242  			       &i32,
243  			       sizeof(i32));
244  			fh->handle_len += sizeof(i32);
245  			fh->handle_data[0] |= HANDLE_TYPE_32;
246  		}
247  	
248  		/* Pack opaque handle into wire handle */
249  		if (fh->handle_len + kernel_fh->handle_bytes > VFS_HANDLE_LEN) {
250  			/* We just can't fit this handle... */
251  			errno = EOVERFLOW;
252  			return -1;
253  		} else {
254  			memcpy(fh->handle_data + fh->handle_len,
255  			       kernel_fh->f_handle,
256  			       kernel_fh->handle_bytes);
257  			fh->handle_len += kernel_fh->handle_bytes;
258  		}
259  	
260  		LogVFSHandle(fh);
261  	
262  		return 0;
263  	}
264  	
265  	int vfs_open_by_handle(struct vfs_filesystem *vfs_fs,
266  			       vfs_file_handle_t *fh, int openflags,
267  			       fsal_errors_t *fsal_error)
268  	{
269  		struct file_handle *kernel_fh;
270  		uint8_t handle_cursor = sizeof_fsid(vfs_fs->fs->fsid_type) + 1;
271  		int16_t i16;
272  		int32_t i32;
273  		int fd;
274  	
275  		LogFullDebug(COMPONENT_FSAL,
276  			     "vfs_fs = %s root_fd = %d",
277  			     vfs_fs->fs->path, vfs_fs->root_fd);
278  	
279  		LogVFSHandle(fh);
280  	
281  		kernel_fh = alloca(sizeof(struct file_handle) + VFS_MAX_HANDLE);
282  	
283  		switch (fh->handle_data[0] & HANDLE_TYPE_MASK) {
284  		case 0:
285  			LogDebug(COMPONENT_FSAL,
286  				 "Invaliid handle type = 0");
287  			errno = EINVAL;
288  			fd = -1;
289  			goto out;
290  		case HANDLE_TYPE_8:
291  			kernel_fh->handle_type = fh->handle_data[handle_cursor];
292  			handle_cursor++;
293  			break;
294  		case HANDLE_TYPE_16:
295  			memcpy(&i16,
296  			       fh->handle_data + handle_cursor,
297  			       sizeof(i16));
298  			handle_cursor += sizeof(i16);
299  			kernel_fh->handle_type = i16;
300  			break;
301  		case HANDLE_TYPE_32:
302  			memcpy(&i32,
303  			       fh->handle_data + handle_cursor,
304  			       sizeof(i32));
305  			handle_cursor += sizeof(i32);
306  			kernel_fh->handle_type = i32;
307  			break;
308  		}
309  	
310  		kernel_fh->handle_bytes = fh->handle_len - handle_cursor;
311  		memcpy(kernel_fh->f_handle,
312  		       fh->handle_data + handle_cursor,
313  		       kernel_fh->handle_bytes);
314  	
315  		fd = open_by_handle_at(vfs_fs->root_fd, kernel_fh, openflags);
316  	
317  	out:
318  		if (fd < 0) {
319  			fd = -errno;
320  			if (fd == -ENOENT)
321  				fd = -ESTALE;
322  			*fsal_error = posix2fsal_error(-fd);
323  			LogDebug(COMPONENT_FSAL, "Failed with %s openflags 0x%08x",
324  				 strerror(-fd), openflags);
325  		} else {
326  			LogFullDebug(COMPONENT_FSAL, "Opened fd %d", fd);
327  		}
328  	
329  		return fd;
330  	}
331  	
332  	int vfs_fd_to_handle(int fd, struct fsal_filesystem *fs,
333  			     vfs_file_handle_t *fh)
334  	{
335  		return vfs_map_name_to_handle_at(fd, fs, "", fh, AT_EMPTY_PATH);
336  	}
337  	
338  	int vfs_name_to_handle(int atfd,
339  			       struct fsal_filesystem *fs,
340  			       const char *name,
341  			       vfs_file_handle_t *fh)
342  	{
343  		return vfs_map_name_to_handle_at(atfd, fs, name, fh, 0);
344  	}
345  	
346  	int vfs_extract_fsid(vfs_file_handle_t *fh,
347  			     enum fsid_type *fsid_type,
348  			     struct fsal_fsid__ *fsid)
349  	{
350  		LogVFSHandle(fh);
351  	
352  		*fsid_type = (enum fsid_type) fh->handle_data[0] & HANDLE_FSID_MASK;
353  	
354  		if (decode_fsid(fh->handle_data + 1,
355  				fh->handle_len - 1,
356  				fsid,
357  				*fsid_type) < 0)
358  			return ESTALE;
359  		else
360  			return 0;
361  	}
362  	
363  	int vfs_encode_dummy_handle(vfs_file_handle_t *fh,
364  				    struct fsal_filesystem *fs)
365  	{
366  		int rc;
367  	
368  		/* Init flags with fsid type */
369  		fh->handle_data[0] = fs->fsid_type | HANDLE_DUMMY;
370  		fh->handle_len = 1;
371  	
372  		/* Pack fsid into wire handle */
373  		rc = encode_fsid(fh->handle_data + 1,
374  				 sizeof_fsid(fs->fsid_type),
375  				 &fs->fsid,
376  				 fs->fsid_type);
377  	
378  		if (rc < 0) {
379  			errno = EINVAL;
380  			return rc;
381  		}
382  	
383  		fh->handle_len += rc;
384  	
385  		LogVFSHandle(fh);
386  	
387  		return 0;
388  	}
389  	
390  	bool vfs_is_dummy_handle(vfs_file_handle_t *fh)
391  	{
392  		return (fh->handle_data[0] & HANDLE_DUMMY) != 0;
393  	}
394  	
395  	bool vfs_valid_handle(struct gsh_buffdesc *desc)
396  	{
397  		uint8_t handle0;
398  		int len = 1; /* handle_type */
399  		bool fsid_type_ok = false;
400  		bool ok;
401  	
402  		if (desc->addr == NULL) {
403  			LogDebug(COMPONENT_FSAL,
404  				 "desc->addr == NULL");
405  			return false;
406  		}
407  	
408  		if (desc->len > VFS_HANDLE_LEN) {
409  			LogDebug(COMPONENT_FSAL,
410  				 "desc->len %d > VFS_HANDLE_LEN",
411  				 (int) desc->len);
412  			return false;
413  		}
414  	
415  		handle0 = *((uint8_t *) (desc->addr));
416  	
417  		switch ((enum fsid_type) handle0 & HANDLE_FSID_MASK) {
418  		case FSID_NO_TYPE:
419  		case FSID_ONE_UINT64:
420  		case FSID_MAJOR_64:
421  		case FSID_TWO_UINT64:
422  		case FSID_TWO_UINT32:
423  		case FSID_DEVICE:
424  			fsid_type_ok = true;
425  			len += sizeof_fsid((enum fsid_type) handle0 &
426  							    HANDLE_FSID_MASK);
427  			break;
428  		}
429  	
430  		if (!fsid_type_ok) {
431  			LogDebug(COMPONENT_FSAL,
432  				 "FSID Type %02hhx invalid",
433  				 (uint8_t) (handle0 & HANDLE_FSID_MASK));
434  			return false;
435  		}
436  	
437  		if ((handle0 & HANDLE_DUMMY) != 0) {
438  			ok = len == desc->len;
439  			if (!ok) {
440  				LogDebug(COMPONENT_FSAL,
441  					 "Len %d != desc->len %d for DUMMY handle",
442  					 len, (int) desc->len);
443  			}
444  	
445  			return ok;
446  		}
447  	
448  		/* min kernel handle size */
449  		len += sizeof(uint32_t);
450  	
451  		switch (handle0 & HANDLE_TYPE_MASK) {
452  		case HANDLE_TYPE_8:
453  			len += sizeof(uint8_t);
454  			break;
455  		case HANDLE_TYPE_16:
456  			len += sizeof(int16_t);
457  			break;
458  		case HANDLE_TYPE_32:
459  			len += sizeof(int32_t);
460  			break;
461  		default:
462  			LogDebug(COMPONENT_FSAL,
463  				 "Handle Type %02hhx invalid",
464  				 (uint8_t) (handle0 & HANDLE_TYPE_MASK));
465  			return false;
466  		}
467  	
468  		ok = (len + VFS_MIN_HANDLE_SIZE) <= desc->len;
469  		if (!ok) {
470  			LogDebug(COMPONENT_FSAL,
471  				 "Len %d + VFS_MIN_HANDLE_SIZE %d > desc->len %d",
472  				 len, len + VFS_MIN_HANDLE_SIZE, (int) desc->len);
473  			return false;
474  		}
475  		ok = (len + VFS_MAX_HANDLE) >= desc->len;
476  		if (!ok) {
477  			LogDebug(COMPONENT_FSAL,
478  				 "Len %d + VFS_MAX_HANDLE %d < desc->len %d",
479  				 len, len + VFS_MAX_HANDLE, (int) desc->len);
480  		}
481  		return true;
482  	}
483  	
484  	int vfs_re_index(struct vfs_filesystem *vfs_fs,
485  			 struct vfs_fsal_export *exp)
486  	{
487  		return 0;
488  	}
489  	
490  	/** @} */
491