From mboxrd@z Thu Jan 1 00:00:00 1970 From: Laurent Pinchart Subject: Re: [PATCH v7] Add udmabuf misc device Date: Mon, 10 Sep 2018 15:12:59 +0300 Message-ID: <21053714.0Xa7F2u2PE@avalon> References: <20180827093444.23623-1-kraxel@redhat.com> Mime-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: base64 Return-path: In-Reply-To: <20180827093444.23623-1-kraxel@redhat.com> List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" To: Gerd Hoffmann Cc: "open list:KERNEL SELFTEST FRAMEWORK" , Tomeu Vizoso , Jonathan Corbet , David Airlie , linux-api@vger.kernel.org, "open list:DOCUMENTATION" , open list , dri-devel@lists.freedesktop.org, "moderated list:DMA BUFFER SHARING FRAMEWORK" , Shuah Khan , "open list:DMA BUFFER SHARING FRAMEWORK" List-Id: linux-api@vger.kernel.org SGkgR2VyZCwKClRoYW5rIHlvdSBmb3IgdGhlIHBhdGNoLgoKQ0MnaW5nIHRoZSBsaW51eC1hcGkg bWFpbGluZyBsaXN0IGFzIHRoaXMgY3JlYXRlcyBhIG5ldyB1c2Vyc3BhY2UgQVBJLgoKT24gTW9u ZGF5LCAyNyBBdWd1c3QgMjAxOCAxMjozNDo0NCBFRVNUIEdlcmQgSG9mZm1hbm4gd3JvdGU6Cj4g QSBkcml2ZXIgdG8gbGV0IHVzZXJzcGFjZSB0dXJuIG1lbWZkIHJlZ2lvbnMgaW50byBkbWEtYnVm cy4KPiAKPiBVc2UgY2FzZTogIEFsbG93cyBxZW11IGNyZWF0ZSBkbWFidWZzIGZvciB0aGUgdmdh IGZyYW1lYnVmZmVyIG9yCj4gdmlydGlvLWdwdSByZXNzb3VyY2VzLiAgVGhlbiB0aGV5IGNhbiBi ZSBwYXNzZWQgYXJvdW5kIHRvIGRpc3BsYXkKPiB0aG9zZSBndWVzdCB0aGluZ3Mgb24gdGhlIGhv c3QuICBUbyBzcGljZSBjbGllbnQgZm9yIGNsYXNzaWMgZnVsbAo+IGZyYW1lYnVmZmVyIGRpc3Bs YXksIGFuZCBob3BlZnVsbHkgc29tZSBkYXkgdG8gd2F5bGFuZCBzZXJ2ZXIgZm9yCj4gc2VhbWxl c3MgZ3Vlc3Qgd2luZG93IGRpc3BsYXkuCj4gCj4gcWVtdSB0ZXN0IGJyYW5jaDoKPiAgIGh0dHBz Oi8vZ2l0LmtyYXhlbC5vcmcvY2dpdC9xZW11L2xvZy8/aD1zaXJpdXMvdWRtYWJ1Zgo+IAo+IENj OiBEYXZpZCBBaXJsaWUgPGFpcmxpZWRAbGludXguaWU+Cj4gQ2M6IFRvbWV1IFZpem9zbyA8dG9t ZXUudml6b3NvQGNvbGxhYm9yYS5jb20+Cj4gQ2M6IExhdXJlbnQgUGluY2hhcnQgPGxhdXJlbnQu cGluY2hhcnRAaWRlYXNvbmJvYXJkLmNvbT4KPiBDYzogRGFuaWVsIFZldHRlciA8ZGFuaWVsQGZm d2xsLmNoPgo+IFNpZ25lZC1vZmYtYnk6IEdlcmQgSG9mZm1hbm4gPGtyYXhlbEByZWRoYXQuY29t Pgo+IC0tLQo+ICBEb2N1bWVudGF0aW9uL2lvY3RsL2lvY3RsLW51bWJlci50eHQgICAgICAgICAg ICAgIHwgICAxICsKPiAgaW5jbHVkZS91YXBpL2xpbnV4L3VkbWFidWYuaCAgICAgICAgICAgICAg ICAgICAgICB8ICAzMyArKysKPiAgZHJpdmVycy9kbWEtYnVmL3VkbWFidWYuYyAgICAgICAgICAg ICAgICAgICAgICAgICB8IDI4NyArKysrKysrKysrKysrKysrKysrCj4gIHRvb2xzL3Rlc3Rpbmcv c2VsZnRlc3RzL2RyaXZlcnMvZG1hLWJ1Zi91ZG1hYnVmLmMgfCAgOTYgKysrKysrKysKPiAgTUFJ TlRBSU5FUlMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8ICAxNiArKwo+ ICBkcml2ZXJzL2RtYS1idWYvS2NvbmZpZyAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgICA4 ICsKPiAgZHJpdmVycy9kbWEtYnVmL01ha2VmaWxlICAgICAgICAgICAgICAgICAgICAgICAgICB8 ICAgMSArCj4gIHRvb2xzL3Rlc3Rpbmcvc2VsZnRlc3RzL2RyaXZlcnMvZG1hLWJ1Zi9NYWtlZmls ZSAgfCAgIDUgKwo+ICA4IGZpbGVzIGNoYW5nZWQsIDQ0NyBpbnNlcnRpb25zKCspCj4gIGNyZWF0 ZSBtb2RlIDEwMDY0NCBpbmNsdWRlL3VhcGkvbGludXgvdWRtYWJ1Zi5oCj4gIGNyZWF0ZSBtb2Rl IDEwMDY0NCBkcml2ZXJzL2RtYS1idWYvdWRtYWJ1Zi5jCj4gIGNyZWF0ZSBtb2RlIDEwMDY0NCB0 b29scy90ZXN0aW5nL3NlbGZ0ZXN0cy9kcml2ZXJzL2RtYS1idWYvdWRtYWJ1Zi5jCj4gIGNyZWF0 ZSBtb2RlIDEwMDY0NCB0b29scy90ZXN0aW5nL3NlbGZ0ZXN0cy9kcml2ZXJzL2RtYS1idWYvTWFr ZWZpbGUKCltzbmlwXQoKPiBkaWZmIC0tZ2l0IGEvaW5jbHVkZS91YXBpL2xpbnV4L3VkbWFidWYu aCBiL2luY2x1ZGUvdWFwaS9saW51eC91ZG1hYnVmLmgKPiBuZXcgZmlsZSBtb2RlIDEwMDY0NAo+ IGluZGV4IDAwMDAwMDAwMDAuLjQ2YjY1MzJlZDgKPiAtLS0gL2Rldi9udWxsCj4gKysrIGIvaW5j bHVkZS91YXBpL2xpbnV4L3VkbWFidWYuaAo+IEBAIC0wLDAgKzEsMzMgQEAKPiArLyogU1BEWC1M aWNlbnNlLUlkZW50aWZpZXI6IEdQTC0yLjAgV0lUSCBMaW51eC1zeXNjYWxsLW5vdGUgKi8KPiAr I2lmbmRlZiBfVUFQSV9MSU5VWF9VRE1BQlVGX0gKPiArI2RlZmluZSBfVUFQSV9MSU5VWF9VRE1B QlVGX0gKPiArCj4gKyNpbmNsdWRlIDxsaW51eC90eXBlcy5oPgo+ICsjaW5jbHVkZSA8bGludXgv aW9jdGwuaD4KPiArCj4gKyNkZWZpbmUgVURNQUJVRl9GTEFHU19DTE9FWEVDCTB4MDEKPiArCj4g K3N0cnVjdCB1ZG1hYnVmX2NyZWF0ZSB7Cj4gKwlfX3UzMiBtZW1mZDsKPiArCV9fdTMyIGZsYWdz Owo+ICsJX191NjQgb2Zmc2V0Owo+ICsJX191NjQgc2l6ZTsKPiArfTsKPiArCj4gK3N0cnVjdCB1 ZG1hYnVmX2NyZWF0ZV9pdGVtIHsKPiArCV9fdTMyIG1lbWZkOwo+ICsJX191MzIgX19wYWQ7Cj4g KwlfX3U2NCBvZmZzZXQ7Cj4gKwlfX3U2NCBzaXplOwo+ICt9Owo+ICsKPiArc3RydWN0IHVkbWFi dWZfY3JlYXRlX2xpc3Qgewo+ICsJX191MzIgZmxhZ3M7Cj4gKwlfX3UzMiBjb3VudDsKPiArCXN0 cnVjdCB1ZG1hYnVmX2NyZWF0ZV9pdGVtIGxpc3RbXTsKPiArfTsKPiArCj4gKyNkZWZpbmUgVURN QUJVRl9DUkVBVEUgICAgICAgX0lPVygndScsIDB4NDIsIHN0cnVjdCB1ZG1hYnVmX2NyZWF0ZSkK CldoeSBkbyB5b3Ugc3RhcnQgYXQgMHg0MiBpZiB5b3UgcmVzZXJ2ZSB0aGUgMHg0MC0weDRmIHJh bmdlID8KCj4gKyNkZWZpbmUgVURNQUJVRl9DUkVBVEVfTElTVCAgX0lPVygndScsIDB4NDMsIHN0 cnVjdCB1ZG1hYnVmX2NyZWF0ZV9saXN0KQoKV2hlcmUncyB0aGUgZG9jdW1lbnRhdGlvbiA/IDot KQoKPiArI2VuZGlmIC8qIF9VQVBJX0xJTlVYX1VETUFCVUZfSCAqLwo+IGRpZmYgLS1naXQgYS9k cml2ZXJzL2RtYS1idWYvdWRtYWJ1Zi5jIGIvZHJpdmVycy9kbWEtYnVmL3VkbWFidWYuYwo+IG5l dyBmaWxlIG1vZGUgMTAwNjQ0Cj4gaW5kZXggMDAwMDAwMDAwMC4uOGUyNDIwNDUyNgo+IC0tLSAv ZGV2L251bGwKPiArKysgYi9kcml2ZXJzL2RtYS1idWYvdWRtYWJ1Zi5jCj4gQEAgLTAsMCArMSwy ODcgQEAKPiArLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEdQTC0yLjAKPiArI2luY2x1ZGUg PGxpbnV4L2luaXQuaD4KPiArI2luY2x1ZGUgPGxpbnV4L21vZHVsZS5oPgo+ICsjaW5jbHVkZSA8 bGludXgvZGV2aWNlLmg+Cj4gKyNpbmNsdWRlIDxsaW51eC9rZXJuZWwuaD4KPiArI2luY2x1ZGUg PGxpbnV4L3NsYWIuaD4KPiArI2luY2x1ZGUgPGxpbnV4L21pc2NkZXZpY2UuaD4KPiArI2luY2x1 ZGUgPGxpbnV4L2RtYS1idWYuaD4KPiArI2luY2x1ZGUgPGxpbnV4L2hpZ2htZW0uaD4KPiArI2lu Y2x1ZGUgPGxpbnV4L2NyZWQuaD4KPiArI2luY2x1ZGUgPGxpbnV4L3NobWVtX2ZzLmg+Cj4gKyNp bmNsdWRlIDxsaW51eC9tZW1mZC5oPgoKQ291bGQgeW91IHBsZWFzZSBrZWVwIHRoZSAjaW5jbHVk ZSBhbHBoYWJldGljYWxseSBzb3J0ZWQgPyBJdCBoZWxwcyBsb2NhdGluZyAKZHVwbGljYXRlcy4K Cj4gKyNpbmNsdWRlIDx1YXBpL2xpbnV4L3VkbWFidWYuaD4KCkkgdGhpbmsgeW91IGNhbiBqdXN0 ICNpbmNsdWRlIDxsaW51eC91ZG1hYnVmLmg+LCBubyBuZWVkIHRvIHVzZSB0aGUgdWFwaS8gCnBy ZWZpeC4KCj4gK3N0cnVjdCB1ZG1hYnVmIHsKPiArCXUzMiBwYWdlY291bnQ7Cj4gKwlzdHJ1Y3Qg cGFnZSAqKnBhZ2VzOwo+ICt9Owo+ICsKPiArc3RhdGljIGludCB1ZG1hYnVmX3ZtX2ZhdWx0KHN0 cnVjdCB2bV9mYXVsdCAqdm1mKQo+ICt7Cj4gKwlzdHJ1Y3Qgdm1fYXJlYV9zdHJ1Y3QgKnZtYSA9 IHZtZi0+dm1hOwo+ICsJc3RydWN0IHVkbWFidWYgKnVidWYgPSB2bWEtPnZtX3ByaXZhdGVfZGF0 YTsKPiArCj4gKwlpZiAoV0FSTl9PTih2bWYtPnBnb2ZmID49IHVidWYtPnBhZ2Vjb3VudCkpCj4g KwkJcmV0dXJuIFZNX0ZBVUxUX1NJR0JVUzsKCkp1c3QgY3VyaW91cywgd2hlbiBkbyB5b3UgZXhw ZWN0IHRoaXMgdG8gaGFwcGVuID8KCj4gKwl2bWYtPnBhZ2UgPSB1YnVmLT5wYWdlc1t2bWYtPnBn b2ZmXTsKPiArCWdldF9wYWdlKHZtZi0+cGFnZSk7Cj4gKwlyZXR1cm4gMDsKPiArfQo+ICsKPiAr c3RhdGljIGNvbnN0IHN0cnVjdCB2bV9vcGVyYXRpb25zX3N0cnVjdCB1ZG1hYnVmX3ZtX29wcyA9 IHsKPiArCS5mYXVsdCA9IHVkbWFidWZfdm1fZmF1bHQsCj4gK307Cj4gKwo+ICtzdGF0aWMgaW50 IG1tYXBfdWRtYWJ1ZihzdHJ1Y3QgZG1hX2J1ZiAqYnVmLCBzdHJ1Y3Qgdm1fYXJlYV9zdHJ1Y3Qg KnZtYSkKPiArewo+ICsJc3RydWN0IHVkbWFidWYgKnVidWYgPSBidWYtPnByaXY7Cj4gKwo+ICsJ aWYgKCh2bWEtPnZtX2ZsYWdzICYgKFZNX1NIQVJFRCB8IFZNX01BWVNIQVJFKSkgPT0gMCkKPiAr CQlyZXR1cm4gLUVJTlZBTDsKPiArCj4gKwl2bWEtPnZtX29wcyA9ICZ1ZG1hYnVmX3ZtX29wczsK PiArCXZtYS0+dm1fcHJpdmF0ZV9kYXRhID0gdWJ1ZjsKPiArCXJldHVybiAwOwo+ICt9Cj4gKwo+ ICtzdGF0aWMgc3RydWN0IHNnX3RhYmxlICptYXBfdWRtYWJ1ZihzdHJ1Y3QgZG1hX2J1Zl9hdHRh Y2htZW50ICphdCwKPiArCQkJCSAgICBlbnVtIGRtYV9kYXRhX2RpcmVjdGlvbiBkaXJlY3Rpb24p Cj4gK3sKPiArCXN0cnVjdCB1ZG1hYnVmICp1YnVmID0gYXQtPmRtYWJ1Zi0+cHJpdjsKPiArCXN0 cnVjdCBzZ190YWJsZSAqc2c7Cj4gKwo+ICsJc2cgPSBremFsbG9jKHNpemVvZigqc2cpLCBHRlBf S0VSTkVMKTsKPiArCWlmICghc2cpCj4gKwkJZ290byBlcnIxOwoKWW91IGNhbiByZXR1cm4gRVJS X1BUUigtRU5PTUVNKSBkaXJlY3RseS4KCj4gKwlpZiAoc2dfYWxsb2NfdGFibGVfZnJvbV9wYWdl cyhzZywgdWJ1Zi0+cGFnZXMsIHVidWYtPnBhZ2Vjb3VudCwKPiArCQkJCSAgICAgIDAsIHVidWYt PnBhZ2Vjb3VudCA8PCBQQUdFX1NISUZULAo+ICsJCQkJICAgICAgR0ZQX0tFUk5FTCkgPCAwKQoK U2hvdWxkbid0IHlvdSBwcm9wYWdhdGUgdGhlIHJldHVybiB2YWx1ZSBmcm9tIHNnX2FsbG9jX3Rh YmxlX2Zyb21fcGFnZXMoKSA/Cgo+ICsJCWdvdG8gZXJyMjsKPiArCWlmICghZG1hX21hcF9zZyhh dC0+ZGV2LCBzZy0+c2dsLCBzZy0+bmVudHMsIGRpcmVjdGlvbikpCj4gKwkJZ290byBlcnIzOwo+ ICsKPiArCXJldHVybiBzZzsKPiArCj4gK2VycjM6Cj4gKwlzZ19mcmVlX3RhYmxlKHNnKTsKPiAr ZXJyMjoKPiArCWtmcmVlKHNnKTsKPiArZXJyMToKPiArCXJldHVybiBFUlJfUFRSKC1FTk9NRU0p OwoKWW91IGNhbiBtZXJnZSBhbGwgdGhlc2UgbGFiZWxzIHdpdGgKCmVycm9yOgoJaWYgKHNnKSB7 CgkJc2dfZnJlZV90YWJsZShzZyk7CgkJa2ZyZWUoc2cpOwoJfQoKCXJldHVybiBFUlJfUFRSKC1F Tk9NRU0pOwoKPiArfQo+ICsKPiArc3RhdGljIHZvaWQgdW5tYXBfdWRtYWJ1ZihzdHJ1Y3QgZG1h X2J1Zl9hdHRhY2htZW50ICphdCwKPiArCQkJICBzdHJ1Y3Qgc2dfdGFibGUgKnNnLAo+ICsJCQkg IGVudW0gZG1hX2RhdGFfZGlyZWN0aW9uIGRpcmVjdGlvbikKPiArewo+ICsJc2dfZnJlZV90YWJs ZShzZyk7Cj4gKwlrZnJlZShzZyk7Cj4gK30KPiArCj4gK3N0YXRpYyB2b2lkIHJlbGVhc2VfdWRt YWJ1ZihzdHJ1Y3QgZG1hX2J1ZiAqYnVmKQo+ICt7Cj4gKwlzdHJ1Y3QgdWRtYWJ1ZiAqdWJ1ZiA9 IGJ1Zi0+cHJpdjsKPiArCXBnb2ZmX3QgcGc7Cj4gKwo+ICsJZm9yIChwZyA9IDA7IHBnIDwgdWJ1 Zi0+cGFnZWNvdW50OyBwZysrKQoKU2hvdWxkbid0IGJvdGggcGcgYW5kIHBhZ2Vjb3VudCBoYXZl IHRoZSBzYW1lIHR5cGUgPyBXaHkgZG9lcyB0aGUgbG9vcCBjb3VudGVyIApxdWFsaWZ5IGZvciBh IHBnb2ZmX3QgYW5kIG5vdCB0aGUgcGFnZWNvdW50IGZpZWxkID8gR3JhbnRlZCwgdGhlIHBnb2Zm X3QgaXMgCmRvY3VtZW50ZWQgYXMgIlRoZSB0eXBlIG9mIGFuIGluZGV4IGluIHRoZSBwYWdlIGNh Y2hlIiwgc28gcGFnZWNvdW50IGRvZXNuJ3QgCnJlYWxseSBxdWFsaXR5LCBidXQgdGhlIGZhY3Qg dGhhdCBvbmUgaXMgYW4gdW5zaWduZWQgbG9uZyBhbmQgdGhlIG90aGVyIGEgdTMyIAptYWtlcyBt ZSB0aGluayB0aGF0IHNvbWV0aGluZyBpcyB3cm9uZy4KCj4gKwkJcHV0X3BhZ2UodWJ1Zi0+cGFn ZXNbcGddKTsKPiArCWtmcmVlKHVidWYtPnBhZ2VzKTsKPiArCWtmcmVlKHVidWYpOwo+ICt9Cj4g Kwo+ICtzdGF0aWMgdm9pZCAqa21hcF91ZG1hYnVmKHN0cnVjdCBkbWFfYnVmICpidWYsIHVuc2ln bmVkIGxvbmcgcGFnZV9udW0pCj4gK3sKPiArCXN0cnVjdCB1ZG1hYnVmICp1YnVmID0gYnVmLT5w cml2Owo+ICsJc3RydWN0IHBhZ2UgKnBhZ2UgPSB1YnVmLT5wYWdlc1twYWdlX251bV07Cj4gKwo+ ICsJcmV0dXJuIGttYXAocGFnZSk7Cj4gK30KPiArCj4gK3N0YXRpYyB2b2lkIGt1bm1hcF91ZG1h YnVmKHN0cnVjdCBkbWFfYnVmICpidWYsIHVuc2lnbmVkIGxvbmcgcGFnZV9udW0sCj4gKwkJCSAg IHZvaWQgKnZhZGRyKQo+ICt7Cj4gKwlrdW5tYXAodmFkZHIpOwo+ICt9Cj4gKwo+ICtzdGF0aWMg c3RydWN0IGRtYV9idWZfb3BzIHVkbWFidWZfb3BzID0gewoKc3RhdGljIGNvbnN0IHN0cnVjdAoK PiArCS5tYXBfZG1hX2J1ZgkgID0gbWFwX3VkbWFidWYsCj4gKwkudW5tYXBfZG1hX2J1ZgkgID0g dW5tYXBfdWRtYWJ1ZiwKPiArCS5yZWxlYXNlCSAgPSByZWxlYXNlX3VkbWFidWYsCj4gKwkubWFw CQkgID0ga21hcF91ZG1hYnVmLAo+ICsJLnVubWFwCQkgID0ga3VubWFwX3VkbWFidWYsCj4gKwku bW1hcAkJICA9IG1tYXBfdWRtYWJ1ZiwKPiArfTsKPiArCj4gKyNkZWZpbmUgU0VBTFNfV0FOVEVE IChGX1NFQUxfU0hSSU5LKQo+ICsjZGVmaW5lIFNFQUxTX0RFTklFRCAoRl9TRUFMX1dSSVRFKQo+ ICsKPiArc3RhdGljIGxvbmcgdWRtYWJ1Zl9jcmVhdGUoc3RydWN0IHVkbWFidWZfY3JlYXRlX2xp c3QgKmhlYWQsCj4gKwkJCSAgIHN0cnVjdCB1ZG1hYnVmX2NyZWF0ZV9pdGVtICpsaXN0KQoKVGhv c2UgdHdvIHN0cnVjdHVyZXMgYXJlIG5vdCBtb2RpZmllZCBieSB0aGUgZnVuY3Rpb24sIHlvdSBj YW4gbWFrZSB0aGVtIApjb25zdC4KCj4gK3sKPiArCURFRklORV9ETUFfQlVGX0VYUE9SVF9JTkZP KGV4cF9pbmZvKTsKPiArCXN0cnVjdCBmaWxlICptZW1mZCA9IE5VTEw7Cj4gKwlzdHJ1Y3QgdWRt YWJ1ZiAqdWJ1ZjsKPiArCXN0cnVjdCBkbWFfYnVmICpidWY7Cj4gKwlwZ29mZl90IHBnb2ZmLCBw Z2NudCwgcGdpZHgsIHBnYnVmOwo+ICsJc3RydWN0IHBhZ2UgKnBhZ2U7Cj4gKwlpbnQgc2VhbHMs IHJldCA9IC1FSU5WQUw7Cj4gKwl1MzIgaSwgZmxhZ3M7Cj4gKwo+ICsJdWJ1ZiA9IGt6YWxsb2Mo c2l6ZW9mKHN0cnVjdCB1ZG1hYnVmKSwgR0ZQX0tFUk5FTCk7CgpzaXplb2YoKnVidWYpCgo+ICsJ aWYgKCF1YnVmKQo+ICsJCXJldHVybiAtRU5PTUVNOwo+ICsKPiArCWZvciAoaSA9IDA7IGkgPCBo ZWFkLT5jb3VudDsgaSsrKSB7Cj4gKwkJaWYgKCFJU19BTElHTkVEKGxpc3RbaV0ub2Zmc2V0LCBQ QUdFX1NJWkUpKQo+ICsJCQlnb3RvIGVycl9mcmVlX3VidWY7Cj4gKwkJaWYgKCFJU19BTElHTkVE KGxpc3RbaV0uc2l6ZSwgUEFHRV9TSVpFKSkKPiArCQkJZ290byBlcnJfZnJlZV91YnVmOwo+ICsJ CXVidWYtPnBhZ2Vjb3VudCArPSBsaXN0W2ldLnNpemUgPj4gUEFHRV9TSElGVDsKCklzIHRoZXJl IGEgcmlzayBvZiBvdmVyZmxvd2luZyBwYWdlY291bnQgPwoKPiArCX0KPiArCXVidWYtPnBhZ2Vz ID0ga21hbGxvY19hcnJheSh1YnVmLT5wYWdlY291bnQsIHNpemVvZihzdHJ1Y3QgcGFnZSAqKSwK PiArCQkJCSAgICBHRlBfS0VSTkVMKTsKCnNpemVvZigqdWJ1Zi0+cGFnZXMpCgo+ICsJaWYgKCF1 YnVmLT5wYWdlcykgewo+ICsJCXJldCA9IC1FTk9NRU07Cj4gKwkJZ290byBlcnJfZnJlZV91YnVm Owo+ICsJfQo+ICsKPiArCXBnYnVmID0gMDsKPiArCWZvciAoaSA9IDA7IGkgPCBoZWFkLT5jb3Vu dDsgaSsrKSB7Cj4gKwkJbWVtZmQgPSBmZ2V0KGxpc3RbaV0ubWVtZmQpOwo+ICsJCWlmICghbWVt ZmQpCj4gKwkJCWdvdG8gZXJyX3B1dF9wYWdlczsKPiArCQlpZiAoIXNobWVtX21hcHBpbmcoZmls ZV9pbm9kZShtZW1mZCktPmlfbWFwcGluZykpCj4gKwkJCWdvdG8gZXJyX3B1dF9wYWdlczsKPiAr CQlzZWFscyA9IG1lbWZkX2ZjbnRsKG1lbWZkLCBGX0dFVF9TRUFMUywgMCk7Cj4gKwkJaWYgKHNl YWxzID09IC1FSU5WQUwgfHwKPiArCQkgICAgKHNlYWxzICYgU0VBTFNfV0FOVEVEKSAhPSBTRUFM U19XQU5URUQgfHwKPiArCQkgICAgKHNlYWxzICYgU0VBTFNfREVOSUVEKSAhPSAwKQo+ICsJCQln b3RvIGVycl9wdXRfcGFnZXM7CgpBbGwgdGhlc2UgY29uZGl0aW9ucyB3aWxsIHJldHVybiAtRUlO VkFMLiBJJ20gbm90IGZhbWlsaWFyIHdpdGggdGhlIG1lbWZkIEFQSSwgCnNob3VsZCBzb21lIGVy cm9yIGNvbmRpdGlvbnMgcmV0dXJuIGEgZGlmZmVyZW50IGVycm9yIGNvZGUgdG8gbWFrZSB0aGVt IApkaXN0aW5ndWlzaGFibGUgYnkgdXNlcnNwYWNlID8KCj4gKwkJcGdvZmYgPSBsaXN0W2ldLm9m ZnNldCA+PiBQQUdFX1NISUZUOwo+ICsJCXBnY250ID0gbGlzdFtpXS5zaXplICAgPj4gUEFHRV9T SElGVDsKPiArCQlmb3IgKHBnaWR4ID0gMDsgcGdpZHggPCBwZ2NudDsgcGdpZHgrKykgewo+ICsJ CQlwYWdlID0gc2htZW1fcmVhZF9tYXBwaW5nX3BhZ2UoCj4gKwkJCQlmaWxlX2lub2RlKG1lbWZk KS0+aV9tYXBwaW5nLCBwZ29mZiArIHBnaWR4KTsKCkNhbid0IHBnb2ZmICsgcGdjbnQgb3ZlcmZs b3cgdGhlIHRvdGFsIG51bWJlciBvZiBhdmlhbGJsZSBwYWdlcyA/Cgo+ICsJCQlpZiAoSVNfRVJS KHBhZ2UpKSB7Cj4gKwkJCQlyZXQgPSBQVFJfRVJSKHBhZ2UpOwo+ICsJCQkJZ290byBlcnJfcHV0 X3BhZ2VzOwo+ICsJCQl9Cj4gKwkJCXVidWYtPnBhZ2VzW3BnYnVmKytdID0gcGFnZTsKPiArCQl9 Cj4gKwkJZnB1dChtZW1mZCk7Cj4gKwl9Cj4gKwltZW1mZCA9IE5VTEw7CgpJJ2QgbW92ZSB0aGlz IGxpbmUganVzdCBhZnRlciBmcHV0KG1lbWZkKSBpbnNpZGUgdGhlIGxvb3AgdG8gYXZvaWQgCmlu dHJvZHVjdGlvbiBidWdzIGluIHRoZSBmdXR1cmUgaWYgd2UgYWRkIGNvZGUgdGhhdCBjYW4gYnJl YWsgZnJvbSB0aGUgbG9vcCAKYmVmb3JlIHRoZSBmZ2V0KCkgY2FsbC4KCj4gKwlleHBfaW5mby5v cHMgID0gJnVkbWFidWZfb3BzOwo+ICsJZXhwX2luZm8uc2l6ZSA9IHVidWYtPnBhZ2Vjb3VudCA8 PCBQQUdFX1NISUZUOwo+ICsJZXhwX2luZm8ucHJpdiA9IHVidWY7Cj4gKwo+ICsJYnVmID0gZG1h X2J1Zl9leHBvcnQoJmV4cF9pbmZvKTsKPiArCWlmIChJU19FUlIoYnVmKSkgewo+ICsJCXJldCA9 IFBUUl9FUlIoYnVmKTsKPiArCQlnb3RvIGVycl9wdXRfcGFnZXM7Cj4gKwl9Cj4gKwo+ICsJZmxh Z3MgPSAwOwo+ICsJaWYgKGhlYWQtPmZsYWdzICYgVURNQUJVRl9GTEFHU19DTE9FWEVDKQo+ICsJ CWZsYWdzIHw9IE9fQ0xPRVhFQzsKPiArCXJldHVybiBkbWFfYnVmX2ZkKGJ1ZiwgZmxhZ3MpOwo+ ICsKPiArZXJyX3B1dF9wYWdlczoKPiArCXdoaWxlIChwZ2J1ZiA+IDApCj4gKwkJcHV0X3BhZ2Uo dWJ1Zi0+cGFnZXNbLS1wZ2J1Zl0pOwoKSWYgeW91IGluaXRpYWxpemUgcGdidWYgdG8gMCB5b3Ug Y2FuIG1lcmdlIHRoZSB0d28gZXJyb3IgbGFiZWxzLgoKPiArZXJyX2ZyZWVfdWJ1ZjoKPiArCWZw dXQobWVtZmQpOwo+ICsJa2ZyZWUodWJ1Zi0+cGFnZXMpOwo+ICsJa2ZyZWUodWJ1Zik7Cj4gKwly ZXR1cm4gcmV0Owo+ICt9Cj4gKwo+ICtzdGF0aWMgbG9uZyB1ZG1hYnVmX2lvY3RsX2NyZWF0ZShz dHJ1Y3QgZmlsZSAqZmlscCwgdW5zaWduZWQgbG9uZyBhcmcpCj4gK3sKPiArCXN0cnVjdCB1ZG1h YnVmX2NyZWF0ZSBjcmVhdGU7Cj4gKwlzdHJ1Y3QgdWRtYWJ1Zl9jcmVhdGVfbGlzdCBoZWFkOwo+ ICsJc3RydWN0IHVkbWFidWZfY3JlYXRlX2l0ZW0gbGlzdDsKPiArCj4gKwlpZiAoY29weV9mcm9t X3VzZXIoJmNyZWF0ZSwgKHZvaWQgX191c2VyICopYXJnLAo+ICsJCQkgICBzaXplb2Yoc3RydWN0 IHVkbWFidWZfY3JlYXRlKSkpCgpzaXplb2YoY3JlYXRlKQoKPiArCQlyZXR1cm4gLUVGQVVMVDsK PiArCj4gKwloZWFkLmZsYWdzICA9IGNyZWF0ZS5mbGFnczsKPiArCWhlYWQuY291bnQgID0gMTsK PiArCWxpc3QubWVtZmQgID0gY3JlYXRlLm1lbWZkOwo+ICsJbGlzdC5vZmZzZXQgPSBjcmVhdGUu b2Zmc2V0Owo+ICsJbGlzdC5zaXplICAgPSBjcmVhdGUuc2l6ZTsKPiArCj4gKwlyZXR1cm4gdWRt YWJ1Zl9jcmVhdGUoJmhlYWQsICZsaXN0KTsKPiArfQo+ICsKPiArc3RhdGljIGxvbmcgdWRtYWJ1 Zl9pb2N0bF9jcmVhdGVfbGlzdChzdHJ1Y3QgZmlsZSAqZmlscCwgdW5zaWduZWQgbG9uZyBhcmcp Cj4gK3sKPiArCXN0cnVjdCB1ZG1hYnVmX2NyZWF0ZV9saXN0IGhlYWQ7Cj4gKwlzdHJ1Y3QgdWRt YWJ1Zl9jcmVhdGVfaXRlbSAqbGlzdDsKPiArCWludCByZXQgPSAtRUlOVkFMOwo+ICsJdTMyIGxz aXplOwo+ICsKPiArCWlmIChjb3B5X2Zyb21fdXNlcigmaGVhZCwgKHZvaWQgX191c2VyICopYXJn LCBzaXplb2YoaGVhZCkpKQo+ICsJCXJldHVybiAtRUZBVUxUOwo+ICsJaWYgKGhlYWQuY291bnQg PiAxMDI0KQo+ICsJCXJldHVybiAtRUlOVkFMOwo+ICsJbHNpemUgPSBzaXplb2Yoc3RydWN0IHVk bWFidWZfY3JlYXRlX2l0ZW0pICogaGVhZC5jb3VudDsKPiArCWxpc3QgPSBtZW1kdXBfdXNlcigo dm9pZCBfX3VzZXIgKikoYXJnICsgc2l6ZW9mKGhlYWQpKSwgbHNpemUpOwo+ICsJaWYgKElTX0VS UihsaXN0KSkKPiArCQlyZXR1cm4gUFRSX0VSUihsaXN0KTsKPiArCj4gKwlyZXQgPSB1ZG1hYnVm X2NyZWF0ZSgmaGVhZCwgbGlzdCk7Cj4gKwlrZnJlZShsaXN0KTsKPiArCXJldHVybiByZXQ7Cj4g K30KPiArCj4gK3N0YXRpYyBsb25nIHVkbWFidWZfaW9jdGwoc3RydWN0IGZpbGUgKmZpbHAsIHVu c2lnbmVkIGludCBpb2N0bCwKPiArCQkJICB1bnNpZ25lZCBsb25nIGFyZykKPiArewo+ICsJbG9u ZyByZXQ7Cj4gKwo+ICsJc3dpdGNoIChpb2N0bCkgewo+ICsJY2FzZSBVRE1BQlVGX0NSRUFURToK PiArCQlyZXQgPSB1ZG1hYnVmX2lvY3RsX2NyZWF0ZShmaWxwLCBhcmcpOwo+ICsJCWJyZWFrOwo+ ICsJY2FzZSBVRE1BQlVGX0NSRUFURV9MSVNUOgo+ICsJCXJldCA9IHVkbWFidWZfaW9jdGxfY3Jl YXRlX2xpc3QoZmlscCwgYXJnKTsKPiArCQlicmVhazsKPiArCWRlZmF1bHQ6Cj4gKwkJcmV0ID0g LUVJTlZBTDsKClRoZSBwcm9wZXIgZXJyb3IgY29kZSBmb3IgaW52YWxpZCBpb2N0bHMgaXMgLUVO T1RUWS4KCj4gKwkJYnJlYWs7Cj4gKwl9Cj4gKwlyZXR1cm4gcmV0Owo+ICt9Cj4gKwo+ICtzdGF0 aWMgY29uc3Qgc3RydWN0IGZpbGVfb3BlcmF0aW9ucyB1ZG1hYnVmX2ZvcHMgPSB7Cj4gKwkub3du ZXIJCT0gVEhJU19NT0RVTEUsCj4gKwkudW5sb2NrZWRfaW9jdGwgPSB1ZG1hYnVmX2lvY3RsLAo+ ICt9Owo+ICsKPiArc3RhdGljIHN0cnVjdCBtaXNjZGV2aWNlIHVkbWFidWZfbWlzYyA9IHsKPiAr CS5taW5vciAgICAgICAgICA9IE1JU0NfRFlOQU1JQ19NSU5PUiwKPiArCS5uYW1lICAgICAgICAg ICA9ICJ1ZG1hYnVmIiwKPiArCS5mb3BzICAgICAgICAgICA9ICZ1ZG1hYnVmX2ZvcHMsCj4gK307 Cj4gKwo+ICtzdGF0aWMgaW50IF9faW5pdCB1ZG1hYnVmX2Rldl9pbml0KHZvaWQpCj4gK3sKPiAr CXJldHVybiBtaXNjX3JlZ2lzdGVyKCZ1ZG1hYnVmX21pc2MpOwo+ICt9Cj4gKwo+ICtzdGF0aWMg dm9pZCBfX2V4aXQgdWRtYWJ1Zl9kZXZfZXhpdCh2b2lkKQo+ICt7Cj4gKwltaXNjX2RlcmVnaXN0 ZXIoJnVkbWFidWZfbWlzYyk7Cj4gK30KPiArCj4gK21vZHVsZV9pbml0KHVkbWFidWZfZGV2X2lu aXQpCj4gK21vZHVsZV9leGl0KHVkbWFidWZfZGV2X2V4aXQpCj4gKwo+ICtNT0RVTEVfQVVUSE9S KCJHZXJkIEhvZmZtYW5uIDxrcmF4ZWxAcmVkaGF0LmNvbT4iKTsKPiArTU9EVUxFX0xJQ0VOU0Uo IkdQTCB2MiIpOwo+IGRpZmYgLS1naXQgYS90b29scy90ZXN0aW5nL3NlbGZ0ZXN0cy9kcml2ZXJz L2RtYS1idWYvdWRtYWJ1Zi5jCj4gYi90b29scy90ZXN0aW5nL3NlbGZ0ZXN0cy9kcml2ZXJzL2Rt YS1idWYvdWRtYWJ1Zi5jIG5ldyBmaWxlIG1vZGUgMTAwNjQ0Cj4gaW5kZXggMDAwMDAwMDAwMC4u Mzc2YjFkNjczMAo+IC0tLSAvZGV2L251bGwKPiArKysgYi90b29scy90ZXN0aW5nL3NlbGZ0ZXN0 cy9kcml2ZXJzL2RtYS1idWYvdWRtYWJ1Zi5jCj4gQEAgLTAsMCArMSw5NiBAQAo+ICsvLyBTUERY LUxpY2Vuc2UtSWRlbnRpZmllcjogR1BMLTIuMAo+ICsjaW5jbHVkZSA8c3RkaW8uaD4KPiArI2lu Y2x1ZGUgPHN0ZGxpYi5oPgo+ICsjaW5jbHVkZSA8dW5pc3RkLmg+Cj4gKyNpbmNsdWRlIDxzdHJp bmcuaD4KPiArI2luY2x1ZGUgPGVycm5vLmg+Cj4gKyNpbmNsdWRlIDxmY250bC5oPgo+ICsjaW5j bHVkZSA8bWFsbG9jLmg+Cj4gKwo+ICsjaW5jbHVkZSA8c3lzL2lvY3RsLmg+Cj4gKyNpbmNsdWRl IDxzeXMvc3lzY2FsbC5oPgo+ICsjaW5jbHVkZSA8bGludXgvbWVtZmQuaD4KPiArI2luY2x1ZGUg PGxpbnV4L3VkbWFidWYuaD4KPiArCj4gKyNkZWZpbmUgVEVTVF9QUkVGSVgJImRyaXZlcnMvZG1h LWJ1Zi91ZG1hYnVmIgo+ICsjZGVmaW5lIE5VTV9QQUdFUyAgICAgICA0Cj4gKwo+ICtzdGF0aWMg aW50IG1lbWZkX2NyZWF0ZShjb25zdCBjaGFyICpuYW1lLCB1bnNpZ25lZCBpbnQgZmxhZ3MpCj4g K3sKPiArCXJldHVybiBzeXNjYWxsKF9fTlJfbWVtZmRfY3JlYXRlLCBuYW1lLCBmbGFncyk7Cj4g K30KPiArCj4gK2ludCBtYWluKGludCBhcmdjLCBjaGFyICphcmd2W10pCj4gK3sKPiArCXN0cnVj dCB1ZG1hYnVmX2NyZWF0ZSBjcmVhdGU7Cj4gKwlpbnQgZGV2ZmQsIG1lbWZkLCBidWYsIHJldDsK PiArCW9mZl90IHNpemU7Cj4gKwl2b2lkICptZW07Cj4gKwo+ICsJZGV2ZmQgPSBvcGVuKCIvZGV2 L3VkbWFidWYiLCBPX1JEV1IpOwo+ICsJaWYgKGRldmZkIDwgMCkgewo+ICsJCXByaW50ZigiJXM6 IFtza2lwLG5vLXVkbWFidWZdXG4iLCBURVNUX1BSRUZJWCk7Cj4gKwkJZXhpdCg3Nyk7Cj4gKwl9 Cj4gKwo+ICsJbWVtZmQgPSBtZW1mZF9jcmVhdGUoInVkbWFidWYtdGVzdCIsIE1GRF9DTE9FWEVD KTsKPiArCWlmIChtZW1mZCA8IDApIHsKPiArCQlwcmludGYoIiVzOiBbc2tpcCxuby1tZW1mZF1c biIsIFRFU1RfUFJFRklYKTsKPiArCQlleGl0KDc3KTsKPiArCX0KPiArCj4gKwlzaXplID0gZ2V0 cGFnZXNpemUoKSAqIE5VTV9QQUdFUzsKPiArCXJldCA9IGZ0cnVuY2F0ZShtZW1mZCwgc2l6ZSk7 Cj4gKwlpZiAocmV0ID09IC0xKSB7Cj4gKwkJcHJpbnRmKCIlczogW0ZBSUwsbWVtZmQtdHJ1bmNh dGVdXG4iLCBURVNUX1BSRUZJWCk7Cj4gKwkJZXhpdCgxKTsKPiArCX0KPiArCj4gKwltZW1zZXQo JmNyZWF0ZSwgMCwgc2l6ZW9mKGNyZWF0ZSkpOwo+ICsKPiArCS8qIHNob3VsZCBmYWlsIChvZmZz ZXQgbm90IHBhZ2UgYWxpZ25lZCkgKi8KPiArCWNyZWF0ZS5tZW1mZCAgPSBtZW1mZDsKPiArCWNy ZWF0ZS5vZmZzZXQgPSBnZXRwYWdlc2l6ZSgpLzI7Cj4gKwljcmVhdGUuc2l6ZSAgID0gZ2V0cGFn ZXNpemUoKTsKPiArCWJ1ZiA9IGlvY3RsKGRldmZkLCBVRE1BQlVGX0NSRUFURSwgJmNyZWF0ZSk7 Cj4gKwlpZiAoYnVmID49IDApIHsKPiArCQlwcmludGYoIiVzOiBbRkFJTCx0ZXN0LTFdXG4iLCBU RVNUX1BSRUZJWCk7Cj4gKwkJZXhpdCgxKTsKPiArCX0KPiArCj4gKwkvKiBzaG91bGQgZmFpbCAo c2l6ZSBub3QgbXVsdGlwbGUgb2YgcGFnZSkgKi8KPiArCWNyZWF0ZS5tZW1mZCAgPSBtZW1mZDsK PiArCWNyZWF0ZS5vZmZzZXQgPSAwOwo+ICsJY3JlYXRlLnNpemUgICA9IGdldHBhZ2VzaXplKCkv MjsKPiArCWJ1ZiA9IGlvY3RsKGRldmZkLCBVRE1BQlVGX0NSRUFURSwgJmNyZWF0ZSk7Cj4gKwlp ZiAoYnVmID49IDApIHsKPiArCQlwcmludGYoIiVzOiBbRkFJTCx0ZXN0LTJdXG4iLCBURVNUX1BS RUZJWCk7Cj4gKwkJZXhpdCgxKTsKPiArCX0KPiArCj4gKwkvKiBzaG91bGQgZmFpbCAobm90IG1l bWZkKSAqLwo+ICsJY3JlYXRlLm1lbWZkICA9IDA7IC8qIHN0ZGluICovCj4gKwljcmVhdGUub2Zm c2V0ID0gMDsKPiArCWNyZWF0ZS5zaXplICAgPSBzaXplOwo+ICsJYnVmID0gaW9jdGwoZGV2ZmQs IFVETUFCVUZfQ1JFQVRFLCAmY3JlYXRlKTsKPiArCWlmIChidWYgPj0gMCkgewo+ICsJCXByaW50 ZigiJXM6IFtGQUlMLHRlc3QtM11cbiIsIFRFU1RfUFJFRklYKTsKPiArCQlleGl0KDEpOwo+ICsJ fQo+ICsKPiArCS8qIHNob3VsZCB3b3JrICovCj4gKwljcmVhdGUubWVtZmQgID0gbWVtZmQ7Cj4g KwljcmVhdGUub2Zmc2V0ID0gMDsKPiArCWNyZWF0ZS5zaXplICAgPSBzaXplOwo+ICsJYnVmID0g aW9jdGwoZGV2ZmQsIFVETUFCVUZfQ1JFQVRFLCAmY3JlYXRlKTsKPiArCWlmIChidWYgPCAwKSB7 Cj4gKwkJcHJpbnRmKCIlczogW0ZBSUwsdGVzdC00XVxuIiwgVEVTVF9QUkVGSVgpOwo+ICsJCWV4 aXQoMSk7Cj4gKwl9Cj4gKwo+ICsJZnByaW50ZihzdGRlcnIsICIlczogb2tcbiIsIFRFU1RfUFJF RklYKTsKPiArCWNsb3NlKGJ1Zik7Cj4gKwljbG9zZShtZW1mZCk7Cj4gKwljbG9zZShkZXZmZCk7 Cj4gKwlyZXR1cm4gMDsKPiArfQo+IGRpZmYgLS1naXQgYS9NQUlOVEFJTkVSUyBiL01BSU5UQUlO RVJTCj4gaW5kZXggYTViMjU2YjI1OS4uMTFhOWIwNDI3NyAxMDA2NDQKPiAtLS0gYS9NQUlOVEFJ TkVSUwo+ICsrKyBiL01BSU5UQUlORVJTCj4gQEAgLTE0OTM0LDYgKzE0OTM0LDE0IEBAIFM6CU1h aW50YWluZWQKPiAgRjoJRG9jdW1lbnRhdGlvbi9maWxlc3lzdGVtcy91ZGYudHh0Cj4gIEY6CWZz L3VkZi8KPiAKPiArVURNQUJVRiBEUklWRVIKPiArTToJR2VyZCBIb2ZmbWFubiA8a3JheGVsQHJl ZGhhdC5jb20+Cj4gK0w6CWRyaS1kZXZlbEBsaXN0cy5mcmVlZGVza3RvcC5vcmcKPiArUzoJTWFp bnRhaW5lZAo+ICtGOglkcml2ZXJzL2RtYS1idWYvdWRtYWJ1Zi5jCj4gK0Y6CWluY2x1ZGUvdWFw aS9saW51eC91ZG1hYnVmLmgKPiArRjoJdG9vbHMvdGVzdGluZy9zZWxmdGVzdHMvZHJpdmVycy9k bWEtYnVmL3VkbWFidWYuYwo+ICsKPiAgVURSQVcgVEFCTEVUCj4gIE06CUJhc3RpZW4gTm9jZXJh IDxoYWRlc3NAaGFkZXNzLm5ldD4KPiAgTDoJbGludXgtaW5wdXRAdmdlci5rZXJuZWwub3JnCj4g QEAgLTE1MzQzLDYgKzE1MzUxLDE0IEBAIEY6CWFyY2gveDg2L3VtLwo+ICBGOglmcy9ob3N0ZnMv Cj4gIEY6CWZzL2hwcGZzLwo+IAo+ICtVU0VSU1BBQ0UgRE1BIEJVRkZFUiBEUklWRVIKPiArTToJ R2VyZCBIb2ZmbWFubiA8a3JheGVsQHJlZGhhdC5jb20+Cj4gK1M6CU1haW50YWluZWQKPiArTDoJ ZHJpLWRldmVsQGxpc3RzLmZyZWVkZXNrdG9wLm9yZwo+ICtGOglkcml2ZXJzL2RtYS1idWYvdWRt YWJ1Zi5jCj4gK0Y6CWluY2x1ZGUvdWFwaS9saW51eC91ZG1hYnVmLmgKPiArVDoJZ2l0IGdpdDov L2Fub25naXQuZnJlZWRlc2t0b3Aub3JnL2RybS9kcm0tbWlzYwoKT25lIGVudHJ5IHNob3VsZCBi ZSBlbm91Z2guCgo+ICBVU0VSU1BBQ0UgSS9PIChVSU8pCj4gIE06CUdyZWcgS3JvYWgtSGFydG1h biA8Z3JlZ2toQGxpbnV4Zm91bmRhdGlvbi5vcmc+Cj4gIFM6CU1haW50YWluZWQKCltzbmlwXQoK LS0gClJlZ2FyZHMsCgpMYXVyZW50IFBpbmNoYXJ0CgoKCl9fX19fX19fX19fX19fX19fX19fX19f X19fX19fX19fX19fX19fX19fX19fX19fCmRyaS1kZXZlbCBtYWlsaW5nIGxpc3QKZHJpLWRldmVs QGxpc3RzLmZyZWVkZXNrdG9wLm9yZwpodHRwczovL2xpc3RzLmZyZWVkZXNrdG9wLm9yZy9tYWls bWFuL2xpc3RpbmZvL2RyaS1kZXZlbAo= From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.1 (2015-04-28) on archive.lwn.net X-Spam-Level: X-Spam-Status: No, score=-5.9 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=unavailable autolearn_force=no version=3.4.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by archive.lwn.net (Postfix) with ESMTP id 25DA87D57F for ; Mon, 10 Sep 2018 12:13:11 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728087AbeIJRGk (ORCPT ); Mon, 10 Sep 2018 13:06:40 -0400 Received: from perceval.ideasonboard.com ([213.167.242.64]:52380 "EHLO perceval.ideasonboard.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727649AbeIJRGk (ORCPT ); Mon, 10 Sep 2018 13:06:40 -0400 Received: from avalon.localnet (dfj612ybrt5fhg77mgycy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:2e86:4862:ef6a:2804]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 7C88E57; Mon, 10 Sep 2018 14:12:49 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1536581570; bh=jFQtJgBpVSsBXxRSWsfoaOqcDvjhr58bySPtC4h4HGQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ZipiXpJJczttw7Ps3eQ4c9LSnxRIlI6VGl3sOjqqopOqSzSx6iZOteVR4hvM+CAWw /E8Df673XlCF3FAv9knCCCpxMf6BDdk/v3IBlaDkxW7ScWD73PLlJuCb7/AeW8jgpP Rj0z5n6sJV63UJDy2/IJc55h1DmeHa/GxeYSly2k= From: Laurent Pinchart To: Gerd Hoffmann Cc: dri-devel@lists.freedesktop.org, David Airlie , Tomeu Vizoso , Daniel Vetter , Jonathan Corbet , Sumit Semwal , Shuah Khan , "open list:DOCUMENTATION" , open list , "open list:DMA BUFFER SHARING FRAMEWORK" , "moderated list:DMA BUFFER SHARING FRAMEWORK" , "open list:KERNEL SELFTEST FRAMEWORK" , linux-api@vger.kernel.org Subject: Re: [PATCH v7] Add udmabuf misc device Date: Mon, 10 Sep 2018 15:12:59 +0300 Message-ID: <21053714.0Xa7F2u2PE@avalon> Organization: Ideas on Board Oy In-Reply-To: <20180827093444.23623-1-kraxel@redhat.com> References: <20180827093444.23623-1-kraxel@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: 7Bit Content-Type: text/plain; charset="us-ascii" Sender: linux-doc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-doc@vger.kernel.org Hi Gerd, Thank you for the patch. CC'ing the linux-api mailing list as this creates a new userspace API. On Monday, 27 August 2018 12:34:44 EEST Gerd Hoffmann wrote: > A driver to let userspace turn memfd regions into dma-bufs. > > Use case: Allows qemu create dmabufs for the vga framebuffer or > virtio-gpu ressources. Then they can be passed around to display > those guest things on the host. To spice client for classic full > framebuffer display, and hopefully some day to wayland server for > seamless guest window display. > > qemu test branch: > https://git.kraxel.org/cgit/qemu/log/?h=sirius/udmabuf > > Cc: David Airlie > Cc: Tomeu Vizoso > Cc: Laurent Pinchart > Cc: Daniel Vetter > Signed-off-by: Gerd Hoffmann > --- > Documentation/ioctl/ioctl-number.txt | 1 + > include/uapi/linux/udmabuf.h | 33 +++ > drivers/dma-buf/udmabuf.c | 287 +++++++++++++++++++ > tools/testing/selftests/drivers/dma-buf/udmabuf.c | 96 ++++++++ > MAINTAINERS | 16 ++ > drivers/dma-buf/Kconfig | 8 + > drivers/dma-buf/Makefile | 1 + > tools/testing/selftests/drivers/dma-buf/Makefile | 5 + > 8 files changed, 447 insertions(+) > create mode 100644 include/uapi/linux/udmabuf.h > create mode 100644 drivers/dma-buf/udmabuf.c > create mode 100644 tools/testing/selftests/drivers/dma-buf/udmabuf.c > create mode 100644 tools/testing/selftests/drivers/dma-buf/Makefile [snip] > diff --git a/include/uapi/linux/udmabuf.h b/include/uapi/linux/udmabuf.h > new file mode 100644 > index 0000000000..46b6532ed8 > --- /dev/null > +++ b/include/uapi/linux/udmabuf.h > @@ -0,0 +1,33 @@ > +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ > +#ifndef _UAPI_LINUX_UDMABUF_H > +#define _UAPI_LINUX_UDMABUF_H > + > +#include > +#include > + > +#define UDMABUF_FLAGS_CLOEXEC 0x01 > + > +struct udmabuf_create { > + __u32 memfd; > + __u32 flags; > + __u64 offset; > + __u64 size; > +}; > + > +struct udmabuf_create_item { > + __u32 memfd; > + __u32 __pad; > + __u64 offset; > + __u64 size; > +}; > + > +struct udmabuf_create_list { > + __u32 flags; > + __u32 count; > + struct udmabuf_create_item list[]; > +}; > + > +#define UDMABUF_CREATE _IOW('u', 0x42, struct udmabuf_create) Why do you start at 0x42 if you reserve the 0x40-0x4f range ? > +#define UDMABUF_CREATE_LIST _IOW('u', 0x43, struct udmabuf_create_list) Where's the documentation ? :-) > +#endif /* _UAPI_LINUX_UDMABUF_H */ > diff --git a/drivers/dma-buf/udmabuf.c b/drivers/dma-buf/udmabuf.c > new file mode 100644 > index 0000000000..8e24204526 > --- /dev/null > +++ b/drivers/dma-buf/udmabuf.c > @@ -0,0 +1,287 @@ > +// SPDX-License-Identifier: GPL-2.0 > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include Could you please keep the #include alphabetically sorted ? It helps locating duplicates. > +#include I think you can just #include , no need to use the uapi/ prefix. > +struct udmabuf { > + u32 pagecount; > + struct page **pages; > +}; > + > +static int udmabuf_vm_fault(struct vm_fault *vmf) > +{ > + struct vm_area_struct *vma = vmf->vma; > + struct udmabuf *ubuf = vma->vm_private_data; > + > + if (WARN_ON(vmf->pgoff >= ubuf->pagecount)) > + return VM_FAULT_SIGBUS; Just curious, when do you expect this to happen ? > + vmf->page = ubuf->pages[vmf->pgoff]; > + get_page(vmf->page); > + return 0; > +} > + > +static const struct vm_operations_struct udmabuf_vm_ops = { > + .fault = udmabuf_vm_fault, > +}; > + > +static int mmap_udmabuf(struct dma_buf *buf, struct vm_area_struct *vma) > +{ > + struct udmabuf *ubuf = buf->priv; > + > + if ((vma->vm_flags & (VM_SHARED | VM_MAYSHARE)) == 0) > + return -EINVAL; > + > + vma->vm_ops = &udmabuf_vm_ops; > + vma->vm_private_data = ubuf; > + return 0; > +} > + > +static struct sg_table *map_udmabuf(struct dma_buf_attachment *at, > + enum dma_data_direction direction) > +{ > + struct udmabuf *ubuf = at->dmabuf->priv; > + struct sg_table *sg; > + > + sg = kzalloc(sizeof(*sg), GFP_KERNEL); > + if (!sg) > + goto err1; You can return ERR_PTR(-ENOMEM) directly. > + if (sg_alloc_table_from_pages(sg, ubuf->pages, ubuf->pagecount, > + 0, ubuf->pagecount << PAGE_SHIFT, > + GFP_KERNEL) < 0) Shouldn't you propagate the return value from sg_alloc_table_from_pages() ? > + goto err2; > + if (!dma_map_sg(at->dev, sg->sgl, sg->nents, direction)) > + goto err3; > + > + return sg; > + > +err3: > + sg_free_table(sg); > +err2: > + kfree(sg); > +err1: > + return ERR_PTR(-ENOMEM); You can merge all these labels with error: if (sg) { sg_free_table(sg); kfree(sg); } return ERR_PTR(-ENOMEM); > +} > + > +static void unmap_udmabuf(struct dma_buf_attachment *at, > + struct sg_table *sg, > + enum dma_data_direction direction) > +{ > + sg_free_table(sg); > + kfree(sg); > +} > + > +static void release_udmabuf(struct dma_buf *buf) > +{ > + struct udmabuf *ubuf = buf->priv; > + pgoff_t pg; > + > + for (pg = 0; pg < ubuf->pagecount; pg++) Shouldn't both pg and pagecount have the same type ? Why does the loop counter qualify for a pgoff_t and not the pagecount field ? Granted, the pgoff_t is documented as "The type of an index in the page cache", so pagecount doesn't really quality, but the fact that one is an unsigned long and the other a u32 makes me think that something is wrong. > + put_page(ubuf->pages[pg]); > + kfree(ubuf->pages); > + kfree(ubuf); > +} > + > +static void *kmap_udmabuf(struct dma_buf *buf, unsigned long page_num) > +{ > + struct udmabuf *ubuf = buf->priv; > + struct page *page = ubuf->pages[page_num]; > + > + return kmap(page); > +} > + > +static void kunmap_udmabuf(struct dma_buf *buf, unsigned long page_num, > + void *vaddr) > +{ > + kunmap(vaddr); > +} > + > +static struct dma_buf_ops udmabuf_ops = { static const struct > + .map_dma_buf = map_udmabuf, > + .unmap_dma_buf = unmap_udmabuf, > + .release = release_udmabuf, > + .map = kmap_udmabuf, > + .unmap = kunmap_udmabuf, > + .mmap = mmap_udmabuf, > +}; > + > +#define SEALS_WANTED (F_SEAL_SHRINK) > +#define SEALS_DENIED (F_SEAL_WRITE) > + > +static long udmabuf_create(struct udmabuf_create_list *head, > + struct udmabuf_create_item *list) Those two structures are not modified by the function, you can make them const. > +{ > + DEFINE_DMA_BUF_EXPORT_INFO(exp_info); > + struct file *memfd = NULL; > + struct udmabuf *ubuf; > + struct dma_buf *buf; > + pgoff_t pgoff, pgcnt, pgidx, pgbuf; > + struct page *page; > + int seals, ret = -EINVAL; > + u32 i, flags; > + > + ubuf = kzalloc(sizeof(struct udmabuf), GFP_KERNEL); sizeof(*ubuf) > + if (!ubuf) > + return -ENOMEM; > + > + for (i = 0; i < head->count; i++) { > + if (!IS_ALIGNED(list[i].offset, PAGE_SIZE)) > + goto err_free_ubuf; > + if (!IS_ALIGNED(list[i].size, PAGE_SIZE)) > + goto err_free_ubuf; > + ubuf->pagecount += list[i].size >> PAGE_SHIFT; Is there a risk of overflowing pagecount ? > + } > + ubuf->pages = kmalloc_array(ubuf->pagecount, sizeof(struct page *), > + GFP_KERNEL); sizeof(*ubuf->pages) > + if (!ubuf->pages) { > + ret = -ENOMEM; > + goto err_free_ubuf; > + } > + > + pgbuf = 0; > + for (i = 0; i < head->count; i++) { > + memfd = fget(list[i].memfd); > + if (!memfd) > + goto err_put_pages; > + if (!shmem_mapping(file_inode(memfd)->i_mapping)) > + goto err_put_pages; > + seals = memfd_fcntl(memfd, F_GET_SEALS, 0); > + if (seals == -EINVAL || > + (seals & SEALS_WANTED) != SEALS_WANTED || > + (seals & SEALS_DENIED) != 0) > + goto err_put_pages; All these conditions will return -EINVAL. I'm not familiar with the memfd API, should some error conditions return a different error code to make them distinguishable by userspace ? > + pgoff = list[i].offset >> PAGE_SHIFT; > + pgcnt = list[i].size >> PAGE_SHIFT; > + for (pgidx = 0; pgidx < pgcnt; pgidx++) { > + page = shmem_read_mapping_page( > + file_inode(memfd)->i_mapping, pgoff + pgidx); Can't pgoff + pgcnt overflow the total number of avialble pages ? > + if (IS_ERR(page)) { > + ret = PTR_ERR(page); > + goto err_put_pages; > + } > + ubuf->pages[pgbuf++] = page; > + } > + fput(memfd); > + } > + memfd = NULL; I'd move this line just after fput(memfd) inside the loop to avoid introduction bugs in the future if we add code that can break from the loop before the fget() call. > + exp_info.ops = &udmabuf_ops; > + exp_info.size = ubuf->pagecount << PAGE_SHIFT; > + exp_info.priv = ubuf; > + > + buf = dma_buf_export(&exp_info); > + if (IS_ERR(buf)) { > + ret = PTR_ERR(buf); > + goto err_put_pages; > + } > + > + flags = 0; > + if (head->flags & UDMABUF_FLAGS_CLOEXEC) > + flags |= O_CLOEXEC; > + return dma_buf_fd(buf, flags); > + > +err_put_pages: > + while (pgbuf > 0) > + put_page(ubuf->pages[--pgbuf]); If you initialize pgbuf to 0 you can merge the two error labels. > +err_free_ubuf: > + fput(memfd); > + kfree(ubuf->pages); > + kfree(ubuf); > + return ret; > +} > + > +static long udmabuf_ioctl_create(struct file *filp, unsigned long arg) > +{ > + struct udmabuf_create create; > + struct udmabuf_create_list head; > + struct udmabuf_create_item list; > + > + if (copy_from_user(&create, (void __user *)arg, > + sizeof(struct udmabuf_create))) sizeof(create) > + return -EFAULT; > + > + head.flags = create.flags; > + head.count = 1; > + list.memfd = create.memfd; > + list.offset = create.offset; > + list.size = create.size; > + > + return udmabuf_create(&head, &list); > +} > + > +static long udmabuf_ioctl_create_list(struct file *filp, unsigned long arg) > +{ > + struct udmabuf_create_list head; > + struct udmabuf_create_item *list; > + int ret = -EINVAL; > + u32 lsize; > + > + if (copy_from_user(&head, (void __user *)arg, sizeof(head))) > + return -EFAULT; > + if (head.count > 1024) > + return -EINVAL; > + lsize = sizeof(struct udmabuf_create_item) * head.count; > + list = memdup_user((void __user *)(arg + sizeof(head)), lsize); > + if (IS_ERR(list)) > + return PTR_ERR(list); > + > + ret = udmabuf_create(&head, list); > + kfree(list); > + return ret; > +} > + > +static long udmabuf_ioctl(struct file *filp, unsigned int ioctl, > + unsigned long arg) > +{ > + long ret; > + > + switch (ioctl) { > + case UDMABUF_CREATE: > + ret = udmabuf_ioctl_create(filp, arg); > + break; > + case UDMABUF_CREATE_LIST: > + ret = udmabuf_ioctl_create_list(filp, arg); > + break; > + default: > + ret = -EINVAL; The proper error code for invalid ioctls is -ENOTTY. > + break; > + } > + return ret; > +} > + > +static const struct file_operations udmabuf_fops = { > + .owner = THIS_MODULE, > + .unlocked_ioctl = udmabuf_ioctl, > +}; > + > +static struct miscdevice udmabuf_misc = { > + .minor = MISC_DYNAMIC_MINOR, > + .name = "udmabuf", > + .fops = &udmabuf_fops, > +}; > + > +static int __init udmabuf_dev_init(void) > +{ > + return misc_register(&udmabuf_misc); > +} > + > +static void __exit udmabuf_dev_exit(void) > +{ > + misc_deregister(&udmabuf_misc); > +} > + > +module_init(udmabuf_dev_init) > +module_exit(udmabuf_dev_exit) > + > +MODULE_AUTHOR("Gerd Hoffmann "); > +MODULE_LICENSE("GPL v2"); > diff --git a/tools/testing/selftests/drivers/dma-buf/udmabuf.c > b/tools/testing/selftests/drivers/dma-buf/udmabuf.c new file mode 100644 > index 0000000000..376b1d6730 > --- /dev/null > +++ b/tools/testing/selftests/drivers/dma-buf/udmabuf.c > @@ -0,0 +1,96 @@ > +// SPDX-License-Identifier: GPL-2.0 > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > +#include > +#include > +#include > + > +#define TEST_PREFIX "drivers/dma-buf/udmabuf" > +#define NUM_PAGES 4 > + > +static int memfd_create(const char *name, unsigned int flags) > +{ > + return syscall(__NR_memfd_create, name, flags); > +} > + > +int main(int argc, char *argv[]) > +{ > + struct udmabuf_create create; > + int devfd, memfd, buf, ret; > + off_t size; > + void *mem; > + > + devfd = open("/dev/udmabuf", O_RDWR); > + if (devfd < 0) { > + printf("%s: [skip,no-udmabuf]\n", TEST_PREFIX); > + exit(77); > + } > + > + memfd = memfd_create("udmabuf-test", MFD_CLOEXEC); > + if (memfd < 0) { > + printf("%s: [skip,no-memfd]\n", TEST_PREFIX); > + exit(77); > + } > + > + size = getpagesize() * NUM_PAGES; > + ret = ftruncate(memfd, size); > + if (ret == -1) { > + printf("%s: [FAIL,memfd-truncate]\n", TEST_PREFIX); > + exit(1); > + } > + > + memset(&create, 0, sizeof(create)); > + > + /* should fail (offset not page aligned) */ > + create.memfd = memfd; > + create.offset = getpagesize()/2; > + create.size = getpagesize(); > + buf = ioctl(devfd, UDMABUF_CREATE, &create); > + if (buf >= 0) { > + printf("%s: [FAIL,test-1]\n", TEST_PREFIX); > + exit(1); > + } > + > + /* should fail (size not multiple of page) */ > + create.memfd = memfd; > + create.offset = 0; > + create.size = getpagesize()/2; > + buf = ioctl(devfd, UDMABUF_CREATE, &create); > + if (buf >= 0) { > + printf("%s: [FAIL,test-2]\n", TEST_PREFIX); > + exit(1); > + } > + > + /* should fail (not memfd) */ > + create.memfd = 0; /* stdin */ > + create.offset = 0; > + create.size = size; > + buf = ioctl(devfd, UDMABUF_CREATE, &create); > + if (buf >= 0) { > + printf("%s: [FAIL,test-3]\n", TEST_PREFIX); > + exit(1); > + } > + > + /* should work */ > + create.memfd = memfd; > + create.offset = 0; > + create.size = size; > + buf = ioctl(devfd, UDMABUF_CREATE, &create); > + if (buf < 0) { > + printf("%s: [FAIL,test-4]\n", TEST_PREFIX); > + exit(1); > + } > + > + fprintf(stderr, "%s: ok\n", TEST_PREFIX); > + close(buf); > + close(memfd); > + close(devfd); > + return 0; > +} > diff --git a/MAINTAINERS b/MAINTAINERS > index a5b256b259..11a9b04277 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -14934,6 +14934,14 @@ S: Maintained > F: Documentation/filesystems/udf.txt > F: fs/udf/ > > +UDMABUF DRIVER > +M: Gerd Hoffmann > +L: dri-devel@lists.freedesktop.org > +S: Maintained > +F: drivers/dma-buf/udmabuf.c > +F: include/uapi/linux/udmabuf.h > +F: tools/testing/selftests/drivers/dma-buf/udmabuf.c > + > UDRAW TABLET > M: Bastien Nocera > L: linux-input@vger.kernel.org > @@ -15343,6 +15351,14 @@ F: arch/x86/um/ > F: fs/hostfs/ > F: fs/hppfs/ > > +USERSPACE DMA BUFFER DRIVER > +M: Gerd Hoffmann > +S: Maintained > +L: dri-devel@lists.freedesktop.org > +F: drivers/dma-buf/udmabuf.c > +F: include/uapi/linux/udmabuf.h > +T: git git://anongit.freedesktop.org/drm/drm-misc One entry should be enough. > USERSPACE I/O (UIO) > M: Greg Kroah-Hartman > S: Maintained [snip] -- Regards, Laurent Pinchart From mboxrd@z Thu Jan 1 00:00:00 1970 From: laurent.pinchart at ideasonboard.com (Laurent Pinchart) Date: Mon, 10 Sep 2018 15:12:59 +0300 Subject: [PATCH v7] Add udmabuf misc device In-Reply-To: <20180827093444.23623-1-kraxel@redhat.com> References: <20180827093444.23623-1-kraxel@redhat.com> Message-ID: <21053714.0Xa7F2u2PE@avalon> Hi Gerd, Thank you for the patch. CC'ing the linux-api mailing list as this creates a new userspace API. On Monday, 27 August 2018 12:34:44 EEST Gerd Hoffmann wrote: > A driver to let userspace turn memfd regions into dma-bufs. > > Use case: Allows qemu create dmabufs for the vga framebuffer or > virtio-gpu ressources. Then they can be passed around to display > those guest things on the host. To spice client for classic full > framebuffer display, and hopefully some day to wayland server for > seamless guest window display. > > qemu test branch: > https://git.kraxel.org/cgit/qemu/log/?h=sirius/udmabuf > > Cc: David Airlie > Cc: Tomeu Vizoso > Cc: Laurent Pinchart > Cc: Daniel Vetter > Signed-off-by: Gerd Hoffmann > --- > Documentation/ioctl/ioctl-number.txt | 1 + > include/uapi/linux/udmabuf.h | 33 +++ > drivers/dma-buf/udmabuf.c | 287 +++++++++++++++++++ > tools/testing/selftests/drivers/dma-buf/udmabuf.c | 96 ++++++++ > MAINTAINERS | 16 ++ > drivers/dma-buf/Kconfig | 8 + > drivers/dma-buf/Makefile | 1 + > tools/testing/selftests/drivers/dma-buf/Makefile | 5 + > 8 files changed, 447 insertions(+) > create mode 100644 include/uapi/linux/udmabuf.h > create mode 100644 drivers/dma-buf/udmabuf.c > create mode 100644 tools/testing/selftests/drivers/dma-buf/udmabuf.c > create mode 100644 tools/testing/selftests/drivers/dma-buf/Makefile [snip] > diff --git a/include/uapi/linux/udmabuf.h b/include/uapi/linux/udmabuf.h > new file mode 100644 > index 0000000000..46b6532ed8 > --- /dev/null > +++ b/include/uapi/linux/udmabuf.h > @@ -0,0 +1,33 @@ > +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ > +#ifndef _UAPI_LINUX_UDMABUF_H > +#define _UAPI_LINUX_UDMABUF_H > + > +#include > +#include > + > +#define UDMABUF_FLAGS_CLOEXEC 0x01 > + > +struct udmabuf_create { > + __u32 memfd; > + __u32 flags; > + __u64 offset; > + __u64 size; > +}; > + > +struct udmabuf_create_item { > + __u32 memfd; > + __u32 __pad; > + __u64 offset; > + __u64 size; > +}; > + > +struct udmabuf_create_list { > + __u32 flags; > + __u32 count; > + struct udmabuf_create_item list[]; > +}; > + > +#define UDMABUF_CREATE _IOW('u', 0x42, struct udmabuf_create) Why do you start at 0x42 if you reserve the 0x40-0x4f range ? > +#define UDMABUF_CREATE_LIST _IOW('u', 0x43, struct udmabuf_create_list) Where's the documentation ? :-) > +#endif /* _UAPI_LINUX_UDMABUF_H */ > diff --git a/drivers/dma-buf/udmabuf.c b/drivers/dma-buf/udmabuf.c > new file mode 100644 > index 0000000000..8e24204526 > --- /dev/null > +++ b/drivers/dma-buf/udmabuf.c > @@ -0,0 +1,287 @@ > +// SPDX-License-Identifier: GPL-2.0 > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include Could you please keep the #include alphabetically sorted ? It helps locating duplicates. > +#include I think you can just #include , no need to use the uapi/ prefix. > +struct udmabuf { > + u32 pagecount; > + struct page **pages; > +}; > + > +static int udmabuf_vm_fault(struct vm_fault *vmf) > +{ > + struct vm_area_struct *vma = vmf->vma; > + struct udmabuf *ubuf = vma->vm_private_data; > + > + if (WARN_ON(vmf->pgoff >= ubuf->pagecount)) > + return VM_FAULT_SIGBUS; Just curious, when do you expect this to happen ? > + vmf->page = ubuf->pages[vmf->pgoff]; > + get_page(vmf->page); > + return 0; > +} > + > +static const struct vm_operations_struct udmabuf_vm_ops = { > + .fault = udmabuf_vm_fault, > +}; > + > +static int mmap_udmabuf(struct dma_buf *buf, struct vm_area_struct *vma) > +{ > + struct udmabuf *ubuf = buf->priv; > + > + if ((vma->vm_flags & (VM_SHARED | VM_MAYSHARE)) == 0) > + return -EINVAL; > + > + vma->vm_ops = &udmabuf_vm_ops; > + vma->vm_private_data = ubuf; > + return 0; > +} > + > +static struct sg_table *map_udmabuf(struct dma_buf_attachment *at, > + enum dma_data_direction direction) > +{ > + struct udmabuf *ubuf = at->dmabuf->priv; > + struct sg_table *sg; > + > + sg = kzalloc(sizeof(*sg), GFP_KERNEL); > + if (!sg) > + goto err1; You can return ERR_PTR(-ENOMEM) directly. > + if (sg_alloc_table_from_pages(sg, ubuf->pages, ubuf->pagecount, > + 0, ubuf->pagecount << PAGE_SHIFT, > + GFP_KERNEL) < 0) Shouldn't you propagate the return value from sg_alloc_table_from_pages() ? > + goto err2; > + if (!dma_map_sg(at->dev, sg->sgl, sg->nents, direction)) > + goto err3; > + > + return sg; > + > +err3: > + sg_free_table(sg); > +err2: > + kfree(sg); > +err1: > + return ERR_PTR(-ENOMEM); You can merge all these labels with error: if (sg) { sg_free_table(sg); kfree(sg); } return ERR_PTR(-ENOMEM); > +} > + > +static void unmap_udmabuf(struct dma_buf_attachment *at, > + struct sg_table *sg, > + enum dma_data_direction direction) > +{ > + sg_free_table(sg); > + kfree(sg); > +} > + > +static void release_udmabuf(struct dma_buf *buf) > +{ > + struct udmabuf *ubuf = buf->priv; > + pgoff_t pg; > + > + for (pg = 0; pg < ubuf->pagecount; pg++) Shouldn't both pg and pagecount have the same type ? Why does the loop counter qualify for a pgoff_t and not the pagecount field ? Granted, the pgoff_t is documented as "The type of an index in the page cache", so pagecount doesn't really quality, but the fact that one is an unsigned long and the other a u32 makes me think that something is wrong. > + put_page(ubuf->pages[pg]); > + kfree(ubuf->pages); > + kfree(ubuf); > +} > + > +static void *kmap_udmabuf(struct dma_buf *buf, unsigned long page_num) > +{ > + struct udmabuf *ubuf = buf->priv; > + struct page *page = ubuf->pages[page_num]; > + > + return kmap(page); > +} > + > +static void kunmap_udmabuf(struct dma_buf *buf, unsigned long page_num, > + void *vaddr) > +{ > + kunmap(vaddr); > +} > + > +static struct dma_buf_ops udmabuf_ops = { static const struct > + .map_dma_buf = map_udmabuf, > + .unmap_dma_buf = unmap_udmabuf, > + .release = release_udmabuf, > + .map = kmap_udmabuf, > + .unmap = kunmap_udmabuf, > + .mmap = mmap_udmabuf, > +}; > + > +#define SEALS_WANTED (F_SEAL_SHRINK) > +#define SEALS_DENIED (F_SEAL_WRITE) > + > +static long udmabuf_create(struct udmabuf_create_list *head, > + struct udmabuf_create_item *list) Those two structures are not modified by the function, you can make them const. > +{ > + DEFINE_DMA_BUF_EXPORT_INFO(exp_info); > + struct file *memfd = NULL; > + struct udmabuf *ubuf; > + struct dma_buf *buf; > + pgoff_t pgoff, pgcnt, pgidx, pgbuf; > + struct page *page; > + int seals, ret = -EINVAL; > + u32 i, flags; > + > + ubuf = kzalloc(sizeof(struct udmabuf), GFP_KERNEL); sizeof(*ubuf) > + if (!ubuf) > + return -ENOMEM; > + > + for (i = 0; i < head->count; i++) { > + if (!IS_ALIGNED(list[i].offset, PAGE_SIZE)) > + goto err_free_ubuf; > + if (!IS_ALIGNED(list[i].size, PAGE_SIZE)) > + goto err_free_ubuf; > + ubuf->pagecount += list[i].size >> PAGE_SHIFT; Is there a risk of overflowing pagecount ? > + } > + ubuf->pages = kmalloc_array(ubuf->pagecount, sizeof(struct page *), > + GFP_KERNEL); sizeof(*ubuf->pages) > + if (!ubuf->pages) { > + ret = -ENOMEM; > + goto err_free_ubuf; > + } > + > + pgbuf = 0; > + for (i = 0; i < head->count; i++) { > + memfd = fget(list[i].memfd); > + if (!memfd) > + goto err_put_pages; > + if (!shmem_mapping(file_inode(memfd)->i_mapping)) > + goto err_put_pages; > + seals = memfd_fcntl(memfd, F_GET_SEALS, 0); > + if (seals == -EINVAL || > + (seals & SEALS_WANTED) != SEALS_WANTED || > + (seals & SEALS_DENIED) != 0) > + goto err_put_pages; All these conditions will return -EINVAL. I'm not familiar with the memfd API, should some error conditions return a different error code to make them distinguishable by userspace ? > + pgoff = list[i].offset >> PAGE_SHIFT; > + pgcnt = list[i].size >> PAGE_SHIFT; > + for (pgidx = 0; pgidx < pgcnt; pgidx++) { > + page = shmem_read_mapping_page( > + file_inode(memfd)->i_mapping, pgoff + pgidx); Can't pgoff + pgcnt overflow the total number of avialble pages ? > + if (IS_ERR(page)) { > + ret = PTR_ERR(page); > + goto err_put_pages; > + } > + ubuf->pages[pgbuf++] = page; > + } > + fput(memfd); > + } > + memfd = NULL; I'd move this line just after fput(memfd) inside the loop to avoid introduction bugs in the future if we add code that can break from the loop before the fget() call. > + exp_info.ops = &udmabuf_ops; > + exp_info.size = ubuf->pagecount << PAGE_SHIFT; > + exp_info.priv = ubuf; > + > + buf = dma_buf_export(&exp_info); > + if (IS_ERR(buf)) { > + ret = PTR_ERR(buf); > + goto err_put_pages; > + } > + > + flags = 0; > + if (head->flags & UDMABUF_FLAGS_CLOEXEC) > + flags |= O_CLOEXEC; > + return dma_buf_fd(buf, flags); > + > +err_put_pages: > + while (pgbuf > 0) > + put_page(ubuf->pages[--pgbuf]); If you initialize pgbuf to 0 you can merge the two error labels. > +err_free_ubuf: > + fput(memfd); > + kfree(ubuf->pages); > + kfree(ubuf); > + return ret; > +} > + > +static long udmabuf_ioctl_create(struct file *filp, unsigned long arg) > +{ > + struct udmabuf_create create; > + struct udmabuf_create_list head; > + struct udmabuf_create_item list; > + > + if (copy_from_user(&create, (void __user *)arg, > + sizeof(struct udmabuf_create))) sizeof(create) > + return -EFAULT; > + > + head.flags = create.flags; > + head.count = 1; > + list.memfd = create.memfd; > + list.offset = create.offset; > + list.size = create.size; > + > + return udmabuf_create(&head, &list); > +} > + > +static long udmabuf_ioctl_create_list(struct file *filp, unsigned long arg) > +{ > + struct udmabuf_create_list head; > + struct udmabuf_create_item *list; > + int ret = -EINVAL; > + u32 lsize; > + > + if (copy_from_user(&head, (void __user *)arg, sizeof(head))) > + return -EFAULT; > + if (head.count > 1024) > + return -EINVAL; > + lsize = sizeof(struct udmabuf_create_item) * head.count; > + list = memdup_user((void __user *)(arg + sizeof(head)), lsize); > + if (IS_ERR(list)) > + return PTR_ERR(list); > + > + ret = udmabuf_create(&head, list); > + kfree(list); > + return ret; > +} > + > +static long udmabuf_ioctl(struct file *filp, unsigned int ioctl, > + unsigned long arg) > +{ > + long ret; > + > + switch (ioctl) { > + case UDMABUF_CREATE: > + ret = udmabuf_ioctl_create(filp, arg); > + break; > + case UDMABUF_CREATE_LIST: > + ret = udmabuf_ioctl_create_list(filp, arg); > + break; > + default: > + ret = -EINVAL; The proper error code for invalid ioctls is -ENOTTY. > + break; > + } > + return ret; > +} > + > +static const struct file_operations udmabuf_fops = { > + .owner = THIS_MODULE, > + .unlocked_ioctl = udmabuf_ioctl, > +}; > + > +static struct miscdevice udmabuf_misc = { > + .minor = MISC_DYNAMIC_MINOR, > + .name = "udmabuf", > + .fops = &udmabuf_fops, > +}; > + > +static int __init udmabuf_dev_init(void) > +{ > + return misc_register(&udmabuf_misc); > +} > + > +static void __exit udmabuf_dev_exit(void) > +{ > + misc_deregister(&udmabuf_misc); > +} > + > +module_init(udmabuf_dev_init) > +module_exit(udmabuf_dev_exit) > + > +MODULE_AUTHOR("Gerd Hoffmann "); > +MODULE_LICENSE("GPL v2"); > diff --git a/tools/testing/selftests/drivers/dma-buf/udmabuf.c > b/tools/testing/selftests/drivers/dma-buf/udmabuf.c new file mode 100644 > index 0000000000..376b1d6730 > --- /dev/null > +++ b/tools/testing/selftests/drivers/dma-buf/udmabuf.c > @@ -0,0 +1,96 @@ > +// SPDX-License-Identifier: GPL-2.0 > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > +#include > +#include > +#include > + > +#define TEST_PREFIX "drivers/dma-buf/udmabuf" > +#define NUM_PAGES 4 > + > +static int memfd_create(const char *name, unsigned int flags) > +{ > + return syscall(__NR_memfd_create, name, flags); > +} > + > +int main(int argc, char *argv[]) > +{ > + struct udmabuf_create create; > + int devfd, memfd, buf, ret; > + off_t size; > + void *mem; > + > + devfd = open("/dev/udmabuf", O_RDWR); > + if (devfd < 0) { > + printf("%s: [skip,no-udmabuf]\n", TEST_PREFIX); > + exit(77); > + } > + > + memfd = memfd_create("udmabuf-test", MFD_CLOEXEC); > + if (memfd < 0) { > + printf("%s: [skip,no-memfd]\n", TEST_PREFIX); > + exit(77); > + } > + > + size = getpagesize() * NUM_PAGES; > + ret = ftruncate(memfd, size); > + if (ret == -1) { > + printf("%s: [FAIL,memfd-truncate]\n", TEST_PREFIX); > + exit(1); > + } > + > + memset(&create, 0, sizeof(create)); > + > + /* should fail (offset not page aligned) */ > + create.memfd = memfd; > + create.offset = getpagesize()/2; > + create.size = getpagesize(); > + buf = ioctl(devfd, UDMABUF_CREATE, &create); > + if (buf >= 0) { > + printf("%s: [FAIL,test-1]\n", TEST_PREFIX); > + exit(1); > + } > + > + /* should fail (size not multiple of page) */ > + create.memfd = memfd; > + create.offset = 0; > + create.size = getpagesize()/2; > + buf = ioctl(devfd, UDMABUF_CREATE, &create); > + if (buf >= 0) { > + printf("%s: [FAIL,test-2]\n", TEST_PREFIX); > + exit(1); > + } > + > + /* should fail (not memfd) */ > + create.memfd = 0; /* stdin */ > + create.offset = 0; > + create.size = size; > + buf = ioctl(devfd, UDMABUF_CREATE, &create); > + if (buf >= 0) { > + printf("%s: [FAIL,test-3]\n", TEST_PREFIX); > + exit(1); > + } > + > + /* should work */ > + create.memfd = memfd; > + create.offset = 0; > + create.size = size; > + buf = ioctl(devfd, UDMABUF_CREATE, &create); > + if (buf < 0) { > + printf("%s: [FAIL,test-4]\n", TEST_PREFIX); > + exit(1); > + } > + > + fprintf(stderr, "%s: ok\n", TEST_PREFIX); > + close(buf); > + close(memfd); > + close(devfd); > + return 0; > +} > diff --git a/MAINTAINERS b/MAINTAINERS > index a5b256b259..11a9b04277 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -14934,6 +14934,14 @@ S: Maintained > F: Documentation/filesystems/udf.txt > F: fs/udf/ > > +UDMABUF DRIVER > +M: Gerd Hoffmann > +L: dri-devel at lists.freedesktop.org > +S: Maintained > +F: drivers/dma-buf/udmabuf.c > +F: include/uapi/linux/udmabuf.h > +F: tools/testing/selftests/drivers/dma-buf/udmabuf.c > + > UDRAW TABLET > M: Bastien Nocera > L: linux-input at vger.kernel.org > @@ -15343,6 +15351,14 @@ F: arch/x86/um/ > F: fs/hostfs/ > F: fs/hppfs/ > > +USERSPACE DMA BUFFER DRIVER > +M: Gerd Hoffmann > +S: Maintained > +L: dri-devel at lists.freedesktop.org > +F: drivers/dma-buf/udmabuf.c > +F: include/uapi/linux/udmabuf.h > +T: git git://anongit.freedesktop.org/drm/drm-misc One entry should be enough. > USERSPACE I/O (UIO) > M: Greg Kroah-Hartman > S: Maintained [snip] -- Regards, Laurent Pinchart From mboxrd@z Thu Jan 1 00:00:00 1970 From: laurent.pinchart@ideasonboard.com (Laurent Pinchart) Date: Mon, 10 Sep 2018 15:12:59 +0300 Subject: [PATCH v7] Add udmabuf misc device In-Reply-To: <20180827093444.23623-1-kraxel@redhat.com> References: <20180827093444.23623-1-kraxel@redhat.com> Message-ID: <21053714.0Xa7F2u2PE@avalon> Content-Type: text/plain; charset="UTF-8" Message-ID: <20180910121259.ShBBt0v-n_17JMrqONksXHhxbYpDBUet6m03WHM8Gbg@z> Hi Gerd, Thank you for the patch. CC'ing the linux-api mailing list as this creates a new userspace API. On Monday, 27 August 2018 12:34:44 EEST Gerd Hoffmann wrote: > A driver to let userspace turn memfd regions into dma-bufs. > > Use case: Allows qemu create dmabufs for the vga framebuffer or > virtio-gpu ressources. Then they can be passed around to display > those guest things on the host. To spice client for classic full > framebuffer display, and hopefully some day to wayland server for > seamless guest window display. > > qemu test branch: > https://git.kraxel.org/cgit/qemu/log/?h=sirius/udmabuf > > Cc: David Airlie > Cc: Tomeu Vizoso > Cc: Laurent Pinchart > Cc: Daniel Vetter > Signed-off-by: Gerd Hoffmann > --- > Documentation/ioctl/ioctl-number.txt | 1 + > include/uapi/linux/udmabuf.h | 33 +++ > drivers/dma-buf/udmabuf.c | 287 +++++++++++++++++++ > tools/testing/selftests/drivers/dma-buf/udmabuf.c | 96 ++++++++ > MAINTAINERS | 16 ++ > drivers/dma-buf/Kconfig | 8 + > drivers/dma-buf/Makefile | 1 + > tools/testing/selftests/drivers/dma-buf/Makefile | 5 + > 8 files changed, 447 insertions(+) > create mode 100644 include/uapi/linux/udmabuf.h > create mode 100644 drivers/dma-buf/udmabuf.c > create mode 100644 tools/testing/selftests/drivers/dma-buf/udmabuf.c > create mode 100644 tools/testing/selftests/drivers/dma-buf/Makefile [snip] > diff --git a/include/uapi/linux/udmabuf.h b/include/uapi/linux/udmabuf.h > new file mode 100644 > index 0000000000..46b6532ed8 > --- /dev/null > +++ b/include/uapi/linux/udmabuf.h > @@ -0,0 +1,33 @@ > +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ > +#ifndef _UAPI_LINUX_UDMABUF_H > +#define _UAPI_LINUX_UDMABUF_H > + > +#include > +#include > + > +#define UDMABUF_FLAGS_CLOEXEC 0x01 > + > +struct udmabuf_create { > + __u32 memfd; > + __u32 flags; > + __u64 offset; > + __u64 size; > +}; > + > +struct udmabuf_create_item { > + __u32 memfd; > + __u32 __pad; > + __u64 offset; > + __u64 size; > +}; > + > +struct udmabuf_create_list { > + __u32 flags; > + __u32 count; > + struct udmabuf_create_item list[]; > +}; > + > +#define UDMABUF_CREATE _IOW('u', 0x42, struct udmabuf_create) Why do you start at 0x42 if you reserve the 0x40-0x4f range ? > +#define UDMABUF_CREATE_LIST _IOW('u', 0x43, struct udmabuf_create_list) Where's the documentation ? :-) > +#endif /* _UAPI_LINUX_UDMABUF_H */ > diff --git a/drivers/dma-buf/udmabuf.c b/drivers/dma-buf/udmabuf.c > new file mode 100644 > index 0000000000..8e24204526 > --- /dev/null > +++ b/drivers/dma-buf/udmabuf.c > @@ -0,0 +1,287 @@ > +// SPDX-License-Identifier: GPL-2.0 > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include Could you please keep the #include alphabetically sorted ? It helps locating duplicates. > +#include I think you can just #include , no need to use the uapi/ prefix. > +struct udmabuf { > + u32 pagecount; > + struct page **pages; > +}; > + > +static int udmabuf_vm_fault(struct vm_fault *vmf) > +{ > + struct vm_area_struct *vma = vmf->vma; > + struct udmabuf *ubuf = vma->vm_private_data; > + > + if (WARN_ON(vmf->pgoff >= ubuf->pagecount)) > + return VM_FAULT_SIGBUS; Just curious, when do you expect this to happen ? > + vmf->page = ubuf->pages[vmf->pgoff]; > + get_page(vmf->page); > + return 0; > +} > + > +static const struct vm_operations_struct udmabuf_vm_ops = { > + .fault = udmabuf_vm_fault, > +}; > + > +static int mmap_udmabuf(struct dma_buf *buf, struct vm_area_struct *vma) > +{ > + struct udmabuf *ubuf = buf->priv; > + > + if ((vma->vm_flags & (VM_SHARED | VM_MAYSHARE)) == 0) > + return -EINVAL; > + > + vma->vm_ops = &udmabuf_vm_ops; > + vma->vm_private_data = ubuf; > + return 0; > +} > + > +static struct sg_table *map_udmabuf(struct dma_buf_attachment *at, > + enum dma_data_direction direction) > +{ > + struct udmabuf *ubuf = at->dmabuf->priv; > + struct sg_table *sg; > + > + sg = kzalloc(sizeof(*sg), GFP_KERNEL); > + if (!sg) > + goto err1; You can return ERR_PTR(-ENOMEM) directly. > + if (sg_alloc_table_from_pages(sg, ubuf->pages, ubuf->pagecount, > + 0, ubuf->pagecount << PAGE_SHIFT, > + GFP_KERNEL) < 0) Shouldn't you propagate the return value from sg_alloc_table_from_pages() ? > + goto err2; > + if (!dma_map_sg(at->dev, sg->sgl, sg->nents, direction)) > + goto err3; > + > + return sg; > + > +err3: > + sg_free_table(sg); > +err2: > + kfree(sg); > +err1: > + return ERR_PTR(-ENOMEM); You can merge all these labels with error: if (sg) { sg_free_table(sg); kfree(sg); } return ERR_PTR(-ENOMEM); > +} > + > +static void unmap_udmabuf(struct dma_buf_attachment *at, > + struct sg_table *sg, > + enum dma_data_direction direction) > +{ > + sg_free_table(sg); > + kfree(sg); > +} > + > +static void release_udmabuf(struct dma_buf *buf) > +{ > + struct udmabuf *ubuf = buf->priv; > + pgoff_t pg; > + > + for (pg = 0; pg < ubuf->pagecount; pg++) Shouldn't both pg and pagecount have the same type ? Why does the loop counter qualify for a pgoff_t and not the pagecount field ? Granted, the pgoff_t is documented as "The type of an index in the page cache", so pagecount doesn't really quality, but the fact that one is an unsigned long and the other a u32 makes me think that something is wrong. > + put_page(ubuf->pages[pg]); > + kfree(ubuf->pages); > + kfree(ubuf); > +} > + > +static void *kmap_udmabuf(struct dma_buf *buf, unsigned long page_num) > +{ > + struct udmabuf *ubuf = buf->priv; > + struct page *page = ubuf->pages[page_num]; > + > + return kmap(page); > +} > + > +static void kunmap_udmabuf(struct dma_buf *buf, unsigned long page_num, > + void *vaddr) > +{ > + kunmap(vaddr); > +} > + > +static struct dma_buf_ops udmabuf_ops = { static const struct > + .map_dma_buf = map_udmabuf, > + .unmap_dma_buf = unmap_udmabuf, > + .release = release_udmabuf, > + .map = kmap_udmabuf, > + .unmap = kunmap_udmabuf, > + .mmap = mmap_udmabuf, > +}; > + > +#define SEALS_WANTED (F_SEAL_SHRINK) > +#define SEALS_DENIED (F_SEAL_WRITE) > + > +static long udmabuf_create(struct udmabuf_create_list *head, > + struct udmabuf_create_item *list) Those two structures are not modified by the function, you can make them const. > +{ > + DEFINE_DMA_BUF_EXPORT_INFO(exp_info); > + struct file *memfd = NULL; > + struct udmabuf *ubuf; > + struct dma_buf *buf; > + pgoff_t pgoff, pgcnt, pgidx, pgbuf; > + struct page *page; > + int seals, ret = -EINVAL; > + u32 i, flags; > + > + ubuf = kzalloc(sizeof(struct udmabuf), GFP_KERNEL); sizeof(*ubuf) > + if (!ubuf) > + return -ENOMEM; > + > + for (i = 0; i < head->count; i++) { > + if (!IS_ALIGNED(list[i].offset, PAGE_SIZE)) > + goto err_free_ubuf; > + if (!IS_ALIGNED(list[i].size, PAGE_SIZE)) > + goto err_free_ubuf; > + ubuf->pagecount += list[i].size >> PAGE_SHIFT; Is there a risk of overflowing pagecount ? > + } > + ubuf->pages = kmalloc_array(ubuf->pagecount, sizeof(struct page *), > + GFP_KERNEL); sizeof(*ubuf->pages) > + if (!ubuf->pages) { > + ret = -ENOMEM; > + goto err_free_ubuf; > + } > + > + pgbuf = 0; > + for (i = 0; i < head->count; i++) { > + memfd = fget(list[i].memfd); > + if (!memfd) > + goto err_put_pages; > + if (!shmem_mapping(file_inode(memfd)->i_mapping)) > + goto err_put_pages; > + seals = memfd_fcntl(memfd, F_GET_SEALS, 0); > + if (seals == -EINVAL || > + (seals & SEALS_WANTED) != SEALS_WANTED || > + (seals & SEALS_DENIED) != 0) > + goto err_put_pages; All these conditions will return -EINVAL. I'm not familiar with the memfd API, should some error conditions return a different error code to make them distinguishable by userspace ? > + pgoff = list[i].offset >> PAGE_SHIFT; > + pgcnt = list[i].size >> PAGE_SHIFT; > + for (pgidx = 0; pgidx < pgcnt; pgidx++) { > + page = shmem_read_mapping_page( > + file_inode(memfd)->i_mapping, pgoff + pgidx); Can't pgoff + pgcnt overflow the total number of avialble pages ? > + if (IS_ERR(page)) { > + ret = PTR_ERR(page); > + goto err_put_pages; > + } > + ubuf->pages[pgbuf++] = page; > + } > + fput(memfd); > + } > + memfd = NULL; I'd move this line just after fput(memfd) inside the loop to avoid introduction bugs in the future if we add code that can break from the loop before the fget() call. > + exp_info.ops = &udmabuf_ops; > + exp_info.size = ubuf->pagecount << PAGE_SHIFT; > + exp_info.priv = ubuf; > + > + buf = dma_buf_export(&exp_info); > + if (IS_ERR(buf)) { > + ret = PTR_ERR(buf); > + goto err_put_pages; > + } > + > + flags = 0; > + if (head->flags & UDMABUF_FLAGS_CLOEXEC) > + flags |= O_CLOEXEC; > + return dma_buf_fd(buf, flags); > + > +err_put_pages: > + while (pgbuf > 0) > + put_page(ubuf->pages[--pgbuf]); If you initialize pgbuf to 0 you can merge the two error labels. > +err_free_ubuf: > + fput(memfd); > + kfree(ubuf->pages); > + kfree(ubuf); > + return ret; > +} > + > +static long udmabuf_ioctl_create(struct file *filp, unsigned long arg) > +{ > + struct udmabuf_create create; > + struct udmabuf_create_list head; > + struct udmabuf_create_item list; > + > + if (copy_from_user(&create, (void __user *)arg, > + sizeof(struct udmabuf_create))) sizeof(create) > + return -EFAULT; > + > + head.flags = create.flags; > + head.count = 1; > + list.memfd = create.memfd; > + list.offset = create.offset; > + list.size = create.size; > + > + return udmabuf_create(&head, &list); > +} > + > +static long udmabuf_ioctl_create_list(struct file *filp, unsigned long arg) > +{ > + struct udmabuf_create_list head; > + struct udmabuf_create_item *list; > + int ret = -EINVAL; > + u32 lsize; > + > + if (copy_from_user(&head, (void __user *)arg, sizeof(head))) > + return -EFAULT; > + if (head.count > 1024) > + return -EINVAL; > + lsize = sizeof(struct udmabuf_create_item) * head.count; > + list = memdup_user((void __user *)(arg + sizeof(head)), lsize); > + if (IS_ERR(list)) > + return PTR_ERR(list); > + > + ret = udmabuf_create(&head, list); > + kfree(list); > + return ret; > +} > + > +static long udmabuf_ioctl(struct file *filp, unsigned int ioctl, > + unsigned long arg) > +{ > + long ret; > + > + switch (ioctl) { > + case UDMABUF_CREATE: > + ret = udmabuf_ioctl_create(filp, arg); > + break; > + case UDMABUF_CREATE_LIST: > + ret = udmabuf_ioctl_create_list(filp, arg); > + break; > + default: > + ret = -EINVAL; The proper error code for invalid ioctls is -ENOTTY. > + break; > + } > + return ret; > +} > + > +static const struct file_operations udmabuf_fops = { > + .owner = THIS_MODULE, > + .unlocked_ioctl = udmabuf_ioctl, > +}; > + > +static struct miscdevice udmabuf_misc = { > + .minor = MISC_DYNAMIC_MINOR, > + .name = "udmabuf", > + .fops = &udmabuf_fops, > +}; > + > +static int __init udmabuf_dev_init(void) > +{ > + return misc_register(&udmabuf_misc); > +} > + > +static void __exit udmabuf_dev_exit(void) > +{ > + misc_deregister(&udmabuf_misc); > +} > + > +module_init(udmabuf_dev_init) > +module_exit(udmabuf_dev_exit) > + > +MODULE_AUTHOR("Gerd Hoffmann "); > +MODULE_LICENSE("GPL v2"); > diff --git a/tools/testing/selftests/drivers/dma-buf/udmabuf.c > b/tools/testing/selftests/drivers/dma-buf/udmabuf.c new file mode 100644 > index 0000000000..376b1d6730 > --- /dev/null > +++ b/tools/testing/selftests/drivers/dma-buf/udmabuf.c > @@ -0,0 +1,96 @@ > +// SPDX-License-Identifier: GPL-2.0 > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > +#include > +#include > +#include > + > +#define TEST_PREFIX "drivers/dma-buf/udmabuf" > +#define NUM_PAGES 4 > + > +static int memfd_create(const char *name, unsigned int flags) > +{ > + return syscall(__NR_memfd_create, name, flags); > +} > + > +int main(int argc, char *argv[]) > +{ > + struct udmabuf_create create; > + int devfd, memfd, buf, ret; > + off_t size; > + void *mem; > + > + devfd = open("/dev/udmabuf", O_RDWR); > + if (devfd < 0) { > + printf("%s: [skip,no-udmabuf]\n", TEST_PREFIX); > + exit(77); > + } > + > + memfd = memfd_create("udmabuf-test", MFD_CLOEXEC); > + if (memfd < 0) { > + printf("%s: [skip,no-memfd]\n", TEST_PREFIX); > + exit(77); > + } > + > + size = getpagesize() * NUM_PAGES; > + ret = ftruncate(memfd, size); > + if (ret == -1) { > + printf("%s: [FAIL,memfd-truncate]\n", TEST_PREFIX); > + exit(1); > + } > + > + memset(&create, 0, sizeof(create)); > + > + /* should fail (offset not page aligned) */ > + create.memfd = memfd; > + create.offset = getpagesize()/2; > + create.size = getpagesize(); > + buf = ioctl(devfd, UDMABUF_CREATE, &create); > + if (buf >= 0) { > + printf("%s: [FAIL,test-1]\n", TEST_PREFIX); > + exit(1); > + } > + > + /* should fail (size not multiple of page) */ > + create.memfd = memfd; > + create.offset = 0; > + create.size = getpagesize()/2; > + buf = ioctl(devfd, UDMABUF_CREATE, &create); > + if (buf >= 0) { > + printf("%s: [FAIL,test-2]\n", TEST_PREFIX); > + exit(1); > + } > + > + /* should fail (not memfd) */ > + create.memfd = 0; /* stdin */ > + create.offset = 0; > + create.size = size; > + buf = ioctl(devfd, UDMABUF_CREATE, &create); > + if (buf >= 0) { > + printf("%s: [FAIL,test-3]\n", TEST_PREFIX); > + exit(1); > + } > + > + /* should work */ > + create.memfd = memfd; > + create.offset = 0; > + create.size = size; > + buf = ioctl(devfd, UDMABUF_CREATE, &create); > + if (buf < 0) { > + printf("%s: [FAIL,test-4]\n", TEST_PREFIX); > + exit(1); > + } > + > + fprintf(stderr, "%s: ok\n", TEST_PREFIX); > + close(buf); > + close(memfd); > + close(devfd); > + return 0; > +} > diff --git a/MAINTAINERS b/MAINTAINERS > index a5b256b259..11a9b04277 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -14934,6 +14934,14 @@ S: Maintained > F: Documentation/filesystems/udf.txt > F: fs/udf/ > > +UDMABUF DRIVER > +M: Gerd Hoffmann > +L: dri-devel at lists.freedesktop.org > +S: Maintained > +F: drivers/dma-buf/udmabuf.c > +F: include/uapi/linux/udmabuf.h > +F: tools/testing/selftests/drivers/dma-buf/udmabuf.c > + > UDRAW TABLET > M: Bastien Nocera > L: linux-input at vger.kernel.org > @@ -15343,6 +15351,14 @@ F: arch/x86/um/ > F: fs/hostfs/ > F: fs/hppfs/ > > +USERSPACE DMA BUFFER DRIVER > +M: Gerd Hoffmann > +S: Maintained > +L: dri-devel at lists.freedesktop.org > +F: drivers/dma-buf/udmabuf.c > +F: include/uapi/linux/udmabuf.h > +T: git git://anongit.freedesktop.org/drm/drm-misc One entry should be enough. > USERSPACE I/O (UIO) > M: Greg Kroah-Hartman > S: Maintained [snip] -- Regards, Laurent Pinchart