16c00db4bb
Pull AFS fixes from David Howells: "Here's a set of patches that fix a number of bugs in the in-kernel AFS client, including: - Fix directory locking to not use individual page locks for directory reading/scanning but rather to use a semaphore on the afs_vnode struct as the directory contents must be read in a single blob and data from different reads must not be mixed as the entire contents may be shuffled about between reads. - Fix address list parsing to handle port specifiers correctly. - Only give up callback records on a server if we actually talked to that server (we might not be able to access a server). - Fix some callback handling bugs, including refcounting, whole-volume callbacks and when callbacks actually get broken in response to a CB.CallBack op. - Fix some server/address rotation bugs, including giving up if we can't probe a server; giving up if a server says it doesn't have a volume, but there are more servers to try. - Fix the decoding of fetched statuses to be OpenAFS compatible. - Fix the handling of server lookups in Cache Manager ops (such as CB.InitCallBackState3) to use a UUID if possible and to handle no server being found. - Fix a bug in server lookup where not all addresses are compared. - Fix the non-encryption of calls that prevents some servers from being accessed (this also requires an AF_RXRPC patch that has already gone in through the net tree). There's also a patch that adds tracepoints to log Cache Manager ops that don't find a matching server, either by UUID or by address" * tag 'afs-fixes-20180514' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs: afs: Fix the non-encryption of calls afs: Fix CB.CallBack handling afs: Fix whole-volume callback handling afs: Fix afs_find_server search loop afs: Fix the handling of an unfound server in CM operations afs: Add a tracepoint to record callbacks from unlisted servers afs: Fix the handling of CB.InitCallBackState3 to find the server by UUID afs: Fix VNOVOL handling in address rotation afs: Fix AFSFetchStatus decoder to provide OpenAFS compatibility afs: Fix server rotation's handling of fileserver probe failure afs: Fix refcounting in callback registration afs: Fix giving up callbacks on server destruction afs: Fix address list parsing afs: Fix directory page locking
162 lines
3.9 KiB
C
162 lines
3.9 KiB
C
/* Parse JSON files using the JSMN parser. */
|
|
|
|
/*
|
|
* Copyright (c) 2014, Intel Corporation
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright notice,
|
|
* this list of conditions and the following disclaimer.
|
|
*
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
|
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
#include <unistd.h>
|
|
#include "jsmn.h"
|
|
#include "json.h"
|
|
#include <linux/kernel.h>
|
|
|
|
|
|
static char *mapfile(const char *fn, size_t *size)
|
|
{
|
|
unsigned ps = sysconf(_SC_PAGESIZE);
|
|
struct stat st;
|
|
char *map = NULL;
|
|
int err;
|
|
int fd = open(fn, O_RDONLY);
|
|
|
|
if (fd < 0 && verbose > 0 && fn) {
|
|
pr_err("Error opening events file '%s': %s\n", fn,
|
|
strerror(errno));
|
|
}
|
|
|
|
if (fd < 0)
|
|
return NULL;
|
|
err = fstat(fd, &st);
|
|
if (err < 0)
|
|
goto out;
|
|
*size = st.st_size;
|
|
map = mmap(NULL,
|
|
(st.st_size + ps - 1) & ~(ps - 1),
|
|
PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
|
|
if (map == MAP_FAILED)
|
|
map = NULL;
|
|
out:
|
|
close(fd);
|
|
return map;
|
|
}
|
|
|
|
static void unmapfile(char *map, size_t size)
|
|
{
|
|
unsigned ps = sysconf(_SC_PAGESIZE);
|
|
munmap(map, roundup(size, ps));
|
|
}
|
|
|
|
/*
|
|
* Parse json file using jsmn. Return array of tokens,
|
|
* and mapped file. Caller needs to free array.
|
|
*/
|
|
jsmntok_t *parse_json(const char *fn, char **map, size_t *size, int *len)
|
|
{
|
|
jsmn_parser parser;
|
|
jsmntok_t *tokens;
|
|
jsmnerr_t res;
|
|
unsigned sz;
|
|
|
|
*map = mapfile(fn, size);
|
|
if (!*map)
|
|
return NULL;
|
|
/* Heuristic */
|
|
sz = *size * 16;
|
|
tokens = malloc(sz);
|
|
if (!tokens)
|
|
goto error;
|
|
jsmn_init(&parser);
|
|
res = jsmn_parse(&parser, *map, *size, tokens,
|
|
sz / sizeof(jsmntok_t));
|
|
if (res != JSMN_SUCCESS) {
|
|
pr_err("%s: json error %s\n", fn, jsmn_strerror(res));
|
|
goto error_free;
|
|
}
|
|
if (len)
|
|
*len = parser.toknext;
|
|
return tokens;
|
|
error_free:
|
|
free(tokens);
|
|
error:
|
|
unmapfile(*map, *size);
|
|
return NULL;
|
|
}
|
|
|
|
void free_json(char *map, size_t size, jsmntok_t *tokens)
|
|
{
|
|
free(tokens);
|
|
unmapfile(map, size);
|
|
}
|
|
|
|
static int countchar(char *map, char c, int end)
|
|
{
|
|
int i;
|
|
int count = 0;
|
|
for (i = 0; i < end; i++)
|
|
if (map[i] == c)
|
|
count++;
|
|
return count;
|
|
}
|
|
|
|
/* Return line number of a jsmn token */
|
|
int json_line(char *map, jsmntok_t *t)
|
|
{
|
|
return countchar(map, '\n', t->start) + 1;
|
|
}
|
|
|
|
static const char * const jsmn_types[] = {
|
|
[JSMN_PRIMITIVE] = "primitive",
|
|
[JSMN_ARRAY] = "array",
|
|
[JSMN_OBJECT] = "object",
|
|
[JSMN_STRING] = "string"
|
|
};
|
|
|
|
#define LOOKUP(a, i) ((i) < (sizeof(a)/sizeof(*(a))) ? ((a)[i]) : "?")
|
|
|
|
/* Return type name of a jsmn token */
|
|
const char *json_name(jsmntok_t *t)
|
|
{
|
|
return LOOKUP(jsmn_types, t->type);
|
|
}
|
|
|
|
int json_len(jsmntok_t *t)
|
|
{
|
|
return t->end - t->start;
|
|
}
|
|
|
|
/* Is string t equal to s? */
|
|
int json_streq(char *map, jsmntok_t *t, const char *s)
|
|
{
|
|
unsigned len = json_len(t);
|
|
return len == strlen(s) && !strncasecmp(map + t->start, s, len);
|
|
}
|