From patchwork Mon Sep 29 14:43:32 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Olivier Blin X-Patchwork-Id: 394483 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from whitealder.osuosl.org (whitealder.osuosl.org [140.211.166.138]) by ozlabs.org (Postfix) with ESMTP id 855ED140097 for ; Tue, 30 Sep 2014 00:50:59 +1000 (EST) Received: from localhost (localhost [127.0.0.1]) by whitealder.osuosl.org (Postfix) with ESMTP id 6186291D75; Mon, 29 Sep 2014 14:50:57 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from whitealder.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id zWdANm9V05lw; Mon, 29 Sep 2014 14:50:54 +0000 (UTC) Received: from ash.osuosl.org (ash.osuosl.org [140.211.166.34]) by whitealder.osuosl.org (Postfix) with ESMTP id 2799D91D4F; Mon, 29 Sep 2014 14:50:54 +0000 (UTC) X-Original-To: uclibc@lists.busybox.net Delivered-To: uclibc@osuosl.org Received: from silver.osuosl.org (silver.osuosl.org [140.211.166.136]) by ash.osuosl.org (Postfix) with ESMTP id 2430E1D0A04 for ; Mon, 29 Sep 2014 14:50:51 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by silver.osuosl.org (Postfix) with ESMTP id 6E52D335ED for ; Mon, 29 Sep 2014 14:50:50 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from silver.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id Yq2HYEbMo6lU for ; Mon, 29 Sep 2014 14:50:48 +0000 (UTC) X-Greylist: delayed 00:06:26 by SQLgrey-1.7.6 Received: from mtantr1.softathome.com (92-137-167-83.reverse.alphalink.fr [83.167.137.92]) by silver.osuosl.org (Postfix) with ESMTP id 235642F959 for ; Mon, 29 Sep 2014 14:50:47 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by mtantr1.softathome.com (Postfix) with ESMTP id EA80688698 for ; Mon, 29 Sep 2014 16:44:20 +0200 (CEST) X-Amavis-Modified: Mail body modified (using disclaimer) - mtantr1.softathome.com X-Virus-Scanned: amavisd-new at mtantr1.softathome.com Received: from mtantr1.softathome.com ([127.0.0.1]) by localhost (mtantr1.softathome.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id cH2QL8+XiGk7 for ; Mon, 29 Sep 2014 16:44:12 +0200 (CEST) Received: from storentr2.softathome.com (storentr2.softathome.com [192.168.64.167]) by mtantr1.softathome.com (Postfix) with ESMTP id E5F5788697 for ; Mon, 29 Sep 2014 16:44:11 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by storentr2.softathome.com (Postfix) with ESMTP id C9D0D1CA4AD3 for ; Mon, 29 Sep 2014 16:44:13 +0200 (CEST) X-Amavis-Modified: Mail body modified (using disclaimer) - storentr2.softathome.com X-Virus-Scanned: amavisd-new at softathome.com Received: from storentr2.softathome.com ([127.0.0.1]) by localhost (storentr2.softathome.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id TNtN7c2CEh8B; Mon, 29 Sep 2014 16:43:53 +0200 (CEST) Received: from localhost.localdomain.com (unknown [192.168.75.213]) by storentr2.softathome.com (Postfix) with ESMTPSA id 8AA5F1CA4A82; Mon, 29 Sep 2014 16:43:53 +0200 (CEST) From: Olivier Blin To: uclibc@uclibc.org Subject: [PATCH] libc: add fallback for posix_fallocate() when not supported by underlying FS Date: Mon, 29 Sep 2014 16:43:32 +0200 Message-Id: <1412001812-9943-1-git-send-email-olivier.blin@softathome.com> X-Mailer: git-send-email 2.1.0 X-BeenThere: uclibc@uclibc.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: "Discussion and development of uClibc \(the embedded C library\)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: uclibc-bounces@uclibc.org Sender: "uClibc" EOPNOTSUPP is not a valid error code for posix_fallocate(), the implementation should have a fallback when the underlying filesystem does not support fallocate(). This is especially useful when using posix_fallocate() on tmpfs with kernels older than 3.5, for which there was no fallocate support. This copies the implementation of the internal fallback from glibc, with a few adaptations for internals symbols. Though, there are no internal symbols for the following functions in uClibc: - fstat64 - fstatfs64 (not important, since it is not weak) - ftruncate/ftruncate64 --- libc/sysdeps/linux/common/posix_fallocate.c | 78 ++++++++++++++++++++++++++- libc/sysdeps/linux/common/posix_fallocate64.c | 78 ++++++++++++++++++++++++++- 2 files changed, 154 insertions(+), 2 deletions(-) diff --git a/libc/sysdeps/linux/common/posix_fallocate.c b/libc/sysdeps/linux/common/posix_fallocate.c index 76771e3..cc4553c 100644 --- a/libc/sysdeps/linux/common/posix_fallocate.c +++ b/libc/sysdeps/linux/common/posix_fallocate.c @@ -12,12 +12,88 @@ #include #include #include +#include #if defined __NR_fallocate +/* Reserve storage for the data of the file associated with FD. */ +/* Adapted from glibc */ +int +internal_fallocate (int fd, __off_t offset, __off_t len) +{ + struct stat64 st; + struct statfs f; + + /* `off_t' is a signed type. Therefore we can determine whether + OFFSET + LEN is too large if it is a negative value. */ + if (offset < 0 || len < 0) + return EINVAL; + if (offset + len < 0) + return EFBIG; + + /* First thing we have to make sure is that this is really a regular + file. */ + if (fstat64 (fd, &st) != 0) + return EBADF; + if (S_ISFIFO (st.st_mode)) + return ESPIPE; + if (! S_ISREG (st.st_mode)) + return ENODEV; + + if (len == 0) + { + if (st.st_size < offset) + { + int ret = ftruncate (fd, offset); + + if (ret != 0) + ret = errno; + return ret; + } + return 0; + } + + /* We have to know the block size of the filesystem to get at least some + sort of performance. */ + if (__libc_fstatfs (fd, &f) != 0) + return errno; + + /* Try to play safe. */ + if (f.f_bsize == 0) + f.f_bsize = 512; + + /* Write something to every block. */ + for (offset += (len - 1) % f.f_bsize; len > 0; offset += f.f_bsize) + { + len -= f.f_bsize; + + if (offset < st.st_size) + { + unsigned char c; + ssize_t rsize = __libc_pread (fd, &c, 1, offset); + + if (rsize < 0) + return errno; + /* If there is a non-zero byte, the block must have been + allocated already. */ + else if (rsize == 1 && c != 0) + continue; + } + + if (__libc_pwrite (fd, "", 1, offset) != 1) + return errno; + } + + return 0; +} + extern __typeof(fallocate) __libc_fallocate attribute_hidden; int posix_fallocate(int fd, __off_t offset, __off_t len) { - return __libc_fallocate(fd, 0, offset, len); + int result = __libc_fallocate(fd, 0, offset, len); + if (result != EOPNOTSUPP) + return result; + + return internal_fallocate(fd, offset, len); } # if defined __UCLIBC_HAS_LFS__ && __WORDSIZE == 64 strong_alias(posix_fallocate,posix_fallocate64) diff --git a/libc/sysdeps/linux/common/posix_fallocate64.c b/libc/sysdeps/linux/common/posix_fallocate64.c index 12ddbc2..2f02626 100644 --- a/libc/sysdeps/linux/common/posix_fallocate64.c +++ b/libc/sysdeps/linux/common/posix_fallocate64.c @@ -12,15 +12,91 @@ #include #include #include +#include #if defined __NR_fallocate # if __WORDSIZE == 64 /* Can use normal posix_fallocate() */ # elif __WORDSIZE == 32 +/* Reserve storage for the data of the file associated with FD. */ +/* Adapted from glibc */ +static int +internal_fallocate64 (int fd, __off64_t offset, __off64_t len) +{ + struct stat64 st; + struct statfs64 f; + + /* `off64_t' is a signed type. Therefore we can determine whether + OFFSET + LEN is too large if it is a negative value. */ + if (offset < 0 || len < 0) + return EINVAL; + if (offset + len < 0) + return EFBIG; + + /* First thing we have to make sure is that this is really a regular + file. */ + if (fstat64 (fd, &st) != 0) + return EBADF; + if (S_ISFIFO (st.st_mode)) + return ESPIPE; + if (! S_ISREG (st.st_mode)) + return ENODEV; + + if (len == 0) + { + if (st.st_size < offset) + { + int ret = ftruncate64 (fd, offset); + + if (ret != 0) + ret = errno; + return ret; + } + return 0; + } + + /* We have to know the block size of the filesystem to get at least some + sort of performance. */ + if (fstatfs64 (fd, &f) != 0) + return errno; + + /* Try to play safe. */ + if (f.f_bsize == 0) + f.f_bsize = 512; + + /* Write something to every block. */ + for (offset += (len - 1) % f.f_bsize; len > 0; offset += f.f_bsize) + { + len -= f.f_bsize; + + if (offset < st.st_size) + { + unsigned char c; + ssize_t rsize = __libc_pread64 (fd, &c, 1, offset); + + if (rsize < 0) + return errno; + /* If there is a non-zero byte, the block must have been + allocated already. */ + else if (rsize == 1 && c != 0) + continue; + } + + if (__libc_pwrite64 (fd, "", 1, offset) != 1) + return errno; + } + + return 0; +} + extern __typeof(fallocate64) __libc_fallocate64 attribute_hidden; int posix_fallocate64(int fd, __off64_t offset, __off64_t len) { - return __libc_fallocate64(fd, 0, offset, len); + int result = __libc_fallocate64(fd, 0, offset, len); + if (result != EOPNOTSUPP) + return result; + + return internal_fallocate64(fd, offset, len); } # else # error your machine is neither 32 bit or 64 bit ... it must be magical