#include "sdfat.h" #define SDFAT_VF_CLUS_MAX 7 /* 512 Byte ~ 32 KByte */ #define SDFAT_EF_CLUS_MAX 17 /* 512 Byte ~ 32 MByte */ enum { SDFAT_MNT_FAT12, SDFAT_MNT_FAT16, SDFAT_MNT_FAT32, SDFAT_MNT_EXFAT, SDFAT_MNT_RO, SDFAT_MNT_MAX }; enum { SDFAT_OP_EXFAT_MNT, SDFAT_OP_MKDIR, SDFAT_OP_CREATE, SDFAT_OP_READ, SDFAT_OP_WRITE, SDFAT_OP_TRUNC, SDFAT_OP_MAX }; enum { SDFAT_VOL_4G, SDFAT_VOL_8G, SDFAT_VOL_16G, SDFAT_VOL_32G, SDFAT_VOL_64G, SDFAT_VOL_128G, SDFAT_VOL_256G, SDFAT_VOL_512G, SDFAT_VOL_XTB, SDFAT_VOL_MAX }; static struct sdfat_statistics { u32 clus_vfat[SDFAT_VF_CLUS_MAX]; u32 clus_exfat[SDFAT_EF_CLUS_MAX]; u32 mnt_cnt[SDFAT_MNT_MAX]; u32 nofat_op[SDFAT_OP_MAX]; u32 vol_size[SDFAT_VOL_MAX]; } statistics; static struct kset *sdfat_statistics_kset; static ssize_t vfat_cl_show(struct kobject *kobj, struct kobj_attribute *attr, char *buff) { return snprintf(buff, PAGE_SIZE, "\"VCL_512B_I\":\"%u\"," "\"VCL_1K_I\":\"%u\",\"VCL_2K_I\":\"%u\"," "\"VCL_4K_I\":\"%u\",\"VCL_8K_I\":\"%u\"," "\"VCL_16K_I\":\"%u\",\"VCL_32K_I\":\"%u\"\n", statistics.clus_vfat[0], statistics.clus_vfat[1], statistics.clus_vfat[2], statistics.clus_vfat[3], statistics.clus_vfat[4], statistics.clus_vfat[5], statistics.clus_vfat[6]); } static ssize_t exfat_cl_show(struct kobject *kobj, struct kobj_attribute *attr, char *buff) { return snprintf(buff, PAGE_SIZE, "\"ECL_512B_I\":\"%u\"," "\"ECL_1K_I\":\"%u\",\"ECL_2K_I\":\"%u\"," "\"ECL_4K_I\":\"%u\",\"ECL_8K_I\":\"%u\"," "\"ECL_16K_I\":\"%u\",\"ECL_32K_I\":\"%u\"," "\"ECL_64K_I\":\"%u\",\"ECL_128K_I\":\"%u\"," "\"ECL_256K_I\":\"%u\",\"ECL_512K_I\":\"%u\"," "\"ECL_1M_I\":\"%u\",\"ECL_2M_I\":\"%u\"," "\"ECL_4M_I\":\"%u\",\"ECL_8M_I\":\"%u\"," "\"ECL_16M_I\":\"%u\",\"ECL_32M_I\":\"%u\"\n", statistics.clus_exfat[0], statistics.clus_exfat[1], statistics.clus_exfat[2], statistics.clus_exfat[3], statistics.clus_exfat[4], statistics.clus_exfat[5], statistics.clus_exfat[6], statistics.clus_exfat[7], statistics.clus_exfat[8], statistics.clus_exfat[9], statistics.clus_exfat[10], statistics.clus_exfat[11], statistics.clus_exfat[12], statistics.clus_exfat[13], statistics.clus_exfat[14], statistics.clus_exfat[15], statistics.clus_exfat[16]); } static ssize_t mount_show(struct kobject *kobj, struct kobj_attribute *attr, char *buff) { return snprintf(buff, PAGE_SIZE, "\"FAT12_MNT_I\":\"%u\"," "\"FAT16_MNT_I\":\"%u\",\"FAT32_MNT_I\":\"%u\"," "\"EXFAT_MNT_I\":\"%u\",\"RO_MNT_I\":\"%u\"\n", statistics.mnt_cnt[SDFAT_MNT_FAT12], statistics.mnt_cnt[SDFAT_MNT_FAT16], statistics.mnt_cnt[SDFAT_MNT_FAT32], statistics.mnt_cnt[SDFAT_MNT_EXFAT], statistics.mnt_cnt[SDFAT_MNT_RO]); } static ssize_t nofat_op_show(struct kobject *kobj, struct kobj_attribute *attr, char *buff) { return snprintf(buff, PAGE_SIZE, "\"NOFAT_MOUNT_I\":\"%u\"," "\"NOFAT_MKDIR_I\":\"%u\",\"NOFAT_CREATE_I\":\"%u\"," "\"NOFAT_READ_I\":\"%u\",\"NOFAT_WRITE_I\":\"%u\"," "\"NOFAT_TRUNC_I\":\"%u\"\n", statistics.nofat_op[SDFAT_OP_EXFAT_MNT], statistics.nofat_op[SDFAT_OP_MKDIR], statistics.nofat_op[SDFAT_OP_CREATE], statistics.nofat_op[SDFAT_OP_READ], statistics.nofat_op[SDFAT_OP_WRITE], statistics.nofat_op[SDFAT_OP_TRUNC]); } static ssize_t vol_size_show(struct kobject *kobj, struct kobj_attribute *attr, char *buff) { return snprintf(buff, PAGE_SIZE, "\"VOL_4G_I\":\"%u\"," "\"VOL_8G_I\":\"%u\",\"VOL_16G_I\":\"%u\"," "\"VOL_32G_I\":\"%u\",\"VOL_64G_I\":\"%u\"," "\"VOL_128G_I\":\"%u\",\"VOL_256G_I\":\"%u\"," "\"VOL_512G_I\":\"%u\",\"VOL_XTB_I\":\"%u\"\n", statistics.vol_size[SDFAT_VOL_4G], statistics.vol_size[SDFAT_VOL_8G], statistics.vol_size[SDFAT_VOL_16G], statistics.vol_size[SDFAT_VOL_32G], statistics.vol_size[SDFAT_VOL_64G], statistics.vol_size[SDFAT_VOL_128G], statistics.vol_size[SDFAT_VOL_256G], statistics.vol_size[SDFAT_VOL_512G], statistics.vol_size[SDFAT_VOL_XTB]); } static struct kobj_attribute vfat_cl_attr = __ATTR_RO(vfat_cl); static struct kobj_attribute exfat_cl_attr = __ATTR_RO(exfat_cl); static struct kobj_attribute mount_attr = __ATTR_RO(mount); static struct kobj_attribute nofat_op_attr = __ATTR_RO(nofat_op); static struct kobj_attribute vol_size_attr = __ATTR_RO(vol_size); static struct attribute *attributes_statistics[] = { &vfat_cl_attr.attr, &exfat_cl_attr.attr, &mount_attr.attr, &nofat_op_attr.attr, &vol_size_attr.attr, NULL, }; static struct attribute_group attr_group_statistics = { .attrs = attributes_statistics, }; int sdfat_statistics_init(struct kset *sdfat_kset) { int err; sdfat_statistics_kset = kset_create_and_add("statistics", NULL, &sdfat_kset->kobj); if (!sdfat_statistics_kset) { pr_err("[SDFAT] failed to create sdfat statistics kobj\n"); return -ENOMEM; } err = sysfs_create_group(&sdfat_statistics_kset->kobj, &attr_group_statistics); if (err) { pr_err("[SDFAT] failed to create sdfat statistics attributes\n"); kset_unregister(sdfat_statistics_kset); sdfat_statistics_kset = NULL; return err; } return 0; } void sdfat_statistics_uninit(void) { if (sdfat_statistics_kset) { sysfs_remove_group(&sdfat_statistics_kset->kobj, &attr_group_statistics); kset_unregister(sdfat_statistics_kset); sdfat_statistics_kset = NULL; } memset(&statistics, 0, sizeof(struct sdfat_statistics)); } void sdfat_statistics_set_mnt(FS_INFO_T *fsi) { if (fsi->vol_type == EXFAT) { statistics.mnt_cnt[SDFAT_MNT_EXFAT]++; statistics.nofat_op[SDFAT_OP_EXFAT_MNT] = 1; if (fsi->sect_per_clus_bits < SDFAT_EF_CLUS_MAX) statistics.clus_exfat[fsi->sect_per_clus_bits]++; else statistics.clus_exfat[SDFAT_EF_CLUS_MAX - 1]++; return; } if (fsi->vol_type == FAT32) statistics.mnt_cnt[SDFAT_MNT_FAT32]++; else if (fsi->vol_type == FAT16) statistics.mnt_cnt[SDFAT_MNT_FAT16]++; else if (fsi->vol_type == FAT12) statistics.mnt_cnt[SDFAT_MNT_FAT12]++; if (fsi->sect_per_clus_bits < SDFAT_VF_CLUS_MAX) statistics.clus_vfat[fsi->sect_per_clus_bits]++; else statistics.clus_vfat[SDFAT_VF_CLUS_MAX - 1]++; } void sdfat_statistics_set_mnt_ro(void) { statistics.mnt_cnt[SDFAT_MNT_RO]++; } void sdfat_statistics_set_mkdir(u8 flags) { if (flags != 0x03) return; statistics.nofat_op[SDFAT_OP_MKDIR] = 1; } void sdfat_statistics_set_create(u8 flags) { if (flags != 0x03) return; statistics.nofat_op[SDFAT_OP_CREATE] = 1; } /* flags : file or dir flgas, 0x03 means no fat-chain. * clu_offset : file or dir logical cluster offset * create : BMAP_ADD_CLUSTER or not * * File or dir have BMAP_ADD_CLUSTER is no fat-chain write * when they have 0x03 flag and two or more clusters. * And don`t have BMAP_ADD_CLUSTER is no fat-chain read * when above same condition. */ void sdfat_statistics_set_rw(u8 flags, u32 clu_offset, s32 create) { if ((flags == 0x03) && (clu_offset > 1)) { if (create) statistics.nofat_op[SDFAT_OP_WRITE] = 1; else statistics.nofat_op[SDFAT_OP_READ] = 1; } } /* flags : file or dir flgas, 0x03 means no fat-chain. * clu : cluster chain * * Set no fat-chain trunc when file or dir have 0x03 flag * and two or more clusters. */ void sdfat_statistics_set_trunc(u8 flags, CHAIN_T *clu) { if ((flags == 0x03) && (clu->size > 1)) statistics.nofat_op[SDFAT_OP_TRUNC] = 1; } void sdfat_statistics_set_vol_size(struct super_block *sb) { u64 vol_size; FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); vol_size = (u64)fsi->num_sectors << sb->s_blocksize_bits; if (vol_size <= ((u64)1 << 32)) statistics.vol_size[SDFAT_VOL_4G]++; else if (vol_size <= ((u64)1 << 33)) statistics.vol_size[SDFAT_VOL_8G]++; else if (vol_size <= ((u64)1 << 34)) statistics.vol_size[SDFAT_VOL_16G]++; else if (vol_size <= ((u64)1 << 35)) statistics.vol_size[SDFAT_VOL_32G]++; else if (vol_size <= ((u64)1 << 36)) statistics.vol_size[SDFAT_VOL_64G]++; else if (vol_size <= ((u64)1 << 37)) statistics.vol_size[SDFAT_VOL_128G]++; else if (vol_size <= ((u64)1 << 38)) statistics.vol_size[SDFAT_VOL_256G]++; else if (vol_size <= ((u64)1 << 39)) statistics.vol_size[SDFAT_VOL_512G]++; else statistics.vol_size[SDFAT_VOL_XTB]++; }