1ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch// Use of this source code is governed by a BSD-style license that can be 3ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch// found in the LICENSE file. 42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <errno.h> 62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <fcntl.h> 72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <pthread.h> 82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <sys/stat.h> 92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <map> 112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <string> 122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "nacl_io/kernel_handle.h" 142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "nacl_io/kernel_object.h" 152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "nacl_io/mount.h" 162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "nacl_io/path.h" 172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "gtest/gtest.h" 192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 20ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochusing namespace nacl_io; 21ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace { 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 24eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochclass MountNodeRefMock : public MountNode { 252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public: 26eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch MountNodeRefMock(Mount* mnt) : MountNode(mnt) {} 27eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}; 282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 29eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochclass MountRefMock : public Mount { 30eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch public: 31eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch MountRefMock() {} 32eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ~MountRefMock() {} 332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public: 35eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch Error Access(const Path& path, int a_mode) { return ENOSYS; } 36eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch Error Open(const Path& path, int mode, ScopedMountNode* out_node) { 37eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch out_node->reset(NULL); 38868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return ENOSYS; 39868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 40868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) Error Unlink(const Path& path) { return 0; } 41868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) Error Mkdir(const Path& path, int permissions) { return 0; } 42868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) Error Rmdir(const Path& path) { return 0; } 43868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) Error Remove(const Path& path) { return 0; } 442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class KernelHandleRefMock : public KernelHandle { 472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public: 48eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch KernelHandleRefMock(const ScopedMount& mnt, const ScopedMountNode& node) 49eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch : KernelHandle(mnt, node) {} 502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 51eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ~KernelHandleRefMock() {} 522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class KernelObjectTest : public ::testing::Test { 552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public: 56eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch KernelObjectTest() { 572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) proxy = new KernelObject; 58eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch mnt.reset(new MountRefMock()); 59eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch node.reset(new MountNodeRefMock(mnt.get())); 602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ~KernelObjectTest() { 632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // mnt is ref-counted, it doesn't need to be explicitly deleted. 64eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch node.reset(NULL); 65eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch mnt.reset(NULL); 662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) delete proxy; 672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) KernelObject* proxy; 70eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ScopedMount mnt; 71eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ScopedMountNode node; 722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace 752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 76eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <nacl_io/mount_mem.h> 77eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <nacl_io/mount_http.h> 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 79eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochTEST_F(KernelObjectTest, Referencing) { 80eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // The mount and node should have 1 ref count at this point 812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) EXPECT_EQ(1, mnt->RefCount()); 82eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch EXPECT_EQ(1, node->RefCount()); 832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 84eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Pass the mount and node into a KernelHandle 85eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch KernelHandle* raw_handle = new KernelHandleRefMock(mnt, node); 86eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ScopedKernelHandle handle_a(raw_handle); 87eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 88eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // The mount and node should have 1 ref count at this point 89eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch EXPECT_EQ(1, handle_a->RefCount()); 90eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch EXPECT_EQ(2, mnt->RefCount()); 91eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch EXPECT_EQ(2, node->RefCount()); 92eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 93eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ScopedKernelHandle handle_b = handle_a; 94eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 95eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // There should be two references to the KernelHandle, the mount and node 96eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // should be unchanged. 97eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch EXPECT_EQ(2, handle_a->RefCount()); 98eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch EXPECT_EQ(2, handle_b->RefCount()); 99eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch EXPECT_EQ(handle_a.get(), handle_b.get()); 1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) EXPECT_EQ(2, mnt->RefCount()); 101eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch EXPECT_EQ(2, node->RefCount()); 1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 103eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Allocating an FD should cause the KernelProxy to ref the handle and 104eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // the node and mount should be unchanged. 105eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch int fd1 = proxy->AllocateFD(handle_a); 106eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch EXPECT_EQ(3, handle_a->RefCount()); 107eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch EXPECT_EQ(2, mnt->RefCount()); 108eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch EXPECT_EQ(2, node->RefCount()); 1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 110eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // If we "dup" the handle, we should bump the ref count on the handle 111eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch int fd2 = proxy->AllocateFD(handle_b); 112eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch EXPECT_EQ(4, handle_a->RefCount()); 113eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch EXPECT_EQ(2, mnt->RefCount()); 114eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch EXPECT_EQ(2, node->RefCount()); 1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 116c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Handles are expected to come out in order 1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) EXPECT_EQ(0, fd1); 1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) EXPECT_EQ(1, fd2); 119eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 120eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Now we "free" the handles, since the proxy should hold them. 121eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch handle_a.reset(NULL); 122eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch handle_b.reset(NULL); 123eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch EXPECT_EQ(2, mnt->RefCount()); 124eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch EXPECT_EQ(2, node->RefCount()); 1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // We should find the handle by either fd 127eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch EXPECT_EQ(0, proxy->AcquireHandle(fd1, &handle_a)); 128eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch EXPECT_EQ(0, proxy->AcquireHandle(fd2, &handle_b)); 129eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch EXPECT_EQ(raw_handle, handle_a.get()); 130eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch EXPECT_EQ(raw_handle, handle_b.get()); 1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 132eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch EXPECT_EQ(4, handle_a->RefCount()); 133eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch EXPECT_EQ(2, mnt->RefCount()); 134eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch EXPECT_EQ(2, node->RefCount()); 135eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 136eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // A non existent fd should fail, and handleA should decrement as handleB 137eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // is released by the call. 138eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch EXPECT_EQ(EBADF, proxy->AcquireHandle(-1, &handle_b)); 139eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch EXPECT_EQ(NULL, handle_b.get()); 140eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch EXPECT_EQ(3, handle_a->RefCount()); 141eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 142eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch EXPECT_EQ(EBADF, proxy->AcquireHandle(100, &handle_b)); 143eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch EXPECT_EQ(NULL, handle_b.get()); 1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 145eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Now only the KernelProxy should reference the KernelHandle in the 146eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // FD to KernelHandle Map. 147eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch handle_a.reset(); 148eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch handle_b.reset(); 1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 150eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch EXPECT_EQ(2, raw_handle->RefCount()); 151eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch EXPECT_EQ(2, mnt->RefCount()); 152eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch EXPECT_EQ(2, node->RefCount()); 1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) proxy->FreeFD(fd2); 154eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch EXPECT_EQ(1, raw_handle->RefCount()); 155eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch EXPECT_EQ(2, mnt->RefCount()); 156eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch EXPECT_EQ(2, node->RefCount()); 157eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 158eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch proxy->FreeFD(fd1); 159eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch EXPECT_EQ(1, mnt->RefCount()); 160eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch EXPECT_EQ(1, node->RefCount()); 1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST_F(KernelObjectTest, FreeAndReassignFD) { 164eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // The mount and node should have 1 ref count at this point 165eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch EXPECT_EQ(1, mnt->RefCount()); 166eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch EXPECT_EQ(1, node->RefCount()); 167eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 168eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch KernelHandle* raw_handle = new KernelHandleRefMock(mnt, node); 169eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ScopedKernelHandle handle(raw_handle); 170eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 171eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch EXPECT_EQ(2, mnt->RefCount()); 172eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch EXPECT_EQ(2, node->RefCount()); 173eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch EXPECT_EQ(1, raw_handle->RefCount()); 174eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 175ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch proxy->AllocateFD(handle); 176eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch EXPECT_EQ(2, mnt->RefCount()); 177eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch EXPECT_EQ(2, node->RefCount()); 178eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch EXPECT_EQ(2, raw_handle->RefCount()); 179eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 180eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch proxy->FreeAndReassignFD(5, handle); 181eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch EXPECT_EQ(2, mnt->RefCount()); 182eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch EXPECT_EQ(2, node->RefCount()); 183eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch EXPECT_EQ(3, raw_handle->RefCount()); 184eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 185eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch handle.reset(); 186eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch EXPECT_EQ(2, raw_handle->RefCount()); 187eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 188eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch proxy->AcquireHandle(5, &handle); 189eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch EXPECT_EQ(3, raw_handle->RefCount()); 190eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch EXPECT_EQ(raw_handle, handle.get()); 1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 192eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 193