static int id_to_sid(unsigned long cid, uint sidtype, struct cifs_sid *ssid) { int rc = 0; struct key *sidkey; const struct cred *saved_cred; struct cifs_sid *lsid; struct cifs_sid_id *psidid, *npsidid; struct rb_root *cidtree; spinlock_t *cidlock; if (sidtype == SIDOWNER) { cidlock = &siduidlock; cidtree = &uidtree; } else if (sidtype == SIDGROUP) { cidlock = &sidgidlock; cidtree = &gidtree; } else return -EINVAL; spin_lock(cidlock); psidid = sid_rb_search(cidtree, cid); if (!psidid) { spin_unlock(cidlock); npsidid = kzalloc(sizeof(struct cifs_sid_id), GFP_KERNEL); if (!npsidid) return -ENOMEM; npsidid->sidstr = kmalloc(SIDLEN, GFP_KERNEL); if (!npsidid->sidstr) { kfree(npsidid); return -ENOMEM; } spin_lock(cidlock); psidid = sid_rb_search(cidtree, cid); if (psidid) { ++psidid->refcount; spin_unlock(cidlock); kfree(npsidid->sidstr); kfree(npsidid); } else { psidid = npsidid; sid_rb_insert(cidtree, cid, &psidid, sidtype == SIDOWNER ? "oi:" : "gi:"); ++psidid->refcount; spin_unlock(cidlock); } } else { ++psidid->refcount; spin_unlock(cidlock); } if (test_bit(SID_ID_MAPPED, &psidid->state)) { memcpy(ssid, &psidid->sid, sizeof(struct cifs_sid)); psidid->time = jiffies; goto id_sid_out; } if (time_after(psidid->time + SID_MAP_RETRY, jiffies)) { rc = -EINVAL; goto id_sid_out; } if (!test_and_set_bit(SID_ID_PENDING, &psidid->state)) { saved_cred = override_creds(root_cred); sidkey = request_key(&cifs_idmap_key_type, psidid->sidstr, ""); if (IS_ERR(sidkey)) { rc = -EINVAL; cFYI(1, "%s: Can't map and id to a SID", __func__); } else { lsid = (struct cifs_sid *)sidkey->payload.data; memcpy(&psidid->sid, lsid, sidkey->datalen < sizeof(struct cifs_sid) ? sidkey->datalen : sizeof(struct cifs_sid)); memcpy(ssid, &psidid->sid, sidkey->datalen < sizeof(struct cifs_sid) ? sidkey->datalen : sizeof(struct cifs_sid)); set_bit(SID_ID_MAPPED, &psidid->state); key_put(sidkey); kfree(psidid->sidstr); } psidid->time = jiffies; revert_creds(saved_cred); clear_bit(SID_ID_PENDING, &psidid->state); wake_up_bit(&psidid->state, SID_ID_PENDING); } else { rc = wait_on_bit(&psidid->state, SID_ID_PENDING, sidid_pending_wait, TASK_INTERRUPTIBLE); if (rc) { cFYI(1, "%s: sidid_pending_wait interrupted %d", __func__, rc); --psidid->refcount; return rc; } if (test_bit(SID_ID_MAPPED, &psidid->state)) memcpy(ssid, &psidid->sid, sizeof(struct cifs_sid)); else rc = -EINVAL; } id_sid_out: --psidid->refcount; return rc; }
static int id_to_sid(unsigned long cid, uint sidtype, struct cifs_sid *ssid) { int rc = 0; struct key *sidkey; const struct cred *saved_cred; struct cifs_sid *lsid; struct cifs_sid_id *psidid, *npsidid; struct rb_root *cidtree; spinlock_t *cidlock; if (sidtype == SIDOWNER) { cidlock = &siduidlock; cidtree = &uidtree; } else if (sidtype == SIDGROUP) { cidlock = &sidgidlock; cidtree = &gidtree; } else return -EINVAL; spin_lock(cidlock); psidid = sid_rb_search(cidtree, cid); if (!psidid) { /* node does not exist, allocate one & attempt adding */ spin_unlock(cidlock); npsidid = kzalloc(sizeof(struct cifs_sid_id), GFP_KERNEL); if (!npsidid) return -ENOMEM; npsidid->sidstr = kmalloc(SIDLEN, GFP_KERNEL); if (!npsidid->sidstr) { kfree(npsidid); return -ENOMEM; } spin_lock(cidlock); psidid = sid_rb_search(cidtree, cid); if (psidid) { /* node happened to get inserted meanwhile */ ++psidid->refcount; spin_unlock(cidlock); kfree(npsidid->sidstr); kfree(npsidid); } else { psidid = npsidid; sid_rb_insert(cidtree, cid, &psidid, sidtype == SIDOWNER ? "oi:" : "gi:"); ++psidid->refcount; spin_unlock(cidlock); } } else { ++psidid->refcount; spin_unlock(cidlock); } /* * If we are here, it is safe to access psidid and its fields * since a reference was taken earlier while holding the spinlock. * A reference on the node is put without holding the spinlock * and it is OK to do so in this case, shrinker will not erase * this node until all references are put and we do not access * any fields of the node after a reference is put . */ if (test_bit(SID_ID_MAPPED, &psidid->state)) { memcpy(ssid, &psidid->sid, sizeof(struct cifs_sid)); psidid->time = jiffies; /* update ts for accessing */ goto id_sid_out; } if (time_after(psidid->time + SID_MAP_RETRY, jiffies)) { rc = -EINVAL; goto id_sid_out; } if (!test_and_set_bit(SID_ID_PENDING, &psidid->state)) { saved_cred = override_creds(root_cred); sidkey = request_key(&cifs_idmap_key_type, psidid->sidstr, ""); if (IS_ERR(sidkey)) { rc = -EINVAL; cFYI(1, "%s: Can't map and id to a SID", __func__); } else { lsid = (struct cifs_sid *)sidkey->payload.data; memcpy(&psidid->sid, lsid, sidkey->datalen < sizeof(struct cifs_sid) ? sidkey->datalen : sizeof(struct cifs_sid)); memcpy(ssid, &psidid->sid, sidkey->datalen < sizeof(struct cifs_sid) ? sidkey->datalen : sizeof(struct cifs_sid)); set_bit(SID_ID_MAPPED, &psidid->state); key_put(sidkey); kfree(psidid->sidstr); } psidid->time = jiffies; /* update ts for accessing */ revert_creds(saved_cred); clear_bit(SID_ID_PENDING, &psidid->state); wake_up_bit(&psidid->state, SID_ID_PENDING); } else { rc = wait_on_bit(&psidid->state, SID_ID_PENDING, sidid_pending_wait, TASK_INTERRUPTIBLE); if (rc) { cFYI(1, "%s: sidid_pending_wait interrupted %d", __func__, rc); --psidid->refcount; return rc; } if (test_bit(SID_ID_MAPPED, &psidid->state)) memcpy(ssid, &psidid->sid, sizeof(struct cifs_sid)); else rc = -EINVAL; } id_sid_out: --psidid->refcount; return rc; }