Add subcommand getpath to eden debug

Summary: Add a command to lookup the path for an inode given the inode number and eden mount path.

Reviewed By: bolinfest

Differential Revision: D5627411

fbshipit-source-id: 25928f506d3f48d8a6784fe81fb17fa0500d6bc9
This commit is contained in:
Braden Watling 2017-08-16 19:56:32 -07:00 committed by Facebook Github Bot
parent 322cad1e8a
commit cf297e0106
5 changed files with 138 additions and 0 deletions

View File

@ -302,6 +302,18 @@ def do_overlay(args: argparse.Namespace):
_display_overlay(args, overlay_dir, 1, '/')
def do_getpath(args: argparse.Namespace):
config = cmd_util.create_config(args)
mount, _ = get_mount_path(args.mount)
with config.get_thrift_client() as client:
inodePathInfo = client.debugGetInodePath(mount, args.number)
print('%s %s' %
('loaded' if inodePathInfo.loaded else 'unloaded',
os.path.normpath(os.path.join(mount, inodePathInfo.path))))
def get_loaded_inode_count(inode_info):
count = 0
for tree in inode_info:
@ -388,6 +400,17 @@ def setup_argparse(parser: argparse.ArgumentParser):
help='The path to the eden mount point.')
parser.set_defaults(func=do_overlay)
parser = subparsers.add_parser(
'getpath', help='Get the eden path that corresponds to an inode number')
parser.add_argument(
'mount',
help='The path to the eden mount point.')
parser.add_argument(
'number',
type=int,
help='Display information for the specified inode number.')
parser.set_defaults(func=do_getpath)
parser = subparsers.add_parser(
'unload', help='Unload unused inodes')
parser.add_argument(

View File

@ -25,6 +25,7 @@
#include "eden/fs/inodes/EdenMount.h"
#include "eden/fs/inodes/FileInode.h"
#include "eden/fs/inodes/InodeError.h"
#include "eden/fs/inodes/InodeMap.h"
#include "eden/fs/inodes/Overlay.h"
#include "eden/fs/inodes/TreeInode.h"
#include "eden/fs/model/Blob.h"
@ -592,6 +593,36 @@ void EdenServiceHandler::debugInodeStatus(
inode->getDebugStatus(inodeInfo);
}
void EdenServiceHandler::debugGetInodePath(
InodePathDebugInfo& info,
std::unique_ptr<std::string> mountPoint,
int64_t inodeNumber) {
auto inodeNum = static_cast<fuse_ino_t>(inodeNumber);
auto edenMount = server_->getMount(*mountPoint);
auto inodeMap = edenMount->getInodeMap();
// Check if the inode is loaded
auto loadedData = inodeMap->lookupLoadedInode(inodeNum);
if (loadedData == nullptr) {
XLOG(INFO) << "looking up unloaded inode " << inodeNum;
// If it's not, check if it's unloaded. If the inodeNum is invalid, this
// lookup will throw
auto unloadedData = inodeMap->lookupUnloadedInode(inodeNum);
info.path = unloadedData.name.stringPiece().str();
info.loaded = false;
} else {
// If the inode is loaded, return its path
auto path = loadedData->getPath();
if (path) {
info.path = path->stringPiece().str();
info.loaded = true;
} else {
throw newEdenError("missing path for loaded inode {}", inodeNum);
}
}
}
void EdenServiceHandler::unloadInodeForPath(
unique_ptr<string> mountPoint,
std::unique_ptr<std::string> path) {

View File

@ -145,6 +145,11 @@ class EdenServiceHandler : virtual public StreamingEdenServiceSvIf,
std::unique_ptr<std::string> mountPoint,
std::unique_ptr<std::string> path) override;
void debugGetInodePath(
InodePathDebugInfo& inodePath,
std::unique_ptr<std::string> mountPoint,
int64_t inodeNumber) override;
void unloadInodeForPath(
std::unique_ptr<std::string> mountPoint,
std::unique_ptr<std::string> path) override;

View File

@ -211,6 +211,11 @@ struct TreeInodeDebugInfo {
6: i64 refcount
}
struct InodePathDebugInfo {
1: string path
2: bool loaded
}
service EdenService extends fb303.FacebookService {
list<MountInfo> listMounts() throws (1: EdenError ex)
void mount(1: MountInfo info) throws (1: EdenError ex)
@ -432,6 +437,17 @@ service EdenService extends fb303.FacebookService {
2: string path,
) throws (1: EdenError ex)
/**
* Get the InodePathDebugInfo for the inode that corresponds to the given
* inode number. This provides the path for the inode and also indicates
* whether the inode is currently loaded or not. Requires that the Eden
* mountPoint be specified.
*/
InodePathDebugInfo debugGetInodePath(
1: string mountPoint,
2: i64 inodeNumber,
) throws (1: EdenError ex)
/**
* Unloads unused Inodes of a tree Node
*/

View File

@ -0,0 +1,63 @@
#!/usr/bin/env python3
#
# Copyright (c) 2016-present, Facebook, Inc.
# All rights reserved.
#
# This source code is licensed under the BSD-style license found in the
# LICENSE file in the root directory of this source tree. An additional grant
# of patent rights can be found in the PATENTS file in the same directory.
from .lib import testcase, edenclient
import os
# This is the name of the default repository created by EdenRepoTestBase.
repo_name = 'main'
@testcase.eden_repo_test
class DebugGetPathTest:
def populate_repo(self):
self.repo.write_file('hello', 'hola\n')
self.repo.write_file(os.path.join('dir', 'file'), 'blah\n')
self.repo.commit('Initial commit.')
def test_getpath_root_inode(self):
'''
Test that calling `eden debug getname 1` returns the path to the eden
mount, and indicates that the inode is loaded.
'''
output = self.eden.run_cmd(
'debug',
'getpath',
self.mount,
'1')
self.assertEqual('loaded ' + self.mount + '\n', output)
def test_getpath_dot_eden_inode(self):
'''
Test that calling `eden debug getname 2` returns the path to the .eden
directory, and indicates that the inode is loaded.
'''
output = self.eden.run_cmd(
'debug',
'getpath',
self.mount,
'2')
self.assertEqual(
'loaded ' + os.path.join(self.mount, ".eden") + '\n',
output)
def test_getpath_invalid_inode(self):
'''
Test that calling `eden debug getname 1234` raises an error since
1234 is not a valid inode number
'''
with self.assertRaises(edenclient.EdenCommandError) as context:
self.eden.run_cmd(
'debug',
'getpath',
self.mount,
'1234')
self.assertIn('unknown inode number 1234', str(context.exception))