diff --git a/src/v4l2/v4l2_camera.cpp b/src/v4l2/v4l2_camera.cpp
index 9a1ebc8..2557320 100644
--- a/src/v4l2/v4l2_camera.cpp
+++ b/src/v4l2/v4l2_camera.cpp
@@ -17,7 +17,8 @@ using namespace libcamera;
 LOG_DECLARE_CATEGORY(V4L2Compat);
 
 V4L2Camera::V4L2Camera(std::shared_ptr<Camera> camera)
-	: camera_(camera), isRunning_(false), bufferAllocator_(nullptr)
+	: camera_(camera), isRunning_(false), bufferAllocator_(nullptr),
+	  efd_(-1)
 {
 	camera_->requestCompleted.connect(this, &V4L2Camera::requestComplete);
 }
@@ -29,7 +30,6 @@ V4L2Camera::~V4L2Camera()
 
 int V4L2Camera::open()
 {
-	/* \todo Support multiple open. */
 	if (camera_->acquire() < 0) {
 		LOG(V4L2Compat, Error) << "Failed to acquire camera";
 		return -EINVAL;
@@ -59,6 +59,11 @@ void V4L2Camera::bind(int efd)
 	efd_ = efd;
 }
 
+void V4L2Camera::unbind()
+{
+	efd_ = -1;
+}
+
 void V4L2Camera::getStreamConfig(StreamConfiguration *streamConfig)
 {
 	*streamConfig = config_->at(0);
diff --git a/src/v4l2/v4l2_camera.h b/src/v4l2/v4l2_camera.h
index 33f5eb0..30114ed 100644
--- a/src/v4l2/v4l2_camera.h
+++ b/src/v4l2/v4l2_camera.h
@@ -40,6 +40,7 @@ public:
 	int open();
 	void close();
 	void bind(int efd);
+	void unbind();
 	void getStreamConfig(StreamConfiguration *streamConfig);
 	std::vector<Buffer> completedBuffers();
 
diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp
index 13db428..594dd13 100644
--- a/src/v4l2/v4l2_camera_proxy.cpp
+++ b/src/v4l2/v4l2_camera_proxy.cpp
@@ -33,45 +33,68 @@ LOG_DECLARE_CATEGORY(V4L2Compat);
 V4L2CameraProxy::V4L2CameraProxy(unsigned int index,
 				 std::shared_ptr<Camera> camera)
 	: refcount_(0), index_(index), bufferCount_(0), currentBuf_(0),
-	  vcam_(std::make_unique<V4L2Camera>(camera))
+	  vcam_(std::make_unique<V4L2Camera>(camera)), efd_(-1),
+	  acquiredFd_(-1), initialized_(false)
 {
 	querycap(camera);
 }
 
-int V4L2CameraProxy::open(bool nonBlocking)
+int V4L2CameraProxy::open(int fd, bool nonBlocking)
 {
-	LOG(V4L2Compat, Debug) << "Servicing open";
+	LOG(V4L2Compat, Debug) << "Servicing open fd = " << fd;
 
-	int ret = vcam_->open();
-	if (ret < 0) {
-		errno = -ret;
-		return -1;
-	}
+	nonBlockingFds_[fd] = nonBlocking;
 
-	nonBlocking_ = nonBlocking;
+	refcount_++;
+
+	if (initialized_)
+		return 0;
+
+	/*
+	 * We will open the camera here, once, and keep it open until the last
+	 * fd is closed. Before any reqbufs with count > 0 is called, anybody
+	 * can call any ioctl. Once reqbufs is called with count > 0, the
+	 * exclusive lock will be assigned to that fd, in acquiredFd_. At this
+	 * point, no other fd can call any ioctl (except for querycap, try_fmt,
+	 * g/s_priority, and enum/g/s_input), and they will return -EBUSY.
+	 * After reqbufs is called with count = 0, the exclusive lock will be
+	 * released.
+	 */
+
+	initialized_ = true;
+
+	int ret = vcam_->open();
+	if (ret < 0)
+		return ret;
 
 	vcam_->getStreamConfig(&streamConfig_);
 	setFmtFromConfig(streamConfig_);
 	sizeimage_ = calculateSizeImage(streamConfig_);
 
-	refcount_++;
-
 	return 0;
 }
 
-void V4L2CameraProxy::dup()
+void V4L2CameraProxy::dup(int oldfd, int newfd)
 {
+	nonBlockingFds_[newfd] = nonBlockingFds_[oldfd];
 	refcount_++;
 }
 
-void V4L2CameraProxy::close()
+void V4L2CameraProxy::close(int fd)
 {
-	LOG(V4L2Compat, Debug) << "Servicing close";
+	LOG(V4L2Compat, Debug) << "Servicing close fd = " << fd;
+
+	nonBlockingFds_.erase(fd);
+
+	if (acquiredFd_ == fd)
+		acquiredFd_ = -1;
 
 	if (--refcount_ > 0)
 		return;
 
 	vcam_->close();
+
+	initialized_ = false;
 }
 
 void *V4L2CameraProxy::mmap(void *addr, size_t length, int prot, int flags,
@@ -220,9 +243,10 @@ int V4L2CameraProxy::vidioc_querycap(struct v4l2_capability *arg)
 	return 0;
 }
 
-int V4L2CameraProxy::vidioc_enum_fmt(struct v4l2_fmtdesc *arg)
+int V4L2CameraProxy::vidioc_enum_fmt(int fd, struct v4l2_fmtdesc *arg)
 {
-	LOG(V4L2Compat, Debug) << "Servicing vidioc_enum_fmt";
+	LOG(V4L2Compat, Debug) << "Servicing vidioc_enum_fmt fd = " << fd;
+
 
 	if (!validateBufferType(arg->type) ||
 	    arg->index >= streamConfig_.formats().pixelformats().size())
@@ -236,9 +260,10 @@ int V4L2CameraProxy::vidioc_enum_fmt(struct v4l2_fmtdesc *arg)
 	return 0;
 }
 
-int V4L2CameraProxy::vidioc_g_fmt(struct v4l2_format *arg)
+int V4L2CameraProxy::vidioc_g_fmt(int fd, struct v4l2_format *arg)
 {
-	LOG(V4L2Compat, Debug) << "Servicing vidioc_g_fmt";
+	LOG(V4L2Compat, Debug) << "Servicing vidioc_g_fmt fd = " << fd;
+
 
 	if (!validateBufferType(arg->type))
 		return -EINVAL;
@@ -274,9 +299,13 @@ void V4L2CameraProxy::tryFormat(struct v4l2_format *arg)
 	arg->fmt.pix.colorspace   = V4L2_COLORSPACE_SRGB;
 }
 
-int V4L2CameraProxy::vidioc_s_fmt(struct v4l2_format *arg)
+int V4L2CameraProxy::vidioc_s_fmt(int fd, struct v4l2_format *arg)
 {
-	LOG(V4L2Compat, Debug) << "Servicing vidioc_s_fmt";
+	LOG(V4L2Compat, Debug) << "Servicing vidioc_s_fmt fd = " << fd;
+
+	int ret = lock(fd);
+	if (ret < 0)
+		return ret;
 
 	if (!validateBufferType(arg->type))
 		return -EINVAL;
@@ -284,9 +313,9 @@ int V4L2CameraProxy::vidioc_s_fmt(struct v4l2_format *arg)
 	tryFormat(arg);
 
 	Size size(arg->fmt.pix.width, arg->fmt.pix.height);
-	int ret = vcam_->configure(&streamConfig_, size,
-				   v4l2ToDrm(arg->fmt.pix.pixelformat),
-				   bufferCount_);
+	ret = vcam_->configure(&streamConfig_, size,
+			       v4l2ToDrm(arg->fmt.pix.pixelformat),
+			       bufferCount_);
 	if (ret < 0)
 		return -EINVAL;
 
@@ -301,9 +330,9 @@ int V4L2CameraProxy::vidioc_s_fmt(struct v4l2_format *arg)
 	return 0;
 }
 
-int V4L2CameraProxy::vidioc_try_fmt(struct v4l2_format *arg)
+int V4L2CameraProxy::vidioc_try_fmt(int fd, struct v4l2_format *arg)
 {
-	LOG(V4L2Compat, Debug) << "Servicing vidioc_try_fmt";
+	LOG(V4L2Compat, Debug) << "Servicing vidioc_try_fmt fd = " << fd;
 
 	if (!validateBufferType(arg->type))
 		return -EINVAL;
@@ -328,11 +357,14 @@ int V4L2CameraProxy::freeBuffers()
 	return 0;
 }
 
-int V4L2CameraProxy::vidioc_reqbufs(struct v4l2_requestbuffers *arg)
+int V4L2CameraProxy::vidioc_reqbufs(int fd, struct v4l2_requestbuffers *arg)
 {
-	int ret;
+	LOG(V4L2Compat, Debug) << "Servicing vidioc_reqbufs fd = " << fd;
+
 
-	LOG(V4L2Compat, Debug) << "Servicing vidioc_reqbufs";
+	int ret = lock(fd);
+	if (ret < 0)
+		return ret;
 
 	if (!validateBufferType(arg->type) ||
 	    !validateMemoryType(arg->memory))
@@ -341,9 +373,21 @@ int V4L2CameraProxy::vidioc_reqbufs(struct v4l2_requestbuffers *arg)
 	LOG(V4L2Compat, Debug) << arg->count << " buffers requested ";
 
 	arg->capabilities = V4L2_BUF_CAP_SUPPORTS_MMAP;
+	memset(arg->reserved, 0, sizeof(arg->reserved));
 
-	if (arg->count == 0)
+	if (arg->count == 0) {
+		unlock(fd);
 		return freeBuffers();
+	}
+
+	if (bufferCount_ > 0) {
+		ret = freeBuffers();
+		if (ret < 0) {
+			LOG(V4L2Compat, Error)
+				<< "Failed to free libcamera buffers for re-reqbufs";
+			return ret;
+		}
+	}
 
 	Size size(curV4L2Format_.fmt.pix.width, curV4L2Format_.fmt.pix.height);
 	ret = vcam_->configure(&streamConfig_, size,
@@ -386,6 +430,7 @@ int V4L2CameraProxy::vidioc_reqbufs(struct v4l2_requestbuffers *arg)
 		buf.memory = V4L2_MEMORY_MMAP;
 		buf.m.offset = i * curV4L2Format_.fmt.pix.sizeimage;
 		buf.index = i;
+		buf.flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
 
 		buffers_[i] = buf;
 	}
@@ -395,9 +440,13 @@ int V4L2CameraProxy::vidioc_reqbufs(struct v4l2_requestbuffers *arg)
 	return 0;
 }
 
-int V4L2CameraProxy::vidioc_querybuf(struct v4l2_buffer *arg)
+int V4L2CameraProxy::vidioc_querybuf(int fd, struct v4l2_buffer *arg)
 {
-	LOG(V4L2Compat, Debug) << "Servicing vidioc_querybuf";
+	LOG(V4L2Compat, Debug) << "Servicing vidioc_querybuf fd = " << fd;
+
+	int ret = lock(fd);
+	if (ret < 0)
+		return ret;
 
 	if (!validateBufferType(arg->type) ||
 	    arg->index >= bufferCount_)
@@ -410,17 +459,21 @@ int V4L2CameraProxy::vidioc_querybuf(struct v4l2_buffer *arg)
 	return 0;
 }
 
-int V4L2CameraProxy::vidioc_qbuf(struct v4l2_buffer *arg)
+int V4L2CameraProxy::vidioc_qbuf(int fd, struct v4l2_buffer *arg)
 {
 	LOG(V4L2Compat, Debug) << "Servicing vidioc_qbuf, index = "
-			       << arg->index;
+			       << arg->index << " fd = " << fd;
+
+	int ret = lock(fd);
+	if (ret < 0)
+		return ret;
 
 	if (!validateBufferType(arg->type) ||
 	    !validateMemoryType(arg->memory) ||
 	    arg->index >= bufferCount_)
 		return -EINVAL;
 
-	int ret = vcam_->qbuf(arg->index);
+	ret = vcam_->qbuf(arg->index);
 	if (ret < 0)
 		return ret;
 
@@ -430,15 +483,19 @@ int V4L2CameraProxy::vidioc_qbuf(struct v4l2_buffer *arg)
 	return ret;
 }
 
-int V4L2CameraProxy::vidioc_dqbuf(struct v4l2_buffer *arg)
+int V4L2CameraProxy::vidioc_dqbuf(int fd, struct v4l2_buffer *arg)
 {
-	LOG(V4L2Compat, Debug) << "Servicing vidioc_dqbuf";
+	LOG(V4L2Compat, Debug) << "Servicing vidioc_dqbuf fd = " << fd;
+
+	int ret = lock(fd);
+	if (ret < 0)
+		return ret;
 
 	if (!validateBufferType(arg->type) ||
 	    !validateMemoryType(arg->memory))
 		return -EINVAL;
 
-	if (!nonBlocking_)
+	if (!nonBlockingFds_[fd])
 		vcam_->bufferSema_.acquire();
 	else if (!vcam_->bufferSema_.tryAcquire())
 		return -EAGAIN;
@@ -454,16 +511,20 @@ int V4L2CameraProxy::vidioc_dqbuf(struct v4l2_buffer *arg)
 	currentBuf_ = (currentBuf_ + 1) % bufferCount_;
 
 	uint64_t data;
-	int ret = ::read(efd_, &data, sizeof(data));
+	ret = ::read(efd_, &data, sizeof(data));
 	if (ret != sizeof(data))
 		LOG(V4L2Compat, Error) << "Failed to clear eventfd POLLIN";
 
 	return 0;
 }
 
-int V4L2CameraProxy::vidioc_streamon(int *arg)
+int V4L2CameraProxy::vidioc_streamon(int fd, int *arg)
 {
-	LOG(V4L2Compat, Debug) << "Servicing vidioc_streamon";
+	LOG(V4L2Compat, Debug) << "Servicing vidioc_streamon fd = " << fd;
+
+	int ret = lock(fd);
+	if (ret < 0)
+		return ret;
 
 	if (!validateBufferType(*arg))
 		return -EINVAL;
@@ -473,14 +534,18 @@ int V4L2CameraProxy::vidioc_streamon(int *arg)
 	return vcam_->streamOn();
 }
 
-int V4L2CameraProxy::vidioc_streamoff(int *arg)
+int V4L2CameraProxy::vidioc_streamoff(int fd, int *arg)
 {
-	LOG(V4L2Compat, Debug) << "Servicing vidioc_streamoff";
+	LOG(V4L2Compat, Debug) << "Servicing vidioc_streamoff fd = " << fd;
+
+	int ret = lock(fd);
+	if (ret < 0)
+		return ret;
 
 	if (!validateBufferType(*arg))
 		return -EINVAL;
 
-	int ret = vcam_->streamOff();
+	ret = vcam_->streamOff();
 
 	for (struct v4l2_buffer &buf : buffers_)
 		buf.flags &= ~(V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE);
@@ -488,7 +553,7 @@ int V4L2CameraProxy::vidioc_streamoff(int *arg)
 	return ret;
 }
 
-int V4L2CameraProxy::ioctl(unsigned long request, void *arg)
+int V4L2CameraProxy::ioctl(int fd, unsigned long request, void *arg)
 {
 	int ret;
 	switch (request) {
@@ -496,34 +561,34 @@ int V4L2CameraProxy::ioctl(unsigned long request, void *arg)
 		ret = vidioc_querycap(static_cast<struct v4l2_capability *>(arg));
 		break;
 	case VIDIOC_ENUM_FMT:
-		ret = vidioc_enum_fmt(static_cast<struct v4l2_fmtdesc *>(arg));
+		ret = vidioc_enum_fmt(fd, static_cast<struct v4l2_fmtdesc *>(arg));
 		break;
 	case VIDIOC_G_FMT:
-		ret = vidioc_g_fmt(static_cast<struct v4l2_format *>(arg));
+		ret = vidioc_g_fmt(fd, static_cast<struct v4l2_format *>(arg));
 		break;
 	case VIDIOC_S_FMT:
-		ret = vidioc_s_fmt(static_cast<struct v4l2_format *>(arg));
+		ret = vidioc_s_fmt(fd, static_cast<struct v4l2_format *>(arg));
 		break;
 	case VIDIOC_TRY_FMT:
-		ret = vidioc_try_fmt(static_cast<struct v4l2_format *>(arg));
+		ret = vidioc_try_fmt(fd, static_cast<struct v4l2_format *>(arg));
 		break;
 	case VIDIOC_REQBUFS:
-		ret = vidioc_reqbufs(static_cast<struct v4l2_requestbuffers *>(arg));
+		ret = vidioc_reqbufs(fd, static_cast<struct v4l2_requestbuffers *>(arg));
 		break;
 	case VIDIOC_QUERYBUF:
-		ret = vidioc_querybuf(static_cast<struct v4l2_buffer *>(arg));
+		ret = vidioc_querybuf(fd, static_cast<struct v4l2_buffer *>(arg));
 		break;
 	case VIDIOC_QBUF:
-		ret = vidioc_qbuf(static_cast<struct v4l2_buffer *>(arg));
+		ret = vidioc_qbuf(fd, static_cast<struct v4l2_buffer *>(arg));
 		break;
 	case VIDIOC_DQBUF:
-		ret = vidioc_dqbuf(static_cast<struct v4l2_buffer *>(arg));
+		ret = vidioc_dqbuf(fd, static_cast<struct v4l2_buffer *>(arg));
 		break;
 	case VIDIOC_STREAMON:
-		ret = vidioc_streamon(static_cast<int *>(arg));
+		ret = vidioc_streamon(fd, static_cast<int *>(arg));
 		break;
 	case VIDIOC_STREAMOFF:
-		ret = vidioc_streamoff(static_cast<int *>(arg));
+		ret = vidioc_streamoff(fd, static_cast<int *>(arg));
 		break;
 	default:
 		ret = -ENOTTY;
@@ -538,10 +603,37 @@ int V4L2CameraProxy::ioctl(unsigned long request, void *arg)
 	return ret;
 }
 
-void V4L2CameraProxy::bind(int fd)
+/**
+ * \brief Acquire an exclusive lock on the V4L2Camera
+ *
+ * \return Zero on success or if already acquired, and negative error on
+ * failure.
+ */
+int V4L2CameraProxy::lock(int fd)
 {
+	if (acquiredFd_ == fd)
+		return 0;
+
+	if (acquiredFd_ >= 0)
+		return -EBUSY;
+
 	efd_ = fd;
 	vcam_->bind(fd);
+
+	acquiredFd_ = fd;
+
+	return 0;
+}
+
+void V4L2CameraProxy::unlock(int fd)
+{
+	if (acquiredFd_ != fd)
+		return;
+
+	efd_ = -1;
+	vcam_->unbind();
+
+	acquiredFd_ = -1;
 }
 
 struct PixelFormatPlaneInfo {
diff --git a/src/v4l2/v4l2_camera_proxy.h b/src/v4l2/v4l2_camera_proxy.h
index b5a9801..90e518c 100644
--- a/src/v4l2/v4l2_camera_proxy.h
+++ b/src/v4l2/v4l2_camera_proxy.h
@@ -26,15 +26,13 @@ class V4L2CameraProxy
 public:
 	V4L2CameraProxy(unsigned int index, std::shared_ptr<Camera> camera);
 
-	int open(bool nonBlocking);
-	void dup();
-	void close();
+	int open(int fd, bool nonBlocking);
+	void dup(int oldfd, int newfd);
+	void close(int fd);
 	void *mmap(void *addr, size_t length, int prot, int flags, __off64_t offset);
 	int munmap(void *addr, size_t length);
 
-	int ioctl(unsigned long request, void *arg);
-
-	void bind(int fd);
+	int ioctl(int fd, unsigned long request, void *arg);
 
 private:
 	bool validateBufferType(uint32_t type);
@@ -47,16 +45,19 @@ private:
 	int freeBuffers();
 
 	int vidioc_querycap(struct v4l2_capability *arg);
-	int vidioc_enum_fmt(struct v4l2_fmtdesc *arg);
-	int vidioc_g_fmt(struct v4l2_format *arg);
-	int vidioc_s_fmt(struct v4l2_format *arg);
-	int vidioc_try_fmt(struct v4l2_format *arg);
-	int vidioc_reqbufs(struct v4l2_requestbuffers *arg);
-	int vidioc_querybuf(struct v4l2_buffer *arg);
-	int vidioc_qbuf(struct v4l2_buffer *arg);
-	int vidioc_dqbuf(struct v4l2_buffer *arg);
-	int vidioc_streamon(int *arg);
-	int vidioc_streamoff(int *arg);
+	int vidioc_enum_fmt(int fd, struct v4l2_fmtdesc *arg);
+	int vidioc_g_fmt(int fd, struct v4l2_format *arg);
+	int vidioc_s_fmt(int fd, struct v4l2_format *arg);
+	int vidioc_try_fmt(int fd, struct v4l2_format *arg);
+	int vidioc_reqbufs(int fd, struct v4l2_requestbuffers *arg);
+	int vidioc_querybuf(int fd, struct v4l2_buffer *arg);
+	int vidioc_qbuf(int fd, struct v4l2_buffer *arg);
+	int vidioc_dqbuf(int fd, struct v4l2_buffer *arg);
+	int vidioc_streamon(int fd, int *arg);
+	int vidioc_streamoff(int fd, int *arg);
+
+	int lock(int fd);
+	void unlock(int fd);
 
 	static unsigned int bplMultiplier(uint32_t format);
 	static unsigned int imageSize(uint32_t format, unsigned int width,
@@ -67,7 +68,6 @@ private:
 
 	unsigned int refcount_;
 	unsigned int index_;
-	bool nonBlocking_;
 
 	struct v4l2_format curV4L2Format_;
 	StreamConfiguration streamConfig_;
@@ -82,6 +82,19 @@ private:
 	std::unique_ptr<V4L2Camera> vcam_;
 
 	int efd_;
+
+	std::map<int, bool> nonBlockingFds_;
+	/*
+	 * This is an exclusive lock on the camera. When this is not taken,
+	 * anybody can call any ioctl before reqbufs. reqbufs with count > 0
+	 * will claim this lock, and reqbufs with count = 0 will release it.
+	 * Any ioctl is called while the lock is taken will return -EBUSY
+	 * (if applicable, eg. try_fmt, querycap, g/s_priority, and
+	 * enum/g/s_input are exempt).
+	 */
+	int acquiredFd_;
+
+	bool initialized_;
 };
 
 #endif /* __V4L2_CAMERA_PROXY_H__ */
diff --git a/src/v4l2/v4l2_compat_manager.cpp b/src/v4l2/v4l2_compat_manager.cpp
index 9298c0f..ce1eace 100644
--- a/src/v4l2/v4l2_compat_manager.cpp
+++ b/src/v4l2/v4l2_compat_manager.cpp
@@ -148,24 +148,17 @@ int V4L2CompatManager::openat(int dirfd, const char *path, int oflag, mode_t mod
 
 	fops_.close(fd);
 
-	unsigned int camera_index = static_cast<unsigned int>(ret);
-
-	V4L2CameraProxy *proxy = proxies_[camera_index].get();
-	ret = proxy->open(oflag & O_NONBLOCK);
-	if (ret < 0)
-		return ret;
-
 	int efd = eventfd(0, EFD_SEMAPHORE |
 			     ((oflag & O_CLOEXEC) ? EFD_CLOEXEC : 0) |
 			     ((oflag & O_NONBLOCK) ? EFD_NONBLOCK : 0));
-	if (efd < 0) {
-		int err = errno;
-		proxy->close();
-		errno = err;
+	if (efd < 0)
 		return efd;
-	}
 
-	proxy->bind(efd);
+	unsigned int camera_index = static_cast<unsigned int>(ret);
+
+	V4L2CameraProxy *proxy = proxies_[camera_index].get();
+	proxy->open(efd, oflag & O_NONBLOCK);
+
 	devices_.emplace(efd, proxy);
 
 	return efd;
@@ -181,7 +174,7 @@ int V4L2CompatManager::dup(int oldfd)
 	if (device != devices_.end()) {
 		V4L2CameraProxy *proxy = device->second;
 		devices_[newfd] = proxy;
-		proxy->dup();
+		proxy->dup(oldfd, newfd);
 	}
 
 	return newfd;
@@ -191,7 +184,7 @@ int V4L2CompatManager::close(int fd)
 {
 	V4L2CameraProxy *proxy = getProxy(fd);
 	if (proxy) {
-		proxy->close();
+		proxy->close(fd);
 		devices_.erase(fd);
 		return 0;
 	}
@@ -237,5 +230,5 @@ int V4L2CompatManager::ioctl(int fd, unsigned long request, void *arg)
 	if (!proxy)
 		return fops_.ioctl(fd, request, arg);
 
-	return proxy->ioctl(request, arg);
+	return proxy->ioctl(fd, request, arg);
 }
