1 /*
2  * Net2FileSystem.cpp
3  *
4  * This source file is part of the FoundationDB open source project
5  *
6  * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *     http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20 
21 
22 #include "fdbrpc/Net2FileSystem.h"
23 
24 // Define boost::asio::io_service
25 #include <algorithm>
26 #define BOOST_SYSTEM_NO_LIB
27 #define BOOST_DATE_TIME_NO_LIB
28 #define BOOST_REGEX_NO_LIB
29 #include <boost/asio.hpp>
30 #include <boost/bind.hpp>
31 
32 #define FILESYSTEM_IMPL 1
33 
34 #include "fdbrpc/AsyncFileCached.actor.h"
35 #include "fdbrpc/AsyncFileEIO.actor.h"
36 #include "fdbrpc/AsyncFileWinASIO.actor.h"
37 #include "fdbrpc/AsyncFileKAIO.actor.h"
38 #include "flow/AsioReactor.h"
39 #include "flow/Platform.h"
40 #include "fdbrpc/AsyncFileWriteChecker.h"
41 
42 // Opens a file for asynchronous I/O
open(std::string filename,int64_t flags,int64_t mode)43 Future< Reference<class IAsyncFile> > Net2FileSystem::open( std::string filename, int64_t flags, int64_t mode )
44 {
45 #ifdef __linux__
46 	if (checkFileSystem) {
47 		dev_t fileDeviceId = getDeviceId(filename);
48 		if (fileDeviceId != this->fileSystemDeviceId) {
49 			TraceEvent(SevError, "DeviceIdMismatched").detail("FileSystemDeviceId", this->fileSystemDeviceId).detail("FileDeviceId", fileDeviceId);
50 			throw io_error();
51 		}
52 	}
53 #endif
54 
55 	if ( (flags & IAsyncFile::OPEN_EXCLUSIVE) ) ASSERT( flags & IAsyncFile::OPEN_CREATE );
56 	if (!(flags & IAsyncFile::OPEN_UNCACHED))
57 		return AsyncFileCached::open(filename, flags, mode);
58 
59 	Future<Reference<IAsyncFile>> f;
60 #ifdef __linux__
61 	// In the vast majority of cases, we wish to use Kernel AIO. However, some systems
62 	// dont properly support don’t properly support kernel async I/O without O_DIRECT
63 	// or AIO at all. In such cases, DISABLE_POSIX_KERNEL_AIO knob can be enabled to fallback to
64 	// EIO instead of Kernel AIO.
65 	if ((flags & IAsyncFile::OPEN_UNBUFFERED) && !(flags & IAsyncFile::OPEN_NO_AIO) &&
66 	    !FLOW_KNOBS->DISABLE_POSIX_KERNEL_AIO)
67 		f = AsyncFileKAIO::open(filename, flags, mode, NULL);
68 	else
69 #endif
70 	f = Net2AsyncFile::open(filename, flags, mode, static_cast<boost::asio::io_service*> ((void*) g_network->global(INetwork::enASIOService)));
71 	if(FLOW_KNOBS->PAGE_WRITE_CHECKSUM_HISTORY > 0)
72 		f = map(f, [=](Reference<IAsyncFile> r) { return Reference<IAsyncFile>(new AsyncFileWriteChecker(r)); });
73 	return f;
74 }
75 
76 // Deletes the given file.  If mustBeDurable, returns only when the file is guaranteed to be deleted even after a power failure.
deleteFile(std::string filename,bool mustBeDurable)77 Future< Void > Net2FileSystem::deleteFile( std::string filename, bool mustBeDurable )
78 {
79 	return Net2AsyncFile::deleteFile(filename, mustBeDurable);
80 }
81 
lastWriteTime(std::string filename)82 Future< std::time_t > Net2FileSystem::lastWriteTime( std::string filename ) {
83 	return Net2AsyncFile::lastWriteTime( filename );
84 }
85 
newFileSystem(double ioTimeout,std::string fileSystemPath)86 void Net2FileSystem::newFileSystem(double ioTimeout, std::string fileSystemPath)
87 {
88 	g_network->setGlobal(INetwork::enFileSystem, (flowGlobalType) new Net2FileSystem(ioTimeout, fileSystemPath));
89 }
90 
Net2FileSystem(double ioTimeout,std::string fileSystemPath)91 Net2FileSystem::Net2FileSystem(double ioTimeout, std::string fileSystemPath)
92 {
93 	Net2AsyncFile::init();
94 #ifdef __linux__
95 	AsyncFileKAIO::init( Reference<IEventFD>(N2::ASIOReactor::getEventFD()), ioTimeout );
96 
97 	if (fileSystemPath.empty()) {
98 		checkFileSystem = false;
99 	} else {
100 		checkFileSystem = true;
101 
102 		try {
103 			this->fileSystemDeviceId = getDeviceId(fileSystemPath);
104 			if (fileSystemPath != "/") {
105 				dev_t fileSystemParentDeviceId = getDeviceId(parentDirectory(fileSystemPath));
106 				if (this->fileSystemDeviceId == fileSystemParentDeviceId) {
107 					criticalError(FDB_EXIT_ERROR, "FileSystemError", format("`%s' is not a mount point", fileSystemPath.c_str()).c_str());
108 				}
109 			}
110 		} catch (Error& e) {
111 			criticalError(FDB_EXIT_ERROR, "FileSystemError", format("Could not get device id from `%s'", fileSystemPath.c_str()).c_str());
112 		}
113 	}
114 #endif
115 }
116