From patchwork Fri Apr 19 10:54:08 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Filipe Manana X-Patchwork-Id: 10909403 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 3DE4E922 for ; Fri, 19 Apr 2019 18:33:30 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 3352C28C6D for ; Fri, 19 Apr 2019 18:33:30 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 2717728D9E; Fri, 19 Apr 2019 18:33:30 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 5ADBF28C6D for ; Fri, 19 Apr 2019 18:33:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728034AbfDSSdW (ORCPT ); Fri, 19 Apr 2019 14:33:22 -0400 Received: from mail.kernel.org ([198.145.29.99]:53894 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727590AbfDSS3Q (ORCPT ); Fri, 19 Apr 2019 14:29:16 -0400 Received: from localhost.localdomain (bl8-197-74.dsl.telepac.pt [85.241.197.74]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 78F2D21900; Fri, 19 Apr 2019 10:54:13 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1555671254; bh=o74CXUPN/VaDtIkLGsVYZ6wO4z9lqKVGvmM5V7gHnaE=; h=From:To:Cc:Subject:Date:From; b=OwOu1prsm7scshfHSdB5esoJDRXu2jdK0vVktIyBXgSdCZ1Qfj7I0WZNoo45e6WwH PAToWjVHhqNjjOqZyu61Ar68kS3Y03oDsQ3AdNUO6dd5pLkWyZ7nM5lFka3SGKMBBZ ET+m8J2Gk9cua4X2EFxMjZkWV0W5WMa1AVUq1j8c= From: fdmanana@kernel.org To: fstests@vger.kernel.org Cc: linux-btrfs@vger.kernel.org, Filipe Manana Subject: [PATCH v4 3/7] fsstress: add operation for setting xattrs on files and directories Date: Fri, 19 Apr 2019 11:54:08 +0100 Message-Id: <20190419105408.11883-1-fdmanana@kernel.org> X-Mailer: git-send-email 2.11.0 Sender: fstests-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: fstests@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Filipe Manana Currently fsstress does not exercise creating, reading or deleting xattrs on files or directories. This change adds support for setting xattrs on files and directories, using only the xattr user namespace (the other namespaces are not general purpose and are used for security, capabilities, ACLs, etc). This adds a counter for each file entry structure that keeps track of the number of xattrs set for the file entry, and each new xattr has a name that includes the counter's value (example: "user.x4"). Values for the xattrs have at most 100 bytes, which is more than the maximum size supported for all major filesystems. Signed-off-by: Filipe Manana --- V2: Use a different name for the operation (setfattr instead of the already taken setxattr) and make use of the helper functions for opening and closing files or directories, introduced in the first patch of this series. V3: Simplified implementation to not need to open a file descriptor and use a path string instead. V4: Addressed Eryu's comments. ltp/fsstress.c | 154 +++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 145 insertions(+), 9 deletions(-) diff --git a/ltp/fsstress.c b/ltp/fsstress.c index 3ec19143..b3ff8d92 100644 --- a/ltp/fsstress.c +++ b/ltp/fsstress.c @@ -27,6 +27,7 @@ io_context_t io_ctx; #endif #include +#include #ifndef FS_IOC_GETFLAGS #define FS_IOC_GETFLAGS _IOR('f', 1, long) @@ -84,6 +85,7 @@ typedef enum { OP_RESVSP, OP_RMDIR, OP_SETATTR, + OP_SETFATTR, OP_SETXATTR, OP_SPLICE, OP_STAT, @@ -110,6 +112,7 @@ typedef struct opdesc { typedef struct fent { int id; int parent; + int xattr_counter; } fent_t; typedef struct flist { @@ -156,6 +159,8 @@ struct print_string { #define MAXFSIZE ((1ULL << 63) - 1ULL) #define MAXFSIZE32 ((1ULL << 40) - 1ULL) +#define XATTR_NAME_BUF_SIZE 18 + void afsync_f(int, long); void allocsp_f(int, long); void aread_f(int, long); @@ -176,6 +181,7 @@ void fdatasync_f(int, long); void fiemap_f(int, long); void freesp_f(int, long); void fsync_f(int, long); +char *gen_random_string(int); void getattr_f(int, long); void getdents_f(int, long); void link_f(int, long); @@ -194,6 +200,7 @@ void rename_f(int, long); void resvsp_f(int, long); void rmdir_f(int, long); void setattr_f(int, long); +void setfattr_f(int, long); void setxattr_f(int, long); void splice_f(int, long); void stat_f(int, long); @@ -204,6 +211,7 @@ void unlink_f(int, long); void unresvsp_f(int, long); void write_f(int, long); void writev_f(int, long); +char *xattr_flag_to_string(int); opdesc_t ops[] = { /* { OP_ENUM, "name", function, freq, iswrite }, */ @@ -244,7 +252,11 @@ opdesc_t ops[] = { { OP_RENAME, "rename", rename_f, 2, 1 }, { OP_RESVSP, "resvsp", resvsp_f, 1, 1 }, { OP_RMDIR, "rmdir", rmdir_f, 1, 1 }, + /* set attribute flag (FS_IOC_SETFLAGS ioctl) */ { OP_SETATTR, "setattr", setattr_f, 0, 1 }, + /* set extended attribute */ + { OP_SETFATTR, "setfattr", setfattr_f, 2, 1 }, + /* set project id (XFS_IOC_FSSETXATTR ioctl) */ { OP_SETXATTR, "setxattr", setxattr_f, 1, 1 }, { OP_SPLICE, "splice", splice_f, 1, 1 }, { OP_STAT, "stat", stat_f, 1, 0 }, @@ -296,7 +308,7 @@ char *execute_cmd = NULL; int execute_freq = 1; struct print_string flag_str = {0}; -void add_to_flist(int, int, int); +void add_to_flist(int, int, int, int); void append_pathname(pathname_t *, char *); int attr_list_path(pathname_t *, char *, const int, int, attrlist_cursor_t *); int attr_remove_path(pathname_t *, const char *, int); @@ -315,6 +327,7 @@ int fent_to_name(pathname_t *, flist_t *, fent_t *); void fix_parent(int, int); void free_pathname(pathname_t *); int generate_fname(fent_t *, int, pathname_t *, int *, int *); +int generate_xattr_name(int, char *, int); int get_fname(int, long, pathname_t *, flist_t **, fent_t **, int *); void init_pathname(pathname_t *); int lchown_path(pathname_t *, uid_t, gid_t); @@ -716,7 +729,7 @@ translate_flags(int flags, const char *delim, } void -add_to_flist(int ft, int id, int parent) +add_to_flist(int ft, int id, int parent, int xattr_counter) { fent_t *fep; flist_t *ftp; @@ -729,6 +742,7 @@ add_to_flist(int ft, int id, int parent) fep = &ftp->fents[ftp->nfiles++]; fep->id = id; fep->parent = parent; + fep->xattr_counter = xattr_counter; } void @@ -1122,6 +1136,18 @@ generate_fname(fent_t *fep, int ft, pathname_t *name, int *idp, int *v) return 1; } +int generate_xattr_name(int xattr_num, char *buffer, int buflen) +{ + int ret; + + ret = snprintf(buffer, buflen, "user.x%d", xattr_num); + if (ret < 0) + return ret; + if (ret < buflen) + return 0; + return -EOVERFLOW; +} + /* * Get file * Input: "which" to choose the file-types eg. non-directory @@ -3030,7 +3056,7 @@ creat_f(int opno, long r) if (xfsctl(f.path, fd, XFS_IOC_FSSETXATTR, &a) < 0) e1 = errno; } - add_to_flist(type, id, parid); + add_to_flist(type, id, parid, 0); close(fd); } if (v) { @@ -3495,6 +3521,28 @@ fsync_f(int opno, long r) close(fd); } +char * +gen_random_string(int len) +{ + static const char charset[] = "0123456789" + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + int i; + char *s; + + if (len == 0) + return NULL; + + s = malloc(len); + if (!s) + return NULL; + + for (i = 0; i < len; i++) + s[i] = charset[random() % sizeof(charset)]; + + return s; +} + void getattr_f(int opno, long r) { @@ -3551,6 +3599,7 @@ link_f(int opno, long r) int e; pathname_t f; fent_t *fep; + fent_t *fep_src; flist_t *flp; int id; pathname_t l; @@ -3559,7 +3608,7 @@ link_f(int opno, long r) int v1; init_pathname(&f); - if (!get_fname(FT_NOTDIR, r, &f, &flp, NULL, &v1)) { + if (!get_fname(FT_NOTDIR, r, &f, &flp, &fep_src, &v1)) { if (v1) printf("%d/%d: link - no file\n", procid, opno); free_pathname(&f); @@ -3586,7 +3635,7 @@ link_f(int opno, long r) e = link_path(&f, &l) < 0 ? errno : 0; check_cwd(); if (e == 0) - add_to_flist(flp - flist, id, parid); + add_to_flist(flp - flist, id, parid, fep_src->xattr_counter); if (v) { printf("%d/%d: link %s %s %d\n", procid, opno, f.path, l.path, e); @@ -3626,7 +3675,7 @@ mkdir_f(int opno, long r) e = mkdir_path(&f, 0777) < 0 ? errno : 0; check_cwd(); if (e == 0) - add_to_flist(FT_DIR, id, parid); + add_to_flist(FT_DIR, id, parid, 0); if (v) { printf("%d/%d: mkdir %s %d\n", procid, opno, f.path, e); printf("%d/%d: mkdir add id=%d,parent=%d\n", procid, opno, id, parid); @@ -3664,7 +3713,7 @@ mknod_f(int opno, long r) e = mknod_path(&f, S_IFCHR|0444, 0) < 0 ? errno : 0; check_cwd(); if (e == 0) - add_to_flist(FT_DEV, id, parid); + add_to_flist(FT_DEV, id, parid, 0); if (v) { printf("%d/%d: mknod %s %d\n", procid, opno, f.path, e); printf("%d/%d: mknod add id=%d,parent=%d\n", procid, opno, id, parid); @@ -4040,12 +4089,14 @@ rename_f(int opno, long r) e = rename_path(&f, &newf) < 0 ? errno : 0; check_cwd(); if (e == 0) { + int xattr_counter = fep->xattr_counter; + if (flp - flist == FT_DIR) { oldid = fep->id; fix_parent(oldid, id); } del_from_flist(flp - flist, fep - flp->fents); - add_to_flist(flp - flist, id, parid); + add_to_flist(flp - flist, id, parid, xattr_counter); } if (v) { printf("%d/%d: rename %s to %s %d\n", procid, opno, f.path, @@ -4168,6 +4219,81 @@ setattr_f(int opno, long r) } void +setfattr_f(int opno, long r) +{ + int e; + pathname_t f; + fent_t *fep; + int v; + int value_len; + char name[XATTR_NAME_BUF_SIZE]; + char *value = NULL; + int flag = 0; + int xattr_num; + + init_pathname(&f); + if (!get_fname(FT_REGFILE | FT_DIRm, r, &f, NULL, &fep, &v)) { + if (v) + printf("%d/%d: setfattr - no filename\n", procid, opno); + goto out; + } + check_cwd(); + + if ((fep->xattr_counter > 0) && (random() % 2)) { + /* + * Use an existing xattr name for replacing its value or + * create again a xattr that was previously deleted. + */ + xattr_num = (random() % fep->xattr_counter) + 1; + if (random() % 2) + flag = XATTR_REPLACE; + } else { + /* Use a new xattr name. */ + xattr_num = fep->xattr_counter + 1; + /* + * Don't always use the create flag because even if our xattr + * counter is 0, we may still have xattrs associated to this + * file (this happens when xattrs are added to a file through + * one of its other hard links), so we can end up updating an + * existing xattr too. + */ + if (random() % 2) + flag = XATTR_CREATE; + } + + /* + * The maximum supported value size depends on the filesystem + * implementation, but 100 bytes is a safe value for most filesystems + * at least. + */ + value_len = random() % 101; + value = gen_random_string(value_len); + if (!value && value_len > 0) { + if (v) + printf("%d/%d: setfattr - file %s failed to allocate value with %d bytes\n", + procid, opno, f.path, value_len); + goto out; + } + e = generate_xattr_name(xattr_num, name, sizeof(name)); + if (e < 0) { + printf("%d/%d: setfattr - file %s failed to generate xattr name: %d\n", + procid, opno, f.path, e); + goto out; + } + + e = setxattr(f.path, name, value, value_len, flag) < 0 ? errno : 0; + if (e == 0) + fep->xattr_counter++; + if (v) + printf("%d/%d: setfattr file %s name %s flag %s value length %d: %d\n", + procid, opno, f.path, name, xattr_flag_to_string(flag), + value_len, e); +out: + free(value); + free_pathname(&f); +} + +void stat_f(int opno, long r) { int e; @@ -4229,7 +4355,7 @@ symlink_f(int opno, long r) e = symlink_path(val, &f) < 0 ? errno : 0; check_cwd(); if (e == 0) - add_to_flist(FT_SYM, id, parid); + add_to_flist(FT_SYM, id, parid, 0); free(val); if (v) { printf("%d/%d: symlink %s %d\n", procid, opno, f.path, e); @@ -4498,3 +4624,13 @@ writev_f(int opno, long r) free_pathname(&f); close(fd); } + +char * +xattr_flag_to_string(int flag) +{ + if (flag == XATTR_CREATE) + return "create"; + if (flag == XATTR_REPLACE) + return "replace"; + return "none"; +}