From patchwork Sun Mar 30 14:58:34 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Conrad Meyer X-Patchwork-Id: 335120 Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 11BDB1400C2 for ; Mon, 31 Mar 2014 01:59:17 +1100 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751560AbaC3O6s (ORCPT ); Sun, 30 Mar 2014 10:58:48 -0400 Received: from mail-pd0-f179.google.com ([209.85.192.179]:62862 "EHLO mail-pd0-f179.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751025AbaC3O6p (ORCPT ); Sun, 30 Mar 2014 10:58:45 -0400 Received: by mail-pd0-f179.google.com with SMTP id w10so6902862pde.10 for ; Sun, 30 Mar 2014 07:58:44 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=MkX2FIFyYrNarEsy5NOp6QWKSvqdDursZkq3JURM87U=; b=DwFSEE8G0XQd3K8zeECl+cZqZNvXsczrbnXaRaGuwc5lBspXyA2AldUapsH11kXKtg A7Xi1TwnScrPweRG8B9+4r+gGFRWNQboC0ktG93lHSDqGNk0cogGnjSxgoS4xDBYSB6N TKJqmuhfgpPuey9MYi+871JQwllmRfVnW/SKu1sXTDZPfoFomVK57nP+hki++x0jsjAX aUcyZsOdluyuBXI5s5Azxl0TWhb/AIhVVzV1fHeU5uciWbgHas8xlvDFzRu3kPahi8IF 4nKUy6gz0L4kj+Zy/JFkWIKoZ8YimgYQTooafe2073KRXWBp/vk4GMJoWf1xr/InVR9P XV9w== X-Gm-Message-State: ALoCoQnoreVLV9X8wYSlp2+0pvt2OCVtlOK8g4i75z2v7nVVSWj7kGfmB07sSLy0vP1QP0+j9S/k X-Received: by 10.66.140.104 with SMTP id rf8mr3656721pab.107.1396191524632; Sun, 30 Mar 2014 07:58:44 -0700 (PDT) Received: from cmeyer.west.isilon.com (c-67-182-131-225.hsd1.wa.comcast.net. [67.182.131.225]) by mx.google.com with ESMTPSA id sy2sm37618652pbc.28.2014.03.30.07.58.42 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sun, 30 Mar 2014 07:58:43 -0700 (PDT) From: Conrad Meyer To: "Theodore Ts'o" , Andreas Dilger Cc: linux-ext4@vger.kernel.org, linux-kernel@vger.kernel.org, Conrad Meyer Subject: [PATCH] fs: ext4: Sign-extend tv_sec after ORing in epoch bits Date: Sun, 30 Mar 2014 07:58:34 -0700 Message-Id: <1396191514-19081-1-git-send-email-cse.cem@gmail.com> X-Mailer: git-send-email 1.9.0 Sender: linux-ext4-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-ext4@vger.kernel.org Fixes kernel.org bug #23732. Background: ext4 stores time as a 34-bit quantity; 2 bits in some extra bits unneeded for nanoseconds in the inode, and 32 bits in the seconds field. On systems with 64-bit time_t, the EXT4_*INODE_GET_XTIME() code incorrectly sign-extended the low 32-bits of the seconds quantity before ORing in the 2 "epoch" bits from nanoseconds. This patch ORs in the 2 higher bits, then sign extends the 34-bit signed number to 64 bits. Signed-off-by: Conrad Meyer --- Patch against next-20140328. Note, the on-disk format has always been written correctly. It was just interpreted incorrectly. Repro: Before: $ touch -d 2038-01-31 test-123 $ sudo sh -c "echo 3 > /proc/sys/vm/drop_caches" $ ls -ld test-123 drwxrwxr-x 2 cmeyer cmeyer 4096 Dec 25 1901 test-123 After: $ ls -ld test-123 drwxrwxr-x 2 cmeyer cmeyer 4096 Jan 31 2038 test-123 Thanks! --- fs/ext4/ext4.h | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index f4f889e..07ee03d 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -710,6 +710,8 @@ struct move_extent { #define EXT4_EPOCH_BITS 2 #define EXT4_EPOCH_MASK ((1 << EXT4_EPOCH_BITS) - 1) #define EXT4_NSEC_MASK (~0UL << EXT4_EPOCH_BITS) +#define EXT4_EPOCH_SIGN (((1UL << (EXT4_EPOCH_BITS - 1)) << 16) << 16) +#define EXT4_SIGN_EXT (~((((1UL << EXT4_EPOCH_BITS) << 16) << 16) - 1)) /* * Extended fields will fit into an inode if the filesystem was formatted @@ -761,19 +763,23 @@ do { \ #define EXT4_INODE_GET_XTIME(xtime, inode, raw_inode) \ do { \ - (inode)->xtime.tv_sec = (signed)le32_to_cpu((raw_inode)->xtime); \ + (inode)->xtime.tv_sec = (__u64)le32_to_cpu((raw_inode)->xtime); \ if (EXT4_FITS_IN_INODE(raw_inode, EXT4_I(inode), xtime ## _extra)) \ ext4_decode_extra_time(&(inode)->xtime, \ raw_inode->xtime ## _extra); \ else \ (inode)->xtime.tv_nsec = 0; \ + if (sizeof((inode)->xtime.tv_sec) > 4) { \ + if ((inode)->xtime.tv_sec & EXT4_EPOCH_SIGN) \ + (inode)->xtime.tv_sec |= EXT4_SIGN_EXT; \ + } \ } while (0) #define EXT4_EINODE_GET_XTIME(xtime, einode, raw_inode) \ do { \ if (EXT4_FITS_IN_INODE(raw_inode, einode, xtime)) \ (einode)->xtime.tv_sec = \ - (signed)le32_to_cpu((raw_inode)->xtime); \ + (__u64)le32_to_cpu((raw_inode)->xtime); \ else \ (einode)->xtime.tv_sec = 0; \ if (EXT4_FITS_IN_INODE(raw_inode, einode, xtime ## _extra)) \ @@ -781,6 +787,10 @@ do { \ raw_inode->xtime ## _extra); \ else \ (einode)->xtime.tv_nsec = 0; \ + if (sizeof((einode)->xtime.tv_sec) > 4) { \ + if ((einode)->xtime.tv_sec & EXT4_EPOCH_SIGN) \ + (einode)->xtime.tv_sec |= EXT4_SIGN_EXT; \ + } \ } while (0) #define i_disk_version osd1.linux1.l_i_version