Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / os / fs / FS.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 /*
4  * Ceph - scalable distributed file system
5  *
6  * Copyright (C) 2014 Red Hat
7  *
8  * This is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License version 2.1, as published by the Free Software
11  * Foundation.  See file COPYING.
12  *
13  */
14
15 #include <errno.h>
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 #include <fcntl.h>
19
20 // from include/linux/falloc.h:
21 #ifndef FALLOC_FL_PUNCH_HOLE
22 # define FALLOC_FL_PUNCH_HOLE 0x2
23 #endif
24
25 #include "FS.h"
26
27 #include "acconfig.h"
28
29 #ifdef HAVE_LIBXFS
30 #include "XFS.h"
31 #endif
32
33 #if defined(DARWIN) || defined(__FreeBSD__)
34 #include <sys/mount.h>
35 #else
36 #include <sys/vfs.h>
37 #endif
38 #include "include/compat.h"
39
40 // ---------------
41
42 FS *FS::create(uint64_t f_type)
43 {
44   switch (f_type) {
45 #ifdef HAVE_LIBXFS
46   case XFS_SUPER_MAGIC:
47     return new XFS;
48 #endif
49   default:
50     return new FS;
51   }
52 }
53
54 FS *FS::create_by_fd(int fd)
55 {
56   struct statfs st;
57   ::fstatfs(fd, &st);
58   return create(st.f_type);
59 }
60
61 // ---------------
62
63 int FS::set_alloc_hint(int fd, uint64_t hint)
64 {
65   return 0;  // no-op
66 }
67
68 #ifdef HAVE_NAME_TO_HANDLE_AT
69 int FS::get_handle(int fd, std::string *h)
70 {
71   char buf[sizeof(struct file_handle) + MAX_HANDLE_SZ];
72   struct file_handle *fh = (struct file_handle *)buf;
73   int mount_id;
74
75   fh->handle_bytes = MAX_HANDLE_SZ;
76   int r = name_to_handle_at(fd, "", fh, &mount_id, AT_EMPTY_PATH);
77   if (r < 0) {
78     return -errno;
79   }
80   *h = std::string(buf, fh->handle_bytes + sizeof(struct file_handle));
81   return 0;
82 }
83
84 int FS::open_handle(int mount_fd, const std::string& h, int flags)
85 {
86   if (h.length() < sizeof(struct file_handle)) {
87     return -EINVAL;
88   }
89   struct file_handle *fh = (struct file_handle *)h.data();
90   if (fh->handle_bytes > h.length()) {
91     return -ERANGE;
92   }
93   int fd = open_by_handle_at(mount_fd, fh, flags);
94   if (fd < 0)
95     return -errno;
96   return fd;
97 }
98
99 #else // HAVE_NAME_TO_HANDLE_AT
100
101 int FS::get_handle(int fd, std::string *h)
102 {
103   return -EOPNOTSUPP;
104 }
105
106 int FS::open_handle(int mount_fd, const std::string& h, int flags)
107 {
108   return -EOPNOTSUPP;
109 }
110
111 #endif // HAVE_NAME_TO_HANDLE_AT
112
113 int FS::copy_file_range(int to_fd, uint64_t to_offset,
114                         int from_fd,
115                         uint64_t from_offset, uint64_t from_len)
116 {
117   assert(0 == "write me");
118 }
119
120 int FS::zero(int fd, uint64_t offset, uint64_t length)
121 {
122   int r;
123
124   /*
125
126     From the fallocate(2) man page:
127
128        Specifying the FALLOC_FL_PUNCH_HOLE flag (available since Linux 2.6.38)
129        in mode deallocates space (i.e., creates a  hole)  in  the  byte  range
130        starting  at offset and continuing for len bytes.  Within the specified
131        range, partial filesystem  blocks  are  zeroed,  and  whole  filesystem
132        blocks  are removed from the file.  After a successful call, subsequent
133        reads from this range will return zeroes.
134
135        The FALLOC_FL_PUNCH_HOLE flag must be ORed with FALLOC_FL_KEEP_SIZE  in
136        mode;  in  other words, even when punching off the end of the file, the
137        file size (as reported by stat(2)) does not change.
138
139        Not all  filesystems  support  FALLOC_FL_PUNCH_HOLE;  if  a  filesystem
140        doesn't  support the operation, an error is returned.  The operation is
141        supported on at least the following filesystems:
142
143        *  XFS (since Linux 2.6.38)
144
145        *  ext4 (since Linux 3.0)
146
147        *  Btrfs (since Linux 3.7)
148
149        *  tmpfs (since Linux 3.5)
150
151    So: we only do this is PUNCH_HOLE *and* KEEP_SIZE are defined.
152
153   */
154 #if !defined(DARWIN) && !defined(__FreeBSD__)
155 # ifdef CEPH_HAVE_FALLOCATE
156 #  ifdef FALLOC_FL_KEEP_SIZE
157   // first try fallocate
158   r = fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, offset, length);
159   if (r < 0) {
160     r = -errno;
161   }
162   if (r != -EOPNOTSUPP) {
163     goto out;  // a real error
164   }
165   // if that failed (-EOPNOTSUPP), fall back to writing zeros.
166 #  endif
167 # endif
168 #endif
169
170   {
171     // fall back to writing zeros
172     bufferlist bl;
173     bl.append_zero(length);
174     r = ::lseek64(fd, offset, SEEK_SET);
175     if (r < 0) {
176       r = -errno;
177       goto out;
178     }
179     r = bl.write_fd(fd);
180   }
181
182  out:
183   return r;
184 }
185
186 // ---------------
187