All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/14] AFS: Fixes and cleanups
@ 2017-02-24 13:13 David Howells
  2017-02-24 13:13 ` [PATCH 01/14] afs: Fix missing put_page() David Howells
                   ` (13 more replies)
  0 siblings, 14 replies; 15+ messages in thread
From: David Howells @ 2017-02-24 13:13 UTC (permalink / raw)
  To: viro; +Cc: dhowells, linux-fsdevel, linux-kernel, linux-afs


Hi Al,

Here are some fixes to the AFS filesystem, including:

 (1) Refcount errors.

 (2) Showing the GID from the server in stat.

 (3) Fix handling of AFS mode bits (which don't work quite the same way as
     Linux mode bits).

 (4) Handle a callback where the FID array and the callback array arguments
     are not populated with the same number of entries (the callback array
     may be empty).

 (5) Better handle FS.FetchData{,64} returning more or less data than
     requested (usually because the EOF pointer shifted).

 (6) Make afs_write_end() handle a short write to a page (ie. EFAULT).

 (7) Flush outstanding writes on closing a file to be consistent with NFS,
     CIFS and other AFS clients.

 (8) Mountpoints (which appear as special symlinks with mode 0644) can be
     differentiated from real symlinks (with mode 0777) can be
     distinguished on mode alone and so we shouldn't try parsing the
     symlink.

 (9) RCU initialisation fixes.

(10) Internal time field 64-bit-isation.

The patches can be found here also:

	http://git.kernel.org/cgit/linux/kernel/git/dhowells/linux-fs.git/log/?h=afs

Tagged thusly:

	git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs.git
	afs-20170224

David
---
Andreea-Cristina Bernat (2):
      afs: inode: Replace rcu_assign_pointer() with RCU_INIT_POINTER()
      afs: security: Replace rcu_assign_pointer() with RCU_INIT_POINTER()

David Howells (7):
      afs: Fix missing put_page()
      afs: Fix page overput in afs_fill_page()
      afs: Handle better the server returning excess or short data
      afs: Kill struct afs_read::pg_offset
      afs: Handle a short write to an AFS page
      afs: Flush outstanding writes when an fd is closed
      afs: Distinguish mountpoints from symlinks by file mode alone

Marc Dionne (3):
      afs: Populate group ID from vnode status
      afs: Adjust mode bits processing
      afs: Deal with an empty callback array

Tina Ruchandani (2):
      afs: Migrate vlocation fields to 64-bit
      afs: Prevent callback expiry timer overflow


 fs/afs/callback.c  |    7 ++++---
 fs/afs/cmservice.c |   11 +++++------
 fs/afs/file.c      |    8 ++++++--
 fs/afs/fsclient.c  |   53 +++++++++++++++++++++++++++++++++++++---------------
 fs/afs/inode.c     |   40 +++++++++++++++++++++------------------
 fs/afs/internal.h  |   21 ++++++++++++---------
 fs/afs/mntpt.c     |   53 ----------------------------------------------------
 fs/afs/security.c  |    9 +++++++--
 fs/afs/server.c    |    6 +++---
 fs/afs/vlocation.c |   16 +++++++++-------
 fs/afs/write.c     |   44 ++++++++++++++++++++++++++++++++++---------
 11 files changed, 140 insertions(+), 128 deletions(-)

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 01/14] afs: Fix missing put_page()
  2017-02-24 13:13 [PATCH 00/14] AFS: Fixes and cleanups David Howells
@ 2017-02-24 13:13 ` David Howells
  2017-02-24 13:13 ` [PATCH 02/14] afs: Fix page overput in afs_fill_page() David Howells
                   ` (12 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: David Howells @ 2017-02-24 13:13 UTC (permalink / raw)
  To: viro; +Cc: dhowells, linux-fsdevel, linux-kernel, linux-afs

In afs_writepages_region(), inside the loop where we find dirty pages to
deal with, one of the if-statements is missing a put_page().

Signed-off-by: David Howells <dhowells@redhat.com>
---

 fs/afs/write.c |    1 +
 1 file changed, 1 insertion(+)

diff --git a/fs/afs/write.c b/fs/afs/write.c
index c83c1a0e851f..e919e64cd4e0 100644
--- a/fs/afs/write.c
+++ b/fs/afs/write.c
@@ -513,6 +513,7 @@ static int afs_writepages_region(struct address_space *mapping,
 
 		if (PageWriteback(page) || !PageDirty(page)) {
 			unlock_page(page);
+			put_page(page);
 			continue;
 		}
 

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 02/14] afs: Fix page overput in afs_fill_page()
  2017-02-24 13:13 [PATCH 00/14] AFS: Fixes and cleanups David Howells
  2017-02-24 13:13 ` [PATCH 01/14] afs: Fix missing put_page() David Howells
@ 2017-02-24 13:13 ` David Howells
  2017-02-24 13:13 ` [PATCH 03/14] afs: Populate group ID from vnode status David Howells
                   ` (11 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: David Howells @ 2017-02-24 13:13 UTC (permalink / raw)
  To: viro; +Cc: Marc Dionne, dhowells, linux-fsdevel, linux-kernel, linux-afs

afs_fill_page() loads the page it wants to fill into the afs_read request
without incrementing its refcount - but then calls afs_put_read() to clean
up afterwards, which then releases a ref on the page.

Fix this by getting a ref on the page before calling
afs_vnode_fetch_data().

This causes sync after a write to hang in afs_writepages_region() because
find_get_pages_tag() gets confused and doesn't return.

Fixes: 196ee9cd2d04 ("afs: Make afs_fs_fetch_data() take a list of pages")
Reported-by: Marc Dionne <marc.dionne@auristor.com>
Signed-off-by: David Howells <dhowells@redhat.com>
Tested-by: Marc Dionne <marc.dionne@auristor.com>
---

 fs/afs/write.c |    1 +
 1 file changed, 1 insertion(+)

diff --git a/fs/afs/write.c b/fs/afs/write.c
index e919e64cd4e0..3ac52f6a96ff 100644
--- a/fs/afs/write.c
+++ b/fs/afs/write.c
@@ -101,6 +101,7 @@ static int afs_fill_page(struct afs_vnode *vnode, struct key *key,
 	req->pos = pos;
 	req->nr_pages = 1;
 	req->pages[0] = page;
+	get_page(page);
 
 	i_size = i_size_read(&vnode->vfs_inode);
 	if (pos + PAGE_SIZE > i_size)

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 03/14] afs: Populate group ID from vnode status
  2017-02-24 13:13 [PATCH 00/14] AFS: Fixes and cleanups David Howells
  2017-02-24 13:13 ` [PATCH 01/14] afs: Fix missing put_page() David Howells
  2017-02-24 13:13 ` [PATCH 02/14] afs: Fix page overput in afs_fill_page() David Howells
@ 2017-02-24 13:13 ` David Howells
  2017-02-24 13:13 ` [PATCH 04/14] afs: Adjust mode bits processing David Howells
                   ` (10 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: David Howells @ 2017-02-24 13:13 UTC (permalink / raw)
  To: viro; +Cc: Marc Dionne, dhowells, linux-fsdevel, linux-kernel, linux-afs

From: Marc Dionne <marc.dionne@auristor.com>

The group was hard coded to GLOBAL_ROOT_GID; use the group
ID that was received from the server.

Signed-off-by: Marc Dionne <marc.dionne@auristor.com>
Signed-off-by: David Howells <dhowells@redhat.com>
---

 fs/afs/inode.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fs/afs/inode.c b/fs/afs/inode.c
index 86cc7264c21c..df9fa4ddcf3a 100644
--- a/fs/afs/inode.c
+++ b/fs/afs/inode.c
@@ -70,7 +70,7 @@ static int afs_inode_map_status(struct afs_vnode *vnode, struct key *key)
 
 	set_nlink(inode, vnode->status.nlink);
 	inode->i_uid		= vnode->status.owner;
-	inode->i_gid		= GLOBAL_ROOT_GID;
+	inode->i_gid            = vnode->status.group;
 	inode->i_size		= vnode->status.size;
 	inode->i_ctime.tv_sec	= vnode->status.mtime_server;
 	inode->i_ctime.tv_nsec	= 0;

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 04/14] afs: Adjust mode bits processing
  2017-02-24 13:13 [PATCH 00/14] AFS: Fixes and cleanups David Howells
                   ` (2 preceding siblings ...)
  2017-02-24 13:13 ` [PATCH 03/14] afs: Populate group ID from vnode status David Howells
@ 2017-02-24 13:13 ` David Howells
  2017-02-24 13:13 ` [PATCH 05/14] afs: Deal with an empty callback array David Howells
                   ` (9 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: David Howells @ 2017-02-24 13:13 UTC (permalink / raw)
  To: viro; +Cc: Marc Dionne, dhowells, linux-fsdevel, linux-kernel, linux-afs

From: Marc Dionne <marc.dionne@auristor.com>

Mode bits for an afs file should not be enforced in the usual
way.

For files, the absence of user bits can restrict file access
with respect to what is granted by the server.

These bits apply regardless of the owner or the current uid; the
rest of the mode bits (group, other) are ignored.

Signed-off-by: Marc Dionne <marc.dionne@auristor.com>
Signed-off-by: David Howells <dhowells@redhat.com>
---

 fs/afs/security.c |    7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/fs/afs/security.c b/fs/afs/security.c
index 8d010422dc89..bfa9d3428383 100644
--- a/fs/afs/security.c
+++ b/fs/afs/security.c
@@ -340,17 +340,22 @@ int afs_permission(struct inode *inode, int mask)
 	} else {
 		if (!(access & AFS_ACE_LOOKUP))
 			goto permission_denied;
+		if ((mask & MAY_EXEC) && !(inode->i_mode & S_IXUSR))
+			goto permission_denied;
 		if (mask & (MAY_EXEC | MAY_READ)) {
 			if (!(access & AFS_ACE_READ))
 				goto permission_denied;
+			if (!(inode->i_mode & S_IRUSR))
+				goto permission_denied;
 		} else if (mask & MAY_WRITE) {
 			if (!(access & AFS_ACE_WRITE))
 				goto permission_denied;
+			if (!(inode->i_mode & S_IWUSR))
+				goto permission_denied;
 		}
 	}
 
 	key_put(key);
-	ret = generic_permission(inode, mask);
 	_leave(" = %d", ret);
 	return ret;
 

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 05/14] afs: Deal with an empty callback array
  2017-02-24 13:13 [PATCH 00/14] AFS: Fixes and cleanups David Howells
                   ` (3 preceding siblings ...)
  2017-02-24 13:13 ` [PATCH 04/14] afs: Adjust mode bits processing David Howells
@ 2017-02-24 13:13 ` David Howells
  2017-02-24 13:14 ` [PATCH 06/14] afs: Handle better the server returning excess or short data David Howells
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: David Howells @ 2017-02-24 13:13 UTC (permalink / raw)
  To: viro; +Cc: Marc Dionne, dhowells, linux-fsdevel, linux-kernel, linux-afs

From: Marc Dionne <marc.dionne@auristor.com>

Servers may send a callback array that is the same size as
the FID array, or an empty array.  If the callback count is
0, the code would attempt to read (fid_count * 12) bytes of
data, which would fail and result in an unmarshalling error.
This would lead to stale data for remotely modified files
or directories.

Store the callback array size in the internal afs_call
structure and use that to determine the amount of data to
read.

Signed-off-by: Marc Dionne <marc.dionne@auristor.com>
---

 fs/afs/cmservice.c |   11 +++++------
 fs/afs/internal.h  |    5 ++++-
 2 files changed, 9 insertions(+), 7 deletions(-)

diff --git a/fs/afs/cmservice.c b/fs/afs/cmservice.c
index 2edbdcbf6432..3062cceb5c2a 100644
--- a/fs/afs/cmservice.c
+++ b/fs/afs/cmservice.c
@@ -187,7 +187,6 @@ static int afs_deliver_cb_callback(struct afs_call *call)
 	struct afs_callback *cb;
 	struct afs_server *server;
 	__be32 *bp;
-	u32 tmp;
 	int ret, loop;
 
 	_enter("{%u}", call->unmarshall);
@@ -249,9 +248,9 @@ static int afs_deliver_cb_callback(struct afs_call *call)
 		if (ret < 0)
 			return ret;
 
-		tmp = ntohl(call->tmp);
-		_debug("CB count: %u", tmp);
-		if (tmp != call->count && tmp != 0)
+		call->count2 = ntohl(call->tmp);
+		_debug("CB count: %u", call->count2);
+		if (call->count2 != call->count && call->count2 != 0)
 			return -EBADMSG;
 		call->offset = 0;
 		call->unmarshall++;
@@ -259,14 +258,14 @@ static int afs_deliver_cb_callback(struct afs_call *call)
 	case 4:
 		_debug("extract CB array");
 		ret = afs_extract_data(call, call->buffer,
-				       call->count * 3 * 4, false);
+				       call->count2 * 3 * 4, false);
 		if (ret < 0)
 			return ret;
 
 		_debug("unmarshall CB array");
 		cb = call->request;
 		bp = call->buffer;
-		for (loop = call->count; loop > 0; loop--, cb++) {
+		for (loop = call->count2; loop > 0; loop--, cb++) {
 			cb->version	= ntohl(*bp++);
 			cb->expiry	= ntohl(*bp++);
 			cb->type	= ntohl(*bp++);
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index 8acf3670e756..68a40e880eb9 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -90,7 +90,10 @@ struct afs_call {
 	unsigned		request_size;	/* size of request data */
 	unsigned		reply_max;	/* maximum size of reply */
 	unsigned		first_offset;	/* offset into mapping[first] */
-	unsigned		last_to;	/* amount of mapping[last] */
+	union {
+		unsigned	last_to;	/* amount of mapping[last] */
+		unsigned	count2;		/* count used in unmarshalling */
+	};
 	unsigned char		unmarshall;	/* unmarshalling phase */
 	bool			incoming;	/* T if incoming call */
 	bool			send_pages;	/* T if data from mapping should be sent */

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 06/14] afs: Handle better the server returning excess or short data
  2017-02-24 13:13 [PATCH 00/14] AFS: Fixes and cleanups David Howells
                   ` (4 preceding siblings ...)
  2017-02-24 13:13 ` [PATCH 05/14] afs: Deal with an empty callback array David Howells
@ 2017-02-24 13:14 ` David Howells
  2017-02-24 13:14 ` [PATCH 07/14] afs: Kill struct afs_read::pg_offset David Howells
                   ` (7 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: David Howells @ 2017-02-24 13:14 UTC (permalink / raw)
  To: viro; +Cc: dhowells, linux-fsdevel, linux-kernel, linux-afs

When an AFS server is given an FS.FetchData{,64} request to read data from
a file, it is permitted by the protocol to return more or less than was
requested.  kafs currently relies on the latter behaviour in readpage{,s}
to handle a partial page at the end of the file (we just ask for a whole
page and clear space beyond the short read).

However, we don't handle all cases.  Add:

 (1) Handle excess data by discarding it rather than aborting.  Note that
     we use a common static buffer to discard into so that the decryption
     algorithm advances the PCBC state.

 (2) Handle a short read that affects more than just the last page.

Note that if a read comes up unexpectedly short of long, it's possible that
the server's copy of the file changed - in which case the data version
number will have been incremented and the callback will have been broken -
in which case all the pages currently attached to the inode will be zapped
anyway at some point.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 fs/afs/file.c     |    7 +++++--
 fs/afs/fsclient.c |   49 +++++++++++++++++++++++++++++++++++--------------
 2 files changed, 40 insertions(+), 16 deletions(-)

diff --git a/fs/afs/file.c b/fs/afs/file.c
index ba7b71fba34b..a38e1c30d110 100644
--- a/fs/afs/file.c
+++ b/fs/afs/file.c
@@ -184,10 +184,13 @@ int afs_page_filler(void *data, struct page *page)
 		if (!req)
 			goto enomem;
 
+		/* We request a full page.  If the page is a partial one at the
+		 * end of the file, the server will return a short read and the
+		 * unmarshalling code will clear the unfilled space.
+		 */
 		atomic_set(&req->usage, 1);
 		req->pos = (loff_t)page->index << PAGE_SHIFT;
-		req->len = min_t(size_t, i_size_read(inode) - req->pos,
-				 PAGE_SIZE);
+		req->len = PAGE_SIZE;
 		req->nr_pages = 1;
 		req->pages[0] = page;
 		get_page(page);
diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c
index ac8e766978dc..bf8904a1a58f 100644
--- a/fs/afs/fsclient.c
+++ b/fs/afs/fsclient.c
@@ -17,6 +17,12 @@
 #include "afs_fs.h"
 
 /*
+ * We need somewhere to discard into in case the server helpfully returns more
+ * than we asked for in FS.FetchData{,64}.
+ */
+static u8 afs_discard_buffer[64];
+
+/*
  * decode an AFSFid block
  */
 static void xdr_decode_AFSFid(const __be32 **_bp, struct afs_fid *fid)
@@ -353,12 +359,6 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call)
 
 		req->actual_len |= ntohl(call->tmp);
 		_debug("DATA length: %llu", req->actual_len);
-		/* Check that the server didn't want to send us extra.  We
-		 * might want to just discard instead, but that requires
-		 * cooperation from AF_RXRPC.
-		 */
-		if (req->actual_len > req->len)
-			return -EBADMSG;
 
 		req->remain = req->actual_len;
 		call->offset = req->pos & (PAGE_SIZE - 1);
@@ -368,6 +368,7 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call)
 		call->unmarshall++;
 
 	begin_page:
+		ASSERTCMP(req->index, <, req->nr_pages);
 		if (req->remain > PAGE_SIZE - call->offset)
 			size = PAGE_SIZE - call->offset;
 		else
@@ -390,18 +391,37 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call)
 			if (req->page_done)
 				req->page_done(call, req);
 			if (req->remain > 0) {
-				req->index++;
 				call->offset = 0;
+				req->index++;
+				if (req->index >= req->nr_pages)
+					goto begin_discard;
 				goto begin_page;
 			}
 		}
+		goto no_more_data;
+
+		/* Discard any excess data the server gave us */
+	begin_discard:
+	case 4:
+		size = min_t(size_t, sizeof(afs_discard_buffer), req->remain);
+		call->count = size;
+		_debug("extract discard %u/%llu %zu/%u",
+		       req->remain, req->actual_len, call->offset, call->count);
+
+		call->offset = 0;
+		ret = afs_extract_data(call, afs_discard_buffer, call->count, true);
+		req->remain -= call->offset;
+		if (ret < 0)
+			return ret;
+		if (req->remain > 0)
+			goto begin_discard;
 
 	no_more_data:
 		call->offset = 0;
-		call->unmarshall++;
+		call->unmarshall = 5;
 
 		/* extract the metadata */
-	case 4:
+	case 5:
 		ret = afs_extract_data(call, call->buffer,
 				       (21 + 3 + 6) * 4, false);
 		if (ret < 0)
@@ -416,16 +436,17 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call)
 		call->offset = 0;
 		call->unmarshall++;
 
-	case 5:
+	case 6:
 		break;
 	}
 
-	if (call->count < PAGE_SIZE) {
-		buffer = kmap(req->pages[req->index]);
-		memset(buffer + call->count, 0, PAGE_SIZE - call->count);
-		kunmap(req->pages[req->index]);
+	for (; req->index < req->nr_pages; req->index++) {
+		if (call->count < PAGE_SIZE)
+			zero_user_segment(req->pages[req->index],
+					  call->count, PAGE_SIZE);
 		if (req->page_done)
 			req->page_done(call, req);
+		call->count = 0;
 	}
 
 	_leave(" = 0 [done]");

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 07/14] afs: Kill struct afs_read::pg_offset
  2017-02-24 13:13 [PATCH 00/14] AFS: Fixes and cleanups David Howells
                   ` (5 preceding siblings ...)
  2017-02-24 13:14 ` [PATCH 06/14] afs: Handle better the server returning excess or short data David Howells
@ 2017-02-24 13:14 ` David Howells
  2017-02-24 13:14 ` [PATCH 08/14] afs: Handle a short write to an AFS page David Howells
                   ` (6 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: David Howells @ 2017-02-24 13:14 UTC (permalink / raw)
  To: viro; +Cc: dhowells, linux-fsdevel, linux-kernel, linux-afs

Kill struct afs_read::pg_offset as nothing uses it.  It's unnecessary as pos
can be masked off.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 fs/afs/internal.h |    1 -
 1 file changed, 1 deletion(-)

diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index 68a40e880eb9..4213aa35deed 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -135,7 +135,6 @@ struct afs_read {
 	atomic_t		usage;
 	unsigned int		remain;		/* Amount remaining */
 	unsigned int		index;		/* Which page we're reading into */
-	unsigned int		pg_offset;	/* Offset in page we're at */
 	unsigned int		nr_pages;
 	void (*page_done)(struct afs_call *, struct afs_read *);
 	struct page		*pages[];

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 08/14] afs: Handle a short write to an AFS page
  2017-02-24 13:13 [PATCH 00/14] AFS: Fixes and cleanups David Howells
                   ` (6 preceding siblings ...)
  2017-02-24 13:14 ` [PATCH 07/14] afs: Kill struct afs_read::pg_offset David Howells
@ 2017-02-24 13:14 ` David Howells
  2017-02-24 13:14 ` [PATCH 09/14] afs: Flush outstanding writes when an fd is closed David Howells
                   ` (5 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: David Howells @ 2017-02-24 13:14 UTC (permalink / raw)
  To: viro; +Cc: dhowells, linux-fsdevel, linux-kernel, linux-afs

Handle the situation where afs_write_begin() is told to expect that a
full-page write will be made, but this doesn't happen (EFAULT, CTRL-C,
etc.), and so afs_write_end() sees a partial write took place.  Currently,
no attempt is to deal with the discrepency.

Fix this by loading the gap from the server.

Reported-by: Al Viro <viro@ZenIV.linux.org.uk>
Signed-off-by: David Howells <dhowells@redhat.com>
---

 fs/afs/fsclient.c |    4 +++-
 fs/afs/internal.h |    2 +-
 fs/afs/write.c    |   28 +++++++++++++++++++---------
 3 files changed, 23 insertions(+), 11 deletions(-)

diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c
index bf8904a1a58f..6f917dd1238c 100644
--- a/fs/afs/fsclient.c
+++ b/fs/afs/fsclient.c
@@ -393,8 +393,10 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call)
 			if (req->remain > 0) {
 				call->offset = 0;
 				req->index++;
-				if (req->index >= req->nr_pages)
+				if (req->index >= req->nr_pages) {
+					call->unmarshall = 4;
 					goto begin_discard;
+				}
 				goto begin_page;
 			}
 		}
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index 4213aa35deed..4ffd50de9386 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -130,7 +130,7 @@ struct afs_call_type {
  */
 struct afs_read {
 	loff_t			pos;		/* Where to start reading */
-	loff_t			len;		/* How much to read */
+	loff_t			len;		/* How much we're asking for */
 	loff_t			actual_len;	/* How much we're actually getting */
 	atomic_t		usage;
 	unsigned int		remain;		/* Amount remaining */
diff --git a/fs/afs/write.c b/fs/afs/write.c
index 3ac52f6a96ff..ea66890fc188 100644
--- a/fs/afs/write.c
+++ b/fs/afs/write.c
@@ -84,10 +84,9 @@ void afs_put_writeback(struct afs_writeback *wb)
  * partly or wholly fill a page that's under preparation for writing
  */
 static int afs_fill_page(struct afs_vnode *vnode, struct key *key,
-			 loff_t pos, struct page *page)
+			 loff_t pos, unsigned int len, struct page *page)
 {
 	struct afs_read *req;
-	loff_t i_size;
 	int ret;
 
 	_enter(",,%llu", (unsigned long long)pos);
@@ -99,16 +98,11 @@ static int afs_fill_page(struct afs_vnode *vnode, struct key *key,
 
 	atomic_set(&req->usage, 1);
 	req->pos = pos;
+	req->len = len;
 	req->nr_pages = 1;
 	req->pages[0] = page;
 	get_page(page);
 
-	i_size = i_size_read(&vnode->vfs_inode);
-	if (pos + PAGE_SIZE > i_size)
-		req->len = i_size - pos;
-	else
-		req->len = PAGE_SIZE;
-
 	ret = afs_vnode_fetch_data(vnode, key, req);
 	afs_put_read(req);
 	if (ret < 0) {
@@ -164,7 +158,7 @@ int afs_write_begin(struct file *file, struct address_space *mapping,
 	/* page won't leak in error case: it eventually gets cleaned off LRU */
 
 	if (!PageUptodate(page) && len != PAGE_SIZE) {
-		ret = afs_fill_page(vnode, key, index << PAGE_SHIFT, page);
+		ret = afs_fill_page(vnode, key, pos & PAGE_MASK, PAGE_SIZE, page);
 		if (ret < 0) {
 			kfree(candidate);
 			_leave(" = %d [prep]", ret);
@@ -258,7 +252,9 @@ int afs_write_end(struct file *file, struct address_space *mapping,
 		  struct page *page, void *fsdata)
 {
 	struct afs_vnode *vnode = AFS_FS_I(file_inode(file));
+	struct key *key = file->private_data;
 	loff_t i_size, maybe_i_size;
+	int ret;
 
 	_enter("{%x:%u},{%lx}",
 	       vnode->fid.vid, vnode->fid.vnode, page->index);
@@ -274,6 +270,20 @@ int afs_write_end(struct file *file, struct address_space *mapping,
 		spin_unlock(&vnode->writeback_lock);
 	}
 
+	if (!PageUptodate(page)) {
+		if (copied < len) {
+			/* Try and load any missing data from the server.  The
+			 * unmarshalling routine will take care of clearing any
+			 * bits that are beyond the EOF.
+			 */
+			ret = afs_fill_page(vnode, key, pos + copied,
+					    len - copied, page);
+			if (ret < 0)
+				return ret;
+		}
+		SetPageUptodate(page);
+	}
+
 	set_page_dirty(page);
 	if (PageDirty(page))
 		_debug("dirtied");

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 09/14] afs: Flush outstanding writes when an fd is closed
  2017-02-24 13:13 [PATCH 00/14] AFS: Fixes and cleanups David Howells
                   ` (7 preceding siblings ...)
  2017-02-24 13:14 ` [PATCH 08/14] afs: Handle a short write to an AFS page David Howells
@ 2017-02-24 13:14 ` David Howells
  2017-02-24 13:14 ` [PATCH 10/14] afs: Distinguish mountpoints from symlinks by file mode alone David Howells
                   ` (4 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: David Howells @ 2017-02-24 13:14 UTC (permalink / raw)
  To: viro; +Cc: dhowells, Marc Dionne, linux-fsdevel, linux-kernel, linux-afs

Flush outstanding writes in afs when an fd is closed.  This is what NFS and
CIFS do.

Reported-by: Marc Dionne <marc.c.dionne@gmail.com>
Signed-off-by: David Howells <dhowells@redhat.com>
---

 fs/afs/file.c     |    1 +
 fs/afs/internal.h |    1 +
 fs/afs/write.c    |   14 ++++++++++++++
 3 files changed, 16 insertions(+)

diff --git a/fs/afs/file.c b/fs/afs/file.c
index a38e1c30d110..b5829443ff69 100644
--- a/fs/afs/file.c
+++ b/fs/afs/file.c
@@ -30,6 +30,7 @@ static int afs_readpages(struct file *filp, struct address_space *mapping,
 
 const struct file_operations afs_file_operations = {
 	.open		= afs_open,
+	.flush		= afs_flush,
 	.release	= afs_release,
 	.llseek		= generic_file_llseek,
 	.read_iter	= generic_file_read_iter,
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index 4ffd50de9386..f57fd8e9728d 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -720,6 +720,7 @@ extern int afs_writepages(struct address_space *, struct writeback_control *);
 extern void afs_pages_written_back(struct afs_vnode *, struct afs_call *);
 extern ssize_t afs_file_write(struct kiocb *, struct iov_iter *);
 extern int afs_writeback_all(struct afs_vnode *);
+extern int afs_flush(struct file *, fl_owner_t);
 extern int afs_fsync(struct file *, loff_t, loff_t, int);
 
 
diff --git a/fs/afs/write.c b/fs/afs/write.c
index ea66890fc188..f1450ea09406 100644
--- a/fs/afs/write.c
+++ b/fs/afs/write.c
@@ -758,6 +758,20 @@ int afs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
 }
 
 /*
+ * Flush out all outstanding writes on a file opened for writing when it is
+ * closed.
+ */
+int afs_flush(struct file *file, fl_owner_t id)
+{
+	_enter("");
+
+	if ((file->f_mode & FMODE_WRITE) == 0)
+		return 0;
+
+	return vfs_fsync(file, 0);
+}
+
+/*
  * notification that a previously read-only page is about to become writable
  * - if it returns an error, the caller will deliver a bus error signal
  */

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 10/14] afs: Distinguish mountpoints from symlinks by file mode alone
  2017-02-24 13:13 [PATCH 00/14] AFS: Fixes and cleanups David Howells
                   ` (8 preceding siblings ...)
  2017-02-24 13:14 ` [PATCH 09/14] afs: Flush outstanding writes when an fd is closed David Howells
@ 2017-02-24 13:14 ` David Howells
  2017-02-24 13:14 ` [PATCH 11/14] afs: inode: Replace rcu_assign_pointer() with RCU_INIT_POINTER() David Howells
                   ` (3 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: David Howells @ 2017-02-24 13:14 UTC (permalink / raw)
  To: viro; +Cc: dhowells, linux-fsdevel, linux-afs, Jeffrey Altman, linux-kernel

In AFS, mountpoints appear as symlinks with mode 0644 and normal symlinks
have mode 0777, so use this to distinguish them rather than reading the
content and parsing it.  In the case of a mountpoint, the symlink body is a
formatted string indicating the location of the target volume.

Note that with this, kAFS no longer 'pre-fetches' the contents of symlinks,
so afs_readpage() may fail with an access-denial because when the VFS calls
d_automount(), it wraps the call in an credentials override that sets the
initial creds - thereby preventing access to the caller's keyrings and the
authentication keys held therein.

To this end, a patch reverting that change to the VFS is required also.

Reported-by: Jeffrey Altman <jaltman@auristor.com>
Signed-off-by: David Howells <dhowells@redhat.com>
---

 fs/afs/inode.c    |   29 +++++++++++++++--------------
 fs/afs/internal.h |    1 -
 fs/afs/mntpt.c    |   53 -----------------------------------------------------
 3 files changed, 15 insertions(+), 68 deletions(-)

diff --git a/fs/afs/inode.c b/fs/afs/inode.c
index df9fa4ddcf3a..8f4e70566e44 100644
--- a/fs/afs/inode.c
+++ b/fs/afs/inode.c
@@ -54,8 +54,21 @@ static int afs_inode_map_status(struct afs_vnode *vnode, struct key *key)
 		inode->i_fop	= &afs_dir_file_operations;
 		break;
 	case AFS_FTYPE_SYMLINK:
-		inode->i_mode	= S_IFLNK | vnode->status.mode;
-		inode->i_op	= &page_symlink_inode_operations;
+		/* Symlinks with a mode of 0644 are actually mountpoints. */
+		if ((vnode->status.mode & 0777) == 0644) {
+			inode->i_flags |= S_AUTOMOUNT;
+
+			spin_lock(&vnode->lock);
+			set_bit(AFS_VNODE_MOUNTPOINT, &vnode->flags);
+			spin_unlock(&vnode->lock);
+
+			inode->i_mode	= S_IFDIR | 0555;
+			inode->i_op	= &afs_mntpt_inode_operations;
+			inode->i_fop	= &afs_mntpt_file_operations;
+		} else {
+			inode->i_mode	= S_IFLNK | vnode->status.mode;
+			inode->i_op	= &page_symlink_inode_operations;
+		}
 		inode_nohighmem(inode);
 		break;
 	default:
@@ -79,18 +92,6 @@ static int afs_inode_map_status(struct afs_vnode *vnode, struct key *key)
 	inode->i_generation	= vnode->fid.unique;
 	inode->i_version	= vnode->status.data_version;
 	inode->i_mapping->a_ops	= &afs_fs_aops;
-
-	/* check to see whether a symbolic link is really a mountpoint */
-	if (vnode->status.type == AFS_FTYPE_SYMLINK) {
-		afs_mntpt_check_symlink(vnode, key);
-
-		if (test_bit(AFS_VNODE_MOUNTPOINT, &vnode->flags)) {
-			inode->i_mode	= S_IFDIR | vnode->status.mode;
-			inode->i_op	= &afs_mntpt_inode_operations;
-			inode->i_fop	= &afs_mntpt_file_operations;
-		}
-	}
-
 	return 0;
 }
 
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index f57fd8e9728d..fa13140d3188 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -559,7 +559,6 @@ extern const struct inode_operations afs_autocell_inode_operations;
 extern const struct file_operations afs_mntpt_file_operations;
 
 extern struct vfsmount *afs_d_automount(struct path *);
-extern int afs_mntpt_check_symlink(struct afs_vnode *, struct key *);
 extern void afs_mntpt_kill_timer(void);
 
 /*
diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c
index d4fb0afc0097..bd3b65cde282 100644
--- a/fs/afs/mntpt.c
+++ b/fs/afs/mntpt.c
@@ -47,59 +47,6 @@ static DECLARE_DELAYED_WORK(afs_mntpt_expiry_timer, afs_mntpt_expiry_timed_out);
 static unsigned long afs_mntpt_expiry_timeout = 10 * 60;
 
 /*
- * check a symbolic link to see whether it actually encodes a mountpoint
- * - sets the AFS_VNODE_MOUNTPOINT flag on the vnode appropriately
- */
-int afs_mntpt_check_symlink(struct afs_vnode *vnode, struct key *key)
-{
-	struct page *page;
-	size_t size;
-	char *buf;
-	int ret;
-
-	_enter("{%x:%u,%u}",
-	       vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique);
-
-	/* read the contents of the symlink into the pagecache */
-	page = read_cache_page(AFS_VNODE_TO_I(vnode)->i_mapping, 0,
-			       afs_page_filler, key);
-	if (IS_ERR(page)) {
-		ret = PTR_ERR(page);
-		goto out;
-	}
-
-	ret = -EIO;
-	if (PageError(page))
-		goto out_free;
-
-	buf = kmap(page);
-
-	/* examine the symlink's contents */
-	size = vnode->status.size;
-	_debug("symlink to %*.*s", (int) size, (int) size, buf);
-
-	if (size > 2 &&
-	    (buf[0] == '%' || buf[0] == '#') &&
-	    buf[size - 1] == '.'
-	    ) {
-		_debug("symlink is a mountpoint");
-		spin_lock(&vnode->lock);
-		set_bit(AFS_VNODE_MOUNTPOINT, &vnode->flags);
-		vnode->vfs_inode.i_flags |= S_AUTOMOUNT;
-		spin_unlock(&vnode->lock);
-	}
-
-	ret = 0;
-
-	kunmap(page);
-out_free:
-	put_page(page);
-out:
-	_leave(" = %d", ret);
-	return ret;
-}
-
-/*
  * no valid lookup procedure on this sort of dir
  */
 static struct dentry *afs_mntpt_lookup(struct inode *dir,

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 11/14] afs: inode: Replace rcu_assign_pointer() with RCU_INIT_POINTER()
  2017-02-24 13:13 [PATCH 00/14] AFS: Fixes and cleanups David Howells
                   ` (9 preceding siblings ...)
  2017-02-24 13:14 ` [PATCH 10/14] afs: Distinguish mountpoints from symlinks by file mode alone David Howells
@ 2017-02-24 13:14 ` David Howells
  2017-02-24 13:14 ` [PATCH 12/14] afs: security: " David Howells
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: David Howells @ 2017-02-24 13:14 UTC (permalink / raw)
  To: viro
  Cc: dhowells, Andreea-Cristina Bernat, linux-fsdevel, linux-kernel,
	linux-afs

From: Andreea-Cristina Bernat <bernat.ada@gmail.com>

The use of "rcu_assign_pointer()" is NULLing out the pointer.
According to RCU_INIT_POINTER()'s block comment:
"1.   This use of RCU_INIT_POINTER() is NULLing out the pointer"
it is better to use it instead of rcu_assign_pointer() because it has a
smaller overhead.

The following Coccinelle semantic patch was used:
@@
@@

- rcu_assign_pointer
+ RCU_INIT_POINTER
  (..., NULL)

Signed-off-by: Andreea-Cristina Bernat <bernat.ada@gmail.com>
Signed-off-by: David Howells <dhowells@redhat.com>
---

 fs/afs/inode.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fs/afs/inode.c b/fs/afs/inode.c
index 8f4e70566e44..5707272adf18 100644
--- a/fs/afs/inode.c
+++ b/fs/afs/inode.c
@@ -447,7 +447,7 @@ void afs_evict_inode(struct inode *inode)
 
 	mutex_lock(&vnode->permits_lock);
 	permits = vnode->permits;
-	rcu_assign_pointer(vnode->permits, NULL);
+	RCU_INIT_POINTER(vnode->permits, NULL);
 	mutex_unlock(&vnode->permits_lock);
 	if (permits)
 		call_rcu(&permits->rcu, afs_zap_permits);

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 12/14] afs: security: Replace rcu_assign_pointer() with RCU_INIT_POINTER()
  2017-02-24 13:13 [PATCH 00/14] AFS: Fixes and cleanups David Howells
                   ` (10 preceding siblings ...)
  2017-02-24 13:14 ` [PATCH 11/14] afs: inode: Replace rcu_assign_pointer() with RCU_INIT_POINTER() David Howells
@ 2017-02-24 13:14 ` David Howells
  2017-02-24 13:14 ` [PATCH 13/14] afs: Migrate vlocation fields to 64-bit David Howells
  2017-02-24 13:15 ` [PATCH 14/14] afs: Prevent callback expiry timer overflow David Howells
  13 siblings, 0 replies; 15+ messages in thread
From: David Howells @ 2017-02-24 13:14 UTC (permalink / raw)
  To: viro
  Cc: dhowells, Andreea-Cristina Bernat, linux-fsdevel, linux-kernel,
	linux-afs

From: Andreea-Cristina Bernat <bernat.ada@gmail.com>

The use of "rcu_assign_pointer()" is NULLing out the pointer.
According to RCU_INIT_POINTER()'s block comment:
"1.   This use of RCU_INIT_POINTER() is NULLing out the pointer"
it is better to use it instead of rcu_assign_pointer() because it has a
smaller overhead.

The following Coccinelle semantic patch was used:
@@
@@

- rcu_assign_pointer
+ RCU_INIT_POINTER
  (..., NULL)

Signed-off-by: Andreea-Cristina Bernat <bernat.ada@gmail.com>
Signed-off-by: David Howells <dhowells@redhat.com>
---

 fs/afs/security.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fs/afs/security.c b/fs/afs/security.c
index bfa9d3428383..ecb86a670180 100644
--- a/fs/afs/security.c
+++ b/fs/afs/security.c
@@ -114,7 +114,7 @@ void afs_clear_permits(struct afs_vnode *vnode)
 
 	mutex_lock(&vnode->permits_lock);
 	permits = vnode->permits;
-	rcu_assign_pointer(vnode->permits, NULL);
+	RCU_INIT_POINTER(vnode->permits, NULL);
 	mutex_unlock(&vnode->permits_lock);
 
 	if (permits)

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 13/14] afs: Migrate vlocation fields to 64-bit
  2017-02-24 13:13 [PATCH 00/14] AFS: Fixes and cleanups David Howells
                   ` (11 preceding siblings ...)
  2017-02-24 13:14 ` [PATCH 12/14] afs: security: " David Howells
@ 2017-02-24 13:14 ` David Howells
  2017-02-24 13:15 ` [PATCH 14/14] afs: Prevent callback expiry timer overflow David Howells
  13 siblings, 0 replies; 15+ messages in thread
From: David Howells @ 2017-02-24 13:14 UTC (permalink / raw)
  To: viro; +Cc: dhowells, linux-fsdevel, linux-afs, Tina Ruchandani, linux-kernel

From: Tina Ruchandani <ruchandani.tina@gmail.com>

get_seconds() returns real wall-clock seconds. On 32-bit systems
this value will overflow in year 2038 and beyond. This patch changes
afs's vlocation record to use ktime_get_real_seconds() instead, for the
fields time_of_death and update_at.

Signed-off-by: Tina Ruchandani <ruchandani.tina@gmail.com>
Signed-off-by: David Howells <dhowells@redhat.com>
---

 fs/afs/callback.c  |    7 ++++---
 fs/afs/internal.h  |    7 ++++---
 fs/afs/server.c    |    6 +++---
 fs/afs/vlocation.c |   16 +++++++++-------
 4 files changed, 20 insertions(+), 16 deletions(-)

diff --git a/fs/afs/callback.c b/fs/afs/callback.c
index b29447e03ede..25d404d22cae 100644
--- a/fs/afs/callback.c
+++ b/fs/afs/callback.c
@@ -362,7 +362,7 @@ static void afs_callback_updater(struct work_struct *work)
 {
 	struct afs_server *server;
 	struct afs_vnode *vnode, *xvnode;
-	time_t now;
+	time64_t now;
 	long timeout;
 	int ret;
 
@@ -370,7 +370,7 @@ static void afs_callback_updater(struct work_struct *work)
 
 	_enter("");
 
-	now = get_seconds();
+	now = ktime_get_real_seconds();
 
 	/* find the first vnode to update */
 	spin_lock(&server->cb_lock);
@@ -424,7 +424,8 @@ static void afs_callback_updater(struct work_struct *work)
 
 	/* and then reschedule */
 	_debug("reschedule");
-	vnode->update_at = get_seconds() + afs_vnode_update_timeout;
+	vnode->update_at = ktime_get_real_seconds() +
+			afs_vnode_update_timeout;
 
 	spin_lock(&server->cb_lock);
 
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index fa13140d3188..6a7fa9975cee 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -11,6 +11,7 @@
 
 #include <linux/compiler.h>
 #include <linux/kernel.h>
+#include <linux/ktime.h>
 #include <linux/fs.h>
 #include <linux/pagemap.h>
 #include <linux/rxrpc.h>
@@ -249,7 +250,7 @@ struct afs_cache_vhash {
  */
 struct afs_vlocation {
 	atomic_t		usage;
-	time_t			time_of_death;	/* time at which put reduced usage to 0 */
+	time64_t		time_of_death;	/* time at which put reduced usage to 0 */
 	struct list_head	link;		/* link in cell volume location list */
 	struct list_head	grave;		/* link in master graveyard list */
 	struct list_head	update;		/* link in master update list */
@@ -260,7 +261,7 @@ struct afs_vlocation {
 	struct afs_cache_vlocation vldb;	/* volume information DB record */
 	struct afs_volume	*vols[3];	/* volume access record pointer (index by type) */
 	wait_queue_head_t	waitq;		/* status change waitqueue */
-	time_t			update_at;	/* time at which record should be updated */
+	time64_t		update_at;	/* time at which record should be updated */
 	spinlock_t		lock;		/* access lock */
 	afs_vlocation_state_t	state;		/* volume location state */
 	unsigned short		upd_rej_cnt;	/* ENOMEDIUM count during update */
@@ -273,7 +274,7 @@ struct afs_vlocation {
  */
 struct afs_server {
 	atomic_t		usage;
-	time_t			time_of_death;	/* time at which put reduced usage to 0 */
+	time64_t		time_of_death;	/* time at which put reduced usage to 0 */
 	struct in_addr		addr;		/* server address */
 	struct afs_cell		*cell;		/* cell in which server resides */
 	struct list_head	link;		/* link in cell's server list */
diff --git a/fs/afs/server.c b/fs/afs/server.c
index d4066ab7dd55..c001b1f2455f 100644
--- a/fs/afs/server.c
+++ b/fs/afs/server.c
@@ -242,7 +242,7 @@ void afs_put_server(struct afs_server *server)
 	spin_lock(&afs_server_graveyard_lock);
 	if (atomic_read(&server->usage) == 0) {
 		list_move_tail(&server->grave, &afs_server_graveyard);
-		server->time_of_death = get_seconds();
+		server->time_of_death = ktime_get_real_seconds();
 		queue_delayed_work(afs_wq, &afs_server_reaper,
 				   afs_server_timeout * HZ);
 	}
@@ -277,9 +277,9 @@ static void afs_reap_server(struct work_struct *work)
 	LIST_HEAD(corpses);
 	struct afs_server *server;
 	unsigned long delay, expiry;
-	time_t now;
+	time64_t now;
 
-	now = get_seconds();
+	now = ktime_get_real_seconds();
 	spin_lock(&afs_server_graveyard_lock);
 
 	while (!list_empty(&afs_server_graveyard)) {
diff --git a/fs/afs/vlocation.c b/fs/afs/vlocation.c
index d7d8dd8c0b31..37b7c3b342a6 100644
--- a/fs/afs/vlocation.c
+++ b/fs/afs/vlocation.c
@@ -340,7 +340,8 @@ static void afs_vlocation_queue_for_updates(struct afs_vlocation *vl)
 	struct afs_vlocation *xvl;
 
 	/* wait at least 10 minutes before updating... */
-	vl->update_at = get_seconds() + afs_vlocation_update_timeout;
+	vl->update_at = ktime_get_real_seconds() +
+			afs_vlocation_update_timeout;
 
 	spin_lock(&afs_vlocation_updates_lock);
 
@@ -506,7 +507,7 @@ void afs_put_vlocation(struct afs_vlocation *vl)
 	if (atomic_read(&vl->usage) == 0) {
 		_debug("buried");
 		list_move_tail(&vl->grave, &afs_vlocation_graveyard);
-		vl->time_of_death = get_seconds();
+		vl->time_of_death = ktime_get_real_seconds();
 		queue_delayed_work(afs_wq, &afs_vlocation_reap,
 				   afs_vlocation_timeout * HZ);
 
@@ -543,11 +544,11 @@ static void afs_vlocation_reaper(struct work_struct *work)
 	LIST_HEAD(corpses);
 	struct afs_vlocation *vl;
 	unsigned long delay, expiry;
-	time_t now;
+	time64_t now;
 
 	_enter("");
 
-	now = get_seconds();
+	now = ktime_get_real_seconds();
 	spin_lock(&afs_vlocation_graveyard_lock);
 
 	while (!list_empty(&afs_vlocation_graveyard)) {
@@ -622,13 +623,13 @@ static void afs_vlocation_updater(struct work_struct *work)
 {
 	struct afs_cache_vlocation vldb;
 	struct afs_vlocation *vl, *xvl;
-	time_t now;
+	time64_t now;
 	long timeout;
 	int ret;
 
 	_enter("");
 
-	now = get_seconds();
+	now = ktime_get_real_seconds();
 
 	/* find a record to update */
 	spin_lock(&afs_vlocation_updates_lock);
@@ -684,7 +685,8 @@ static void afs_vlocation_updater(struct work_struct *work)
 
 	/* and then reschedule */
 	_debug("reschedule");
-	vl->update_at = get_seconds() + afs_vlocation_update_timeout;
+	vl->update_at = ktime_get_real_seconds() +
+			afs_vlocation_update_timeout;
 
 	spin_lock(&afs_vlocation_updates_lock);
 

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 14/14] afs: Prevent callback expiry timer overflow
  2017-02-24 13:13 [PATCH 00/14] AFS: Fixes and cleanups David Howells
                   ` (12 preceding siblings ...)
  2017-02-24 13:14 ` [PATCH 13/14] afs: Migrate vlocation fields to 64-bit David Howells
@ 2017-02-24 13:15 ` David Howells
  13 siblings, 0 replies; 15+ messages in thread
From: David Howells @ 2017-02-24 13:15 UTC (permalink / raw)
  To: viro; +Cc: dhowells, linux-fsdevel, linux-afs, Tina Ruchandani, linux-kernel

From: Tina Ruchandani <ruchandani.tina@gmail.com>

get_seconds() returns real wall-clock seconds. On 32-bit systems
this value will overflow in year 2038 and beyond. This patch changes
afs_vnode record to use ktime_get_real_seconds() instead, for the
fields cb_expires and cb_expires_at.

Signed-off-by: Tina Ruchandani <ruchandani.tina@gmail.com>
Signed-off-by: David Howells <dhowells@redhat.com>
---

 fs/afs/fsclient.c |    2 +-
 fs/afs/inode.c    |    7 ++++---
 fs/afs/internal.h |    4 ++--
 3 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c
index 6f917dd1238c..c05452a09398 100644
--- a/fs/afs/fsclient.c
+++ b/fs/afs/fsclient.c
@@ -145,7 +145,7 @@ static void xdr_decode_AFSCallBack(const __be32 **_bp, struct afs_vnode *vnode)
 	vnode->cb_version	= ntohl(*bp++);
 	vnode->cb_expiry	= ntohl(*bp++);
 	vnode->cb_type		= ntohl(*bp++);
-	vnode->cb_expires	= vnode->cb_expiry + get_seconds();
+	vnode->cb_expires	= vnode->cb_expiry + ktime_get_real_seconds();
 	*_bp = bp;
 }
 
diff --git a/fs/afs/inode.c b/fs/afs/inode.c
index 5707272adf18..1614998886f3 100644
--- a/fs/afs/inode.c
+++ b/fs/afs/inode.c
@@ -246,12 +246,13 @@ struct inode *afs_iget(struct super_block *sb, struct key *key,
 			vnode->cb_version = 0;
 			vnode->cb_expiry = 0;
 			vnode->cb_type = 0;
-			vnode->cb_expires = get_seconds();
+			vnode->cb_expires = ktime_get_real_seconds();
 		} else {
 			vnode->cb_version = cb->version;
 			vnode->cb_expiry = cb->expiry;
 			vnode->cb_type = cb->type;
-			vnode->cb_expires = vnode->cb_expiry + get_seconds();
+			vnode->cb_expires = vnode->cb_expiry +
+				ktime_get_real_seconds();
 		}
 	}
 
@@ -324,7 +325,7 @@ int afs_validate(struct afs_vnode *vnode, struct key *key)
 	    !test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags) &&
 	    !test_bit(AFS_VNODE_MODIFIED, &vnode->flags) &&
 	    !test_bit(AFS_VNODE_ZAP_DATA, &vnode->flags)) {
-		if (vnode->cb_expires < get_seconds() + 10) {
+		if (vnode->cb_expires < ktime_get_real_seconds() + 10) {
 			_debug("callback expired");
 			set_bit(AFS_VNODE_CB_BROKEN, &vnode->flags);
 		} else {
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index 6a7fa9975cee..c956ccbe50b0 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -377,8 +377,8 @@ struct afs_vnode {
 	struct rb_node		server_rb;	/* link in server->fs_vnodes */
 	struct rb_node		cb_promise;	/* link in server->cb_promises */
 	struct work_struct	cb_broken_work;	/* work to be done on callback break */
-	time_t			cb_expires;	/* time at which callback expires */
-	time_t			cb_expires_at;	/* time used to order cb_promise */
+	time64_t		cb_expires;	/* time at which callback expires */
+	time64_t		cb_expires_at;	/* time used to order cb_promise */
 	unsigned		cb_version;	/* callback version */
 	unsigned		cb_expiry;	/* callback expiry time */
 	afs_callback_type_t	cb_type;	/* type of callback */

^ permalink raw reply related	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2017-02-24 13:24 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-02-24 13:13 [PATCH 00/14] AFS: Fixes and cleanups David Howells
2017-02-24 13:13 ` [PATCH 01/14] afs: Fix missing put_page() David Howells
2017-02-24 13:13 ` [PATCH 02/14] afs: Fix page overput in afs_fill_page() David Howells
2017-02-24 13:13 ` [PATCH 03/14] afs: Populate group ID from vnode status David Howells
2017-02-24 13:13 ` [PATCH 04/14] afs: Adjust mode bits processing David Howells
2017-02-24 13:13 ` [PATCH 05/14] afs: Deal with an empty callback array David Howells
2017-02-24 13:14 ` [PATCH 06/14] afs: Handle better the server returning excess or short data David Howells
2017-02-24 13:14 ` [PATCH 07/14] afs: Kill struct afs_read::pg_offset David Howells
2017-02-24 13:14 ` [PATCH 08/14] afs: Handle a short write to an AFS page David Howells
2017-02-24 13:14 ` [PATCH 09/14] afs: Flush outstanding writes when an fd is closed David Howells
2017-02-24 13:14 ` [PATCH 10/14] afs: Distinguish mountpoints from symlinks by file mode alone David Howells
2017-02-24 13:14 ` [PATCH 11/14] afs: inode: Replace rcu_assign_pointer() with RCU_INIT_POINTER() David Howells
2017-02-24 13:14 ` [PATCH 12/14] afs: security: " David Howells
2017-02-24 13:14 ` [PATCH 13/14] afs: Migrate vlocation fields to 64-bit David Howells
2017-02-24 13:15 ` [PATCH 14/14] afs: Prevent callback expiry timer overflow David Howells

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.