1*36af84cdSRashmica Gupta // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) 2*36af84cdSRashmica Gupta #define _GNU_SOURCE 3*36af84cdSRashmica Gupta #include "libpldm/requester/instance-id.h" 4*36af84cdSRashmica Gupta #include "libpldm/pldm.h" 5*36af84cdSRashmica Gupta #include <errno.h> 6*36af84cdSRashmica Gupta #include <fcntl.h> 7*36af84cdSRashmica Gupta #include <stdlib.h> 8*36af84cdSRashmica Gupta #include <unistd.h> 9*36af84cdSRashmica Gupta 10*36af84cdSRashmica Gupta #define PLDM_TID_MAX 256 11*36af84cdSRashmica Gupta #define PLDM_INST_ID_MAX 32 12*36af84cdSRashmica Gupta 13*36af84cdSRashmica Gupta struct pldm_instance_db { 14*36af84cdSRashmica Gupta pldm_instance_id_t prev[PLDM_TID_MAX]; 15*36af84cdSRashmica Gupta int lock_db_fd; 16*36af84cdSRashmica Gupta }; 17*36af84cdSRashmica Gupta 18*36af84cdSRashmica Gupta static inline int iid_next(pldm_instance_id_t cur) 19*36af84cdSRashmica Gupta { 20*36af84cdSRashmica Gupta return (cur + 1) % PLDM_INST_ID_MAX; 21*36af84cdSRashmica Gupta } 22*36af84cdSRashmica Gupta 23*36af84cdSRashmica Gupta int pldm_instance_db_init(struct pldm_instance_db **ctx, const char *dbpath) 24*36af84cdSRashmica Gupta { 25*36af84cdSRashmica Gupta struct pldm_instance_db *l_ctx; 26*36af84cdSRashmica Gupta 27*36af84cdSRashmica Gupta /* Make sure the provided pointer was initialised to NULL. In the future 28*36af84cdSRashmica Gupta * if we stabilise the ABI and expose the struct definition the caller 29*36af84cdSRashmica Gupta * can potentially pass a valid pointer to a struct they've allocated 30*36af84cdSRashmica Gupta */ 31*36af84cdSRashmica Gupta if (!ctx || *ctx) { 32*36af84cdSRashmica Gupta return -EINVAL; 33*36af84cdSRashmica Gupta } 34*36af84cdSRashmica Gupta 35*36af84cdSRashmica Gupta l_ctx = calloc(1, sizeof(struct pldm_instance_db)); 36*36af84cdSRashmica Gupta if (!l_ctx) { 37*36af84cdSRashmica Gupta return -ENOMEM; 38*36af84cdSRashmica Gupta } 39*36af84cdSRashmica Gupta 40*36af84cdSRashmica Gupta /* Initialise previous ID values so the next one is zero */ 41*36af84cdSRashmica Gupta for (int i = 0; i < PLDM_TID_MAX; i++) { 42*36af84cdSRashmica Gupta l_ctx->prev[i] = 31; 43*36af84cdSRashmica Gupta } 44*36af84cdSRashmica Gupta 45*36af84cdSRashmica Gupta /* Lock database may be read-only, either by permissions or mountpoint 46*36af84cdSRashmica Gupta */ 47*36af84cdSRashmica Gupta l_ctx->lock_db_fd = open(dbpath, O_RDONLY | O_CLOEXEC); 48*36af84cdSRashmica Gupta if (l_ctx->lock_db_fd < 0) { 49*36af84cdSRashmica Gupta free(l_ctx); 50*36af84cdSRashmica Gupta return -errno; 51*36af84cdSRashmica Gupta } 52*36af84cdSRashmica Gupta *ctx = l_ctx; 53*36af84cdSRashmica Gupta 54*36af84cdSRashmica Gupta return 0; 55*36af84cdSRashmica Gupta } 56*36af84cdSRashmica Gupta 57*36af84cdSRashmica Gupta int pldm_instance_db_init_default(struct pldm_instance_db **ctx) 58*36af84cdSRashmica Gupta { 59*36af84cdSRashmica Gupta return pldm_instance_db_init(ctx, 60*36af84cdSRashmica Gupta "/usr/share/libpldm/instance-db/default"); 61*36af84cdSRashmica Gupta } 62*36af84cdSRashmica Gupta 63*36af84cdSRashmica Gupta int pldm_instance_db_destroy(struct pldm_instance_db *ctx) 64*36af84cdSRashmica Gupta { 65*36af84cdSRashmica Gupta if (!ctx) { 66*36af84cdSRashmica Gupta return 0; 67*36af84cdSRashmica Gupta } 68*36af84cdSRashmica Gupta close(ctx->lock_db_fd); 69*36af84cdSRashmica Gupta free(ctx); 70*36af84cdSRashmica Gupta return 0; 71*36af84cdSRashmica Gupta } 72*36af84cdSRashmica Gupta 73*36af84cdSRashmica Gupta int pldm_instance_id_alloc(struct pldm_instance_db *ctx, pldm_tid_t tid, 74*36af84cdSRashmica Gupta pldm_instance_id_t *iid) 75*36af84cdSRashmica Gupta { 76*36af84cdSRashmica Gupta static const struct flock cfls = { 77*36af84cdSRashmica Gupta .l_type = F_RDLCK, 78*36af84cdSRashmica Gupta .l_whence = SEEK_SET, 79*36af84cdSRashmica Gupta .l_len = 1, 80*36af84cdSRashmica Gupta }; 81*36af84cdSRashmica Gupta static const struct flock cflx = { 82*36af84cdSRashmica Gupta .l_type = F_WRLCK, 83*36af84cdSRashmica Gupta .l_whence = SEEK_SET, 84*36af84cdSRashmica Gupta .l_len = 1, 85*36af84cdSRashmica Gupta }; 86*36af84cdSRashmica Gupta uint8_t l_iid; 87*36af84cdSRashmica Gupta 88*36af84cdSRashmica Gupta if (!iid) { 89*36af84cdSRashmica Gupta return -EINVAL; 90*36af84cdSRashmica Gupta } 91*36af84cdSRashmica Gupta 92*36af84cdSRashmica Gupta l_iid = ctx->prev[tid]; 93*36af84cdSRashmica Gupta if (l_iid >= PLDM_INST_ID_MAX) { 94*36af84cdSRashmica Gupta return -EPROTO; 95*36af84cdSRashmica Gupta } 96*36af84cdSRashmica Gupta 97*36af84cdSRashmica Gupta while ((l_iid = iid_next(l_iid)) != ctx->prev[tid]) { 98*36af84cdSRashmica Gupta struct flock flop; 99*36af84cdSRashmica Gupta off_t loff; 100*36af84cdSRashmica Gupta int rc; 101*36af84cdSRashmica Gupta 102*36af84cdSRashmica Gupta /* Derive the instance ID offset in the lock database */ 103*36af84cdSRashmica Gupta loff = tid * PLDM_INST_ID_MAX + l_iid; 104*36af84cdSRashmica Gupta 105*36af84cdSRashmica Gupta /* Reserving the TID's IID. Done via a shared lock */ 106*36af84cdSRashmica Gupta flop = cfls; 107*36af84cdSRashmica Gupta flop.l_start = loff; 108*36af84cdSRashmica Gupta rc = fcntl(ctx->lock_db_fd, F_OFD_SETLK, &flop); 109*36af84cdSRashmica Gupta if (rc < 0) { 110*36af84cdSRashmica Gupta if (errno == EAGAIN || errno == EINTR) { 111*36af84cdSRashmica Gupta return -EAGAIN; 112*36af84cdSRashmica Gupta } 113*36af84cdSRashmica Gupta return -EPROTO; 114*36af84cdSRashmica Gupta } 115*36af84cdSRashmica Gupta 116*36af84cdSRashmica Gupta /* 117*36af84cdSRashmica Gupta * If we *may* promote the lock to exclusive then this IID is 118*36af84cdSRashmica Gupta * only reserved by us. This is now our allocated IID. 119*36af84cdSRashmica Gupta * 120*36af84cdSRashmica Gupta * If we *may not* promote the lock to exclusive then this IID 121*36af84cdSRashmica Gupta * is also reserved on another file descriptor. Move on to the 122*36af84cdSRashmica Gupta * next IID index. 123*36af84cdSRashmica Gupta * 124*36af84cdSRashmica Gupta * Note that we cannot actually *perform* the promotion in 125*36af84cdSRashmica Gupta * practice because this is prevented by the lock database being 126*36af84cdSRashmica Gupta * opened O_RDONLY. 127*36af84cdSRashmica Gupta */ 128*36af84cdSRashmica Gupta flop = cflx; 129*36af84cdSRashmica Gupta flop.l_start = loff; 130*36af84cdSRashmica Gupta rc = fcntl(ctx->lock_db_fd, F_OFD_GETLK, &flop); 131*36af84cdSRashmica Gupta if (rc < 0) { 132*36af84cdSRashmica Gupta if (errno == EAGAIN || errno == EINTR) { 133*36af84cdSRashmica Gupta return -EAGAIN; 134*36af84cdSRashmica Gupta } 135*36af84cdSRashmica Gupta return -EPROTO; 136*36af84cdSRashmica Gupta } 137*36af84cdSRashmica Gupta 138*36af84cdSRashmica Gupta /* F_UNLCK is the type of the lock if we could successfully 139*36af84cdSRashmica Gupta * promote it to F_WRLCK */ 140*36af84cdSRashmica Gupta if (flop.l_type == F_UNLCK) { 141*36af84cdSRashmica Gupta ctx->prev[tid] = l_iid; 142*36af84cdSRashmica Gupta *iid = l_iid; 143*36af84cdSRashmica Gupta return 0; 144*36af84cdSRashmica Gupta } 145*36af84cdSRashmica Gupta if (flop.l_type != F_RDLCK) { 146*36af84cdSRashmica Gupta return -EPROTO; 147*36af84cdSRashmica Gupta } 148*36af84cdSRashmica Gupta } 149*36af84cdSRashmica Gupta 150*36af84cdSRashmica Gupta /* Failed to allocate an IID after a full loop. Make the caller try 151*36af84cdSRashmica Gupta * again */ 152*36af84cdSRashmica Gupta return -EAGAIN; 153*36af84cdSRashmica Gupta } 154*36af84cdSRashmica Gupta 155*36af84cdSRashmica Gupta int pldm_instance_id_free(struct pldm_instance_db *ctx, pldm_tid_t tid, 156*36af84cdSRashmica Gupta pldm_instance_id_t iid) 157*36af84cdSRashmica Gupta { 158*36af84cdSRashmica Gupta static const struct flock cflu = { 159*36af84cdSRashmica Gupta .l_type = F_UNLCK, 160*36af84cdSRashmica Gupta .l_whence = SEEK_SET, 161*36af84cdSRashmica Gupta .l_len = 1, 162*36af84cdSRashmica Gupta }; 163*36af84cdSRashmica Gupta struct flock flop; 164*36af84cdSRashmica Gupta int rc; 165*36af84cdSRashmica Gupta 166*36af84cdSRashmica Gupta flop = cflu; 167*36af84cdSRashmica Gupta flop.l_start = tid * PLDM_INST_ID_MAX + iid; 168*36af84cdSRashmica Gupta rc = fcntl(ctx->lock_db_fd, F_OFD_SETLK, &flop); 169*36af84cdSRashmica Gupta if (rc < 0) { 170*36af84cdSRashmica Gupta if (errno == EAGAIN || errno == EINTR) { 171*36af84cdSRashmica Gupta return -EAGAIN; 172*36af84cdSRashmica Gupta } 173*36af84cdSRashmica Gupta return -EPROTO; 174*36af84cdSRashmica Gupta } 175*36af84cdSRashmica Gupta 176*36af84cdSRashmica Gupta return 0; 177*36af84cdSRashmica Gupta } 178