h2_task *h2_task_create(conn_rec *slave, int stream_id,
                        const h2_request *req, h2_mplx *m,
                        h2_bucket_beam *input,
                        apr_interval_time_t timeout,
                        apr_size_t output_max_mem)
{
    apr_pool_t *pool;
    h2_task *task;

    ap_assert(slave);
    ap_assert(req);

    apr_pool_create(&pool, slave->pool);
    apr_pool_tag(pool, "h2_task");
    task = apr_pcalloc(pool, sizeof(h2_task));
    if (task == NULL) {
        return NULL;
    }
    task->id          = "000";
    task->stream_id   = stream_id;
    task->c           = slave;
    task->mplx        = m;
    task->pool        = pool;
    task->request     = req;
    task->timeout     = timeout;
    task->input.beam  = input;
    task->output.max_buffer = output_max_mem;

    return task;
}


static apr_status_t mplx_be_annoyed(h2_mplx *m)
{
    apr_status_t status = APR_SUCCESS;
    apr_time_t now;

    ++m->irritations_since;
    now = apr_time_now();
    if (m->limit_active > 2 &&
        ((now - m->last_mood_change >= m->mood_update_interval)
         || (m->irritations_since >= m->limit_active))) {

        if (m->limit_active > 16) {
            m->limit_active = 16;
        }
        else if (m->limit_active > 8) {
            m->limit_active = 8;
        }
        else if (m->limit_active > 4) {
            m->limit_active = 4;
        }
        else if (m->limit_active > 2) {
            m->limit_active = 2;
        }
        m->last_mood_change = now;
        m->irritations_since = 0;
        ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, m->c,
                      "h2_mplx(%ld): mood update, decreasing worker limit to %d",
                      m->id, m->limit_active);
    }

    if (m->tasks_active > m->limit_active) {
        status = unschedule_slow_tasks(m);
    }
    return status;
}


apr_status_t h2_proxy_session_process(h2_proxy_session *session)
{
    apr_status_t status;
    int have_written = 0, have_read = 0;

    ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, session->c,
                  "h2_proxy_session(%s): process", session->id);

run_loop:
    switch (session->state) {
        case H2_PROXYS_ST_INIT:
            status = session_start(session);
            if (status == APR_SUCCESS) {
                dispatch_event(session, H2_PROXYS_EV_INIT, 0, NULL);
                goto run_loop;
            }
            else {
                dispatch_event(session, H2_PROXYS_EV_CONN_ERROR, status, NULL);
            }
            break;

        case H2_PROXYS_ST_BUSY:
        case H2_PROXYS_ST_LOCAL_SHUTDOWN:
        case H2_PROXYS_ST_REMOTE_SHUTDOWN:
            have_written = send_loop(session);

            if (nghttp2_session_want_read(session->ngh2)) {
                status = h2_proxy_session_read(session, 0, 0);
                if (status == APR_SUCCESS) {
                    have_read = 1;
                }
            }

            if (!have_written && !have_read
                && !nghttp2_session_want_write(session->ngh2)) {
                dispatch_event(session, H2_PROXYS_EV_NO_IO, 0, NULL);
                goto run_loop;
            }
            break;

        case H2_PROXYS_ST_WAIT:
            if (check_suspended(session) == APR_EAGAIN) {
                /* no stream has become resumed. Do a blocking read with
                 * ever increasing timeouts... */
                if (session->wait_timeout < 25) {
                    session->wait_timeout = 25;
                }
                else {
                    session->wait_timeout = H2MIN(apr_time_from_msec(100),
                                                  2*session->wait_timeout);
                }

                status = h2_proxy_session_read(session, 1, session->wait_timeout);
                ap_log_cerror(APLOG_MARK, APLOG_TRACE3, status, session->c,
                              APLOGNO(03365)
                              "h2_proxy_session(%s): WAIT read, timeout=%fms",
                              session->id, session->wait_timeout/1000.0);
                if (status == APR_SUCCESS) {
                    have_read = 1;
                    dispatch_event(session, H2_PROXYS_EV_DATA_READ, 0, NULL);
                }
                else if (APR_STATUS_IS_TIMEUP(status)
                    || APR_STATUS_IS_EAGAIN(status)) {
                    /* go back to checking all inputs again */
                    transit(session, "wait cycle", H2_PROXYS_ST_BUSY);
                }
            }
            break;

        case H2_PROXYS_ST_IDLE:
            break;

        case H2_PROXYS_ST_DONE: /* done, session terminated */
            return APR_EOF;

        default:
            ap_log_cerror(APLOG_MARK, APLOG_ERR, APR_EGENERAL, session->c,
                          APLOGNO(03346)"h2_proxy_session(%s): unknown state %d",
                          session->id, session->state);
            dispatch_event(session, H2_PROXYS_EV_PROTO_ERROR, 0, NULL);
            break;
    }

    if (have_read || have_written) {
        session->wait_timeout = 0;
    }

    if (!nghttp2_session_want_read(session->ngh2)
        && !nghttp2_session_want_write(session->ngh2)) {
        dispatch_event(session, H2_PROXYS_EV_NGH2_DONE, 0, NULL);
    }

    return APR_SUCCESS; /* needs to be called again */
}


static apr_status_t submit_stream(h2_proxy_session *session, h2_proxy_stream *stream)
{
    h2_proxy_ngheader *hd;
    nghttp2_data_provider *pp = NULL;
    nghttp2_data_provider provider;
    int rv, may_have_request_body = 1;
    apr_status_t status;

    hd = h2_proxy_util_nghd_make_req(stream->pool, stream->req);

    /* If we expect a 100-continue response, we must refrain from reading
       any input until we get it. Reading the input will possibly trigger
       HTTP_IN filter to generate the 100-continue itself. */
    if (stream->waiting_on_100 || stream->waiting_on_ping) {
        /* make a small test if we get an EOF/EOS immediately */
        status = ap_get_brigade(stream->r->input_filters, stream->input,
                                AP_MODE_READBYTES, APR_NONBLOCK_READ,
                                APR_BUCKET_BUFF_SIZE);
        may_have_request_body = APR_STATUS_IS_EAGAIN(status)
                                || (status == APR_SUCCESS
                                    && !APR_BUCKET_IS_EOS(APR_BRIGADE_FIRST(stream->input)));
    }

    if (may_have_request_body) {
        provider.source.fd = 0;
        provider.source.ptr = NULL;
        provider.read_callback = stream_request_data;
        pp = &provider;
    }

    rv = nghttp2_submit_request(session->ngh2, NULL,
                                hd->nv, hd->nvlen, pp, stream);

    ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c, APLOGNO(03363)
                  "h2_proxy_session(%s): submit %s%s -> %d",
                  session->id, stream->req->authority, stream->req->path,
                  rv);
    if (rv > 0) {
        stream->id = rv;
        stream->state = H2_STREAM_ST_OPEN;
        h2_proxy_ihash_add(session->streams, stream);
        dispatch_event(session, H2_PROXYS_EV_STREAM_SUBMITTED, rv, NULL);

        return APR_SUCCESS;
    }
    return APR_EGENERAL;
}


const h2_priority *h2_stream_get_priority(h2_stream *stream,
                                          h2_headers *response)
{
    if (response && stream->initiated_on) {
        const char *ctype = apr_table_get(response->headers, "content-type");
        if (ctype) {
            /* FIXME: Not good enough, config needs to come from request->server */
            return h2_cconfig_get_priority(stream->session->c, ctype);
        }
    }
    return NULL;
}


static int f_midi_snd_free(struct snd_device *device)
{
	return 0;
}


static void midi_attr_release(struct config_item *item)
{
	struct f_midi_opts *opts = to_f_midi_opts(item);

	usb_put_function_instance(&opts->func_inst);
}


static void dwc3_gadget_start_isoc(struct dwc3 *dwc,
		struct dwc3_ep *dep, const struct dwc3_event_depevt *event)
{
	u32 cur_uf, mask;

	mask = ~(dep->interval - 1);
	cur_uf = event->parameters & mask;

	__dwc3_gadget_start_isoc(dwc, dep, cur_uf);
}


static void dwc3_gadget_suspend_interrupt(struct dwc3 *dwc,
					  unsigned int evtinfo)
{
	enum dwc3_link_state next = evtinfo & DWC3_LINK_STATE_MASK;

	if (dwc->link_state != next && next == DWC3_LINK_STATE_U3)
		dwc3_suspend_gadget(dwc);

	dwc->link_state = next;
}


static void dwc3_resume_gadget(struct dwc3 *dwc)
{
	if (dwc->gadget_driver && dwc->gadget_driver->resume) {
		spin_unlock(&dwc->lock);
		dwc->gadget_driver->resume(&dwc->gadget);
		spin_lock(&dwc->lock);
	}
}


int dwc3_gadget_suspend(struct dwc3 *dwc)
{
	if (!dwc->gadget_driver)
		return 0;

	dwc3_gadget_run_stop(dwc, false, false);
	dwc3_disconnect_gadget(dwc);
	__dwc3_gadget_stop(dwc);

	return 0;
}


static int __dwc3_gadget_start(struct dwc3 *dwc)
{
	struct dwc3_ep		*dep;
	int			ret = 0;
	u32			reg;

	/*
	 * Use IMOD if enabled via dwc->imod_interval. Otherwise, if
	 * the core supports IMOD, disable it.
	 */
	if (dwc->imod_interval) {
		dwc3_writel(dwc->regs, DWC3_DEV_IMOD(0), dwc->imod_interval);
		dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), DWC3_GEVNTCOUNT_EHB);
	} else if (dwc3_has_imod(dwc)) {
		dwc3_writel(dwc->regs, DWC3_DEV_IMOD(0), 0);
	}

	/*
	 * We are telling dwc3 that we want to use DCFG.NUMP as ACK TP's NUMP
	 * field instead of letting dwc3 itself calculate that automatically.
	 *
	 * This way, we maximize the chances that we'll be able to get several
	 * bursts of data without going through any sort of endpoint throttling.
	 */
	reg = dwc3_readl(dwc->regs, DWC3_GRXTHRCFG);
	if (dwc3_is_usb31(dwc))
		reg &= ~DWC31_GRXTHRCFG_PKTCNTSEL;
	else
		reg &= ~DWC3_GRXTHRCFG_PKTCNTSEL;

	dwc3_writel(dwc->regs, DWC3_GRXTHRCFG, reg);

	dwc3_gadget_setup_nump(dwc);

	/* Start with SuperSpeed Default */
	dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);

	dep = dwc->eps[0];
	ret = __dwc3_gadget_ep_enable(dep, false, false);
	if (ret) {
		dev_err(dwc->dev, "failed to enable %s\n", dep->name);
		goto err0;
	}

	dep = dwc->eps[1];
	ret = __dwc3_gadget_ep_enable(dep, false, false);
	if (ret) {
		dev_err(dwc->dev, "failed to enable %s\n", dep->name);
		goto err1;
	}

	/* begin to receive SETUP packets */
	dwc->ep0state = EP0_SETUP_PHASE;
	dwc3_ep0_out_start(dwc);

	dwc3_gadget_enable_irq(dwc);

	return 0;

err1:
	__dwc3_gadget_ep_disable(dwc->eps[0]);

err0:
	return ret;
}


static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
{
	struct dwc3		*dwc = dep->dwc;

	if (!dep->endpoint.desc) {
		dev_err(dwc->dev, "%s: can't queue to disabled endpoint\n",
				dep->name);
		return -ESHUTDOWN;
	}

	if (WARN(req->dep != dep, "request %pK belongs to '%s'\n",
				&req->request, req->dep->name))
		return -EINVAL;

	pm_runtime_get(dwc->dev);

	req->request.actual	= 0;
	req->request.status	= -EINPROGRESS;
	req->direction		= dep->direction;
	req->epnum		= dep->number;

	trace_dwc3_ep_queue(req);

	list_add_tail(&req->list, &dep->pending_list);

	/*
	 * NOTICE: Isochronous endpoints should NEVER be prestarted. We must
	 * wait for a XferNotReady event so we will know what's the current
	 * (micro-)frame number.
	 *
	 * Without this trick, we are very, very likely gonna get Bus Expiry
	 * errors which will force us issue EndTransfer command.
	 */
	if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
		if ((dep->flags & DWC3_EP_PENDING_REQUEST)) {
			if (dep->flags & DWC3_EP_TRANSFER_STARTED) {
				dwc3_stop_active_transfer(dwc, dep->number, true);
				dep->flags = DWC3_EP_ENABLED;
			} else {
				u32 cur_uf;

				cur_uf = __dwc3_gadget_get_frame(dwc);
				__dwc3_gadget_start_isoc(dwc, dep, cur_uf);
				dep->flags &= ~DWC3_EP_PENDING_REQUEST;
			}
			return 0;
		}

		if ((dep->flags & DWC3_EP_BUSY) &&
		    !(dep->flags & DWC3_EP_MISSED_ISOC))
			goto out;

		return 0;
	}

out:
	return __dwc3_gadget_kick_transfer(dep);
}


static dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep,
		struct dwc3_trb *trb)
{
	u32		offset = (char *) trb - (char *) dep->trb_pool;

	return dep->trb_pool_dma + offset;
}


static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep,
		bool modify, bool restore)
{
	const struct usb_ss_ep_comp_descriptor *comp_desc;
	const struct usb_endpoint_descriptor *desc;
	struct dwc3_gadget_ep_cmd_params params;

	if (dev_WARN_ONCE(dwc->dev, modify && restore,
					"Can't modify and restore\n"))
		return -EINVAL;

	comp_desc = dep->endpoint.comp_desc;
	desc = dep->endpoint.desc;

	memset(&params, 0x00, sizeof(params));

	params.param0 = DWC3_DEPCFG_EP_TYPE(usb_endpoint_type(desc))
		| DWC3_DEPCFG_MAX_PACKET_SIZE(usb_endpoint_maxp(desc));

	/* Burst size is only needed in SuperSpeed mode */
	if (dwc->gadget.speed >= USB_SPEED_SUPER) {
		u32 burst = dep->endpoint.maxburst;
		params.param0 |= DWC3_DEPCFG_BURST_SIZE(burst - 1);
	}

	if (modify) {
		params.param0 |= DWC3_DEPCFG_ACTION_MODIFY;
	} else if (restore) {
		params.param0 |= DWC3_DEPCFG_ACTION_RESTORE;
		params.param2 |= dep->saved_state;
	} else {
		params.param0 |= DWC3_DEPCFG_ACTION_INIT;
	}

	if (usb_endpoint_xfer_control(desc))
		params.param1 = DWC3_DEPCFG_XFER_COMPLETE_EN;

	if (dep->number <= 1 || usb_endpoint_xfer_isoc(desc))
		params.param1 |= DWC3_DEPCFG_XFER_NOT_READY_EN;

	if (usb_ss_max_streams(comp_desc) && usb_endpoint_xfer_bulk(desc)) {
		params.param1 |= DWC3_DEPCFG_STREAM_CAPABLE
			| DWC3_DEPCFG_STREAM_EVENT_EN;
		dep->stream_capable = true;
	}

	if (!usb_endpoint_xfer_control(desc))
		params.param1 |= DWC3_DEPCFG_XFER_IN_PROGRESS_EN;

	/*
	 * We are doing 1:1 mapping for endpoints, meaning
	 * Physical Endpoints 2 maps to Logical Endpoint 2 and
	 * so on. We consider the direction bit as part of the physical
	 * endpoint number. So USB endpoint 0x81 is 0x03.
	 */
	params.param1 |= DWC3_DEPCFG_EP_NUMBER(dep->number);

	/*
	 * We must use the lower 16 TX FIFOs even though
	 * HW might have more
	 */
	if (dep->direction)
		params.param0 |= DWC3_DEPCFG_FIFO_NUMBER(dep->number >> 1);

	if (desc->bInterval) {
		params.param1 |= DWC3_DEPCFG_BINTERVAL_M1(desc->bInterval - 1);
		dep->interval = 1 << (desc->bInterval - 1);
	}

	return dwc3_send_gadget_ep_cmd(dep, DWC3_DEPCMD_SETEPCONFIG, &params);
}


static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc)
{
	/*
	 * TODO take core out of low power mode when that's
	 * implemented.
	 */

	if (dwc->gadget_driver && dwc->gadget_driver->resume) {
		spin_unlock(&dwc->lock);
		dwc->gadget_driver->resume(&dwc->gadget);
		spin_lock(&dwc->lock);
	}
}


static void dwc3_suspend_gadget(struct dwc3 *dwc)
{
	if (dwc->gadget_driver && dwc->gadget_driver->suspend) {
		spin_unlock(&dwc->lock);
		dwc->gadget_driver->suspend(&dwc->gadget);
		spin_lock(&dwc->lock);
	}
}


static void hidg_free(struct usb_function *f)
{
	struct f_hidg *hidg;
	struct f_hid_opts *opts;

	hidg = func_to_hidg(f);
	opts = container_of(f->fi, struct f_hid_opts, func_inst);
	kfree(hidg->report_desc);
	kfree(hidg);
	mutex_lock(&opts->lock);
	--opts->refcnt;
	mutex_unlock(&opts->lock);
}


static inline struct f_hidg *func_to_hidg(struct usb_function *f)
{
	return container_of(f, struct f_hidg, func);
}


static inline struct f_hid_opts *to_f_hid_opts(struct config_item *item)
{
	return container_of(to_config_group(item), struct f_hid_opts,
			    func_inst.group);
}


static ssize_t f_hidg_read(struct file *file, char __user *buffer,
			size_t count, loff_t *ptr)
{
	struct f_hidg *hidg = file->private_data;
	struct f_hidg_req_list *list;
	struct usb_request *req;
	unsigned long flags;
	int ret;

	if (!count)
		return 0;

	if (!access_ok(buffer, count))
		return -EFAULT;

	spin_lock_irqsave(&hidg->read_spinlock, flags);

#define READ_COND (!list_empty(&hidg->completed_out_req))

	/* wait for at least one buffer to complete */
	while (!READ_COND) {
		spin_unlock_irqrestore(&hidg->read_spinlock, flags);
		if (file->f_flags & O_NONBLOCK)
			return -EAGAIN;

		if (wait_event_interruptible(hidg->read_queue, READ_COND))
			return -ERESTARTSYS;

		spin_lock_irqsave(&hidg->read_spinlock, flags);
	}

	/* pick the first one */
	list = list_first_entry(&hidg->completed_out_req,
				struct f_hidg_req_list, list);

	/*
	 * Remove this from list to protect it from beign free()
	 * while host disables our function
	 */
	list_del(&list->list);

	req = list->req;
	count = min_t(unsigned int, count, req->actual - list->pos);
	spin_unlock_irqrestore(&hidg->read_spinlock, flags);

	/* copy to user outside spinlock */
	count -= copy_to_user(buffer, req->buf + list->pos, count);
	list->pos += count;

	/*
	 * if this request is completely handled and transfered to
	 * userspace, remove its entry from the list and requeue it
	 * again. Otherwise, we will revisit it again upon the next
	 * call, taking into account its current read position.
	 */
	if (list->pos == req->actual) {
		kfree(list);

		req->length = hidg->report_length;
		ret = usb_ep_queue(hidg->out_ep, req, GFP_KERNEL);
		if (ret < 0) {
			free_ep_req(hidg->out_ep, req);
			return ret;
		}
	} else {
		spin_lock_irqsave(&hidg->read_spinlock, flags);
		list_add(&list->list, &hidg->completed_out_req);
		spin_unlock_irqrestore(&hidg->read_spinlock, flags);

		wake_up(&hidg->read_queue);
	}

	return count;
}


static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
{
	struct usb_composite_dev		*cdev = f->config->cdev;
	struct f_hidg				*hidg = func_to_hidg(f);
	struct usb_request			*req_in = NULL;
	unsigned long				flags;
	int i, status = 0;

	VDBG(cdev, "hidg_set_alt intf:%d alt:%d\n", intf, alt);

	if (hidg->in_ep != NULL) {
		/* restart endpoint */
		usb_ep_disable(hidg->in_ep);

		status = config_ep_by_speed(f->config->cdev->gadget, f,
					    hidg->in_ep);
		if (status) {
			ERROR(cdev, "config_ep_by_speed FAILED!\n");
			goto fail;
		}
		status = usb_ep_enable(hidg->in_ep);
		if (status < 0) {
			ERROR(cdev, "Enable IN endpoint FAILED!\n");
			goto fail;
		}
		hidg->in_ep->driver_data = hidg;

		req_in = hidg_alloc_ep_req(hidg->in_ep, hidg->report_length);
		if (!req_in) {
			status = -ENOMEM;
			goto disable_ep_in;
		}
	}

	if (hidg->out_ep != NULL) {
		/* restart endpoint */
		usb_ep_disable(hidg->out_ep);

		status = config_ep_by_speed(f->config->cdev->gadget, f,
					    hidg->out_ep);
		if (status) {
			ERROR(cdev, "config_ep_by_speed FAILED!\n");
			goto free_req_in;
		}
		status = usb_ep_enable(hidg->out_ep);
		if (status < 0) {
			ERROR(cdev, "Enable OUT endpoint FAILED!\n");
			goto free_req_in;
		}
		hidg->out_ep->driver_data = hidg;

		/*
		 * allocate a bunch of read buffers and queue them all at once.
		 */
		for (i = 0; i < hidg->qlen && status == 0; i++) {
			struct usb_request *req =
					hidg_alloc_ep_req(hidg->out_ep,
							  hidg->report_length);
			if (req) {
				req->complete = hidg_set_report_complete;
				req->context  = hidg;
				status = usb_ep_queue(hidg->out_ep, req,
						      GFP_ATOMIC);
				if (status) {
					ERROR(cdev, "%s queue req --> %d\n",
						hidg->out_ep->name, status);
					free_ep_req(hidg->out_ep, req);
				}
			} else {
				status = -ENOMEM;
				goto disable_out_ep;
			}
		}
	}

	if (hidg->in_ep != NULL) {
		spin_lock_irqsave(&hidg->write_spinlock, flags);
		hidg->req = req_in;
		hidg->write_pending = 0;
		spin_unlock_irqrestore(&hidg->write_spinlock, flags);

		wake_up(&hidg->write_queue);
	}
	return 0;
disable_out_ep:
	usb_ep_disable(hidg->out_ep);
free_req_in:
	if (req_in)
		free_ep_req(hidg->in_ep, req_in);

disable_ep_in:
	if (hidg->in_ep)
		usb_ep_disable(hidg->in_ep);

fail:
	return status;
}


struct sock *mroute6_socket(struct net *net, struct sk_buff *skb)
{
	struct mr6_table *mrt;
	struct flowi6 fl6 = {
		.flowi6_iif	= skb->skb_iif ? : LOOPBACK_IFINDEX,
		.flowi6_oif	= skb->dev->ifindex,
		.flowi6_mark	= skb->mark,
	};

	if (ip6mr_fib_lookup(net, &fl6, &mrt) < 0)
		return NULL;

	return mrt->mroute6_sk;
}


static int __net_init ip6mr_net_init(struct net *net)
{
	int err;

	err = ip6mr_rules_init(net);
	if (err < 0)
		goto fail;

#ifdef CONFIG_PROC_FS
	err = -ENOMEM;
	if (!proc_create("ip6_mr_vif", 0, net->proc_net, &ip6mr_vif_fops))
		goto proc_vif_fail;
	if (!proc_create("ip6_mr_cache", 0, net->proc_net, &ip6mr_mfc_fops))
		goto proc_cache_fail;
#endif

	return 0;

#ifdef CONFIG_PROC_FS
proc_cache_fail:
	remove_proc_entry("ip6_mr_vif", net->proc_net);
proc_vif_fail:
	ip6mr_rules_exit(net);
#endif
fail:
	return err;
}


static void *ipmr_mfc_seq_start(struct seq_file *seq, loff_t *pos)
{
	struct ipmr_mfc_iter *it = seq->private;
	struct net *net = seq_file_net(seq);
	struct mr6_table *mrt;

	mrt = ip6mr_get_table(net, RT6_TABLE_DFLT);
	if (!mrt)
		return ERR_PTR(-ENOENT);

	it->mrt = mrt;
	return *pos ? ipmr_mfc_seq_idx(net, seq->private, *pos - 1)
		: SEQ_START_TOKEN;
}


static int __net_init ip6mr_rules_init(struct net *net)
{
	net->ipv6.mrt6 = ip6mr_new_table(net, RT6_TABLE_DFLT);
	return net->ipv6.mrt6 ? 0 : -ENOMEM;
}


static struct mfc6_cache *ipmr_mfc_seq_idx(struct net *net,
					   struct ipmr_mfc_iter *it, loff_t pos)
{
	struct mr6_table *mrt = it->mrt;
	struct mfc6_cache *mfc;

	read_lock(&mrt_lock);
	for (it->ct = 0; it->ct < MFC6_LINES; it->ct++) {
		it->cache = &mrt->mfc6_cache_array[it->ct];
		list_for_each_entry(mfc, it->cache, list)
			if (pos-- == 0)
				return mfc;
	}
	read_unlock(&mrt_lock);

	spin_lock_bh(&mfc_unres_lock);
	it->cache = &mrt->mfc6_unres_queue;
	list_for_each_entry(mfc, it->cache, list)
		if (pos-- == 0)
			return mfc;
	spin_unlock_bh(&mfc_unres_lock);

	it->cache = NULL;
	return NULL;
}


static int pim6_rcv(struct sk_buff *skb)
{
	struct pimreghdr *pim;
	struct ipv6hdr   *encap;
	struct net_device  *reg_dev = NULL;
	struct net *net = dev_net(skb->dev);
	struct mr6_table *mrt;
	struct flowi6 fl6 = {
		.flowi6_iif	= skb->dev->ifindex,
		.flowi6_mark	= skb->mark,
	};
	int reg_vif_num;

	if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(*encap)))
		goto drop;

	pim = (struct pimreghdr *)skb_transport_header(skb);
	if (pim->type != ((PIM_VERSION << 4) | PIM_TYPE_REGISTER) ||
	    (pim->flags & PIM_NULL_REGISTER) ||
	    (csum_ipv6_magic(&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr,
			     sizeof(*pim), IPPROTO_PIM,
			     csum_partial((void *)pim, sizeof(*pim), 0)) &&
	     csum_fold(skb_checksum(skb, 0, skb->len, 0))))
		goto drop;

	/* check if the inner packet is destined to mcast group */
	encap = (struct ipv6hdr *)(skb_transport_header(skb) +
				   sizeof(*pim));

	if (!ipv6_addr_is_multicast(&encap->daddr) ||
	    encap->payload_len == 0 ||
	    ntohs(encap->payload_len) + sizeof(*pim) > skb->len)
		goto drop;

	if (ip6mr_fib_lookup(net, &fl6, &mrt) < 0)
		goto drop;
	reg_vif_num = mrt->mroute_reg_vif_num;

	read_lock(&mrt_lock);
	if (reg_vif_num >= 0)
		reg_dev = mrt->vif6_table[reg_vif_num].dev;
	if (reg_dev)
		dev_hold(reg_dev);
	read_unlock(&mrt_lock);

	if (!reg_dev)
		goto drop;

	skb->mac_header = skb->network_header;
	skb_pull(skb, (u8 *)encap - skb->data);
	skb_reset_network_header(skb);
	skb->protocol = htons(ETH_P_IPV6);
	skb->ip_summed = CHECKSUM_NONE;

	skb_tunnel_rx(skb, reg_dev, dev_net(reg_dev));

	netif_rx(skb);

	dev_put(reg_dev);
	return 0;
 drop:
	kfree_skb(skb);
	return 0;
}


static netdev_tx_t reg_vif_xmit(struct sk_buff *skb,
				      struct net_device *dev)
{
	struct net *net = dev_net(dev);
	struct mr6_table *mrt;
	struct flowi6 fl6 = {
		.flowi6_oif	= dev->ifindex,
		.flowi6_iif	= skb->skb_iif ? : LOOPBACK_IFINDEX,
		.flowi6_mark	= skb->mark,
	};
	int err;

	err = ip6mr_fib_lookup(net, &fl6, &mrt);
	if (err < 0) {
		kfree_skb(skb);
		return err;
	}

	read_lock(&mrt_lock);
	dev->stats.tx_bytes += skb->len;
	dev->stats.tx_packets++;
	ip6mr_cache_report(mrt, skb, mrt->mroute_reg_vif_num, MRT6MSG_WHOLEPKT);
	read_unlock(&mrt_lock);
	kfree_skb(skb);
	return NETDEV_TX_OK;
}


static int ip6mr_find_vif(struct mr6_table *mrt, struct net_device *dev)
{
	int ct;

	for (ct = mrt->maxvif - 1; ct >= 0; ct--) {
		if (mrt->vif6_table[ct].dev == dev)
			break;
	}
	return ct;
}


int ip6mr_sk_done(struct sock *sk)
{
	int err = -EACCES;
	struct net *net = sock_net(sk);
	struct mr6_table *mrt;

	rtnl_lock();
	ip6mr_for_each_table(mrt, net) {
		if (sk == mrt->mroute6_sk) {
			write_lock_bh(&mrt_lock);
			mrt->mroute6_sk = NULL;
			net->ipv6.devconf_all->mc_forwarding--;
			write_unlock_bh(&mrt_lock);
			inet6_netconf_notify_devconf(net,
						     NETCONFA_MC_FORWARDING,
						     NETCONFA_IFINDEX_ALL,
						     net->ipv6.devconf_all);

			mroute_clean_tables(mrt, false);
			err = 0;
			break;
		}
	}
	rtnl_unlock();

	return err;
}


static void build_feature_ctl_badd(struct usb_mixer_interface *mixer,
			      unsigned int ctl_mask, int control, int unitid,
			      const struct usbmix_name_map *badd_map)
{
	__build_feature_ctl(mixer, badd_map, ctl_mask, control,
			NULL, NULL, unitid, 0, 0);
}


static int mixer_ctl_master_bool_get(struct snd_kcontrol *kcontrol,
				     struct snd_ctl_elem_value *ucontrol)
{
	struct usb_mixer_elem_info *cval = kcontrol->private_data;
	int val, err;

	err = snd_usb_get_cur_mix_value(cval, 0, 0, &val);
	if (err < 0)
		return filter_error(cval, err);
	val = (val != 0);
	ucontrol->value.integer.value[0] = val;
	return 0;
}


int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,
				int request, int validx, int value_set)
{
	struct snd_usb_audio *chip = cval->head.mixer->chip;
	unsigned char buf[4];
	int idx = 0, val_len, err, timeout = 10;

	validx += cval->idx_off;

	if (cval->head.mixer->protocol == UAC_VERSION_1) {
		val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1;
	} else { /* UAC_VERSION_2/3 */
		val_len = uac2_ctl_value_size(cval->val_type);

		/* FIXME */
		if (request != UAC_SET_CUR) {
			usb_audio_dbg(chip, "RANGE setting not yet supported\n");
			return -EINVAL;
		}

		request = UAC2_CS_CUR;
	}

	value_set = convert_bytes_value(cval, value_set);
	buf[0] = value_set & 0xff;
	buf[1] = (value_set >> 8) & 0xff;
	buf[2] = (value_set >> 16) & 0xff;
	buf[3] = (value_set >> 24) & 0xff;

	err = snd_usb_lock_shutdown(chip);
	if (err < 0)
		return -EIO;

	while (timeout-- > 0) {
		idx = snd_usb_ctrl_intf(chip) | (cval->head.id << 8);
		err = snd_usb_ctl_msg(chip->dev,
				      usb_sndctrlpipe(chip->dev, 0), request,
				      USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
				      validx, idx, buf, val_len);
		if (err >= 0) {
			err = 0;
			goto out;
		} else if (err == -ETIMEDOUT) {
			goto out;
		}
	}
	usb_audio_dbg(chip, "cannot set ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d, data = %#x/%#x\n",
		      request, validx, idx, cval->val_type, buf[0], buf[1]);
	err = -EINVAL;

 out:
	snd_usb_unlock_shutdown(chip);
	return err;
}


xfs_finish_flags(
	struct xfs_mount	*mp)
{
	int			ronly = (mp->m_flags & XFS_MOUNT_RDONLY);

	/* Fail a mount where the logbuf is smaller than the log stripe */
	if (xfs_sb_version_haslogv2(&mp->m_sb)) {
		if (mp->m_logbsize <= 0 &&
		    mp->m_sb.sb_logsunit > XLOG_BIG_RECORD_BSIZE) {
			mp->m_logbsize = mp->m_sb.sb_logsunit;
		} else if (mp->m_logbsize > 0 &&
			   mp->m_logbsize < mp->m_sb.sb_logsunit) {
			xfs_warn(mp,
		"logbuf size must be greater than or equal to log stripe size");
			return -EINVAL;
		}
	} else {
		/* Fail a mount if the logbuf is larger than 32K */
		if (mp->m_logbsize > XLOG_BIG_RECORD_BSIZE) {
			xfs_warn(mp,
		"logbuf size for version 1 logs must be 16K or 32K");
			return -EINVAL;
		}
	}

	/*
	 * V5 filesystems always use attr2 format for attributes.
	 */
	if (xfs_sb_version_hascrc(&mp->m_sb) &&
	    (mp->m_flags & XFS_MOUNT_NOATTR2)) {
		xfs_warn(mp, "Cannot mount a V5 filesystem as noattr2. "
			     "attr2 is always enabled for V5 filesystems.");
		return -EINVAL;
	}

	/*
	 * mkfs'ed attr2 will turn on attr2 mount unless explicitly
	 * told by noattr2 to turn it off
	 */
	if (xfs_sb_version_hasattr2(&mp->m_sb) &&
	    !(mp->m_flags & XFS_MOUNT_NOATTR2))
		mp->m_flags |= XFS_MOUNT_ATTR2;

	/*
	 * prohibit r/w mounts of read-only filesystems
	 */
	if ((mp->m_sb.sb_flags & XFS_SBF_READONLY) && !ronly) {
		xfs_warn(mp,
			"cannot mount a read-only filesystem as read-write");
		return -EROFS;
	}

	if ((mp->m_qflags & (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE)) &&
	    (mp->m_qflags & (XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE)) &&
	    !xfs_sb_version_has_pquotino(&mp->m_sb)) {
		xfs_warn(mp,
		  "Super block does not support project and group quota together");
		return -EINVAL;
	}

	return 0;
}


init_xfs_fs(void)
{
	int			error;

	xfs_check_ondisk_structs();

	printk(KERN_INFO XFS_VERSION_STRING " with "
			 XFS_BUILD_OPTIONS " enabled\n");

	xfs_extent_free_init_defer_op();
	xfs_rmap_update_init_defer_op();
	xfs_refcount_update_init_defer_op();
	xfs_bmap_update_init_defer_op();

	xfs_dir_startup();

	error = xfs_init_zones();
	if (error)
		goto out;

	error = xfs_init_workqueues();
	if (error)
		goto out_destroy_zones;

	error = xfs_mru_cache_init();
	if (error)
		goto out_destroy_wq;

	error = xfs_buf_init();
	if (error)
		goto out_mru_cache_uninit;

	error = xfs_init_procfs();
	if (error)
		goto out_buf_terminate;

	error = xfs_sysctl_register();
	if (error)
		goto out_cleanup_procfs;

	xfs_kset = kset_create_and_add("xfs", NULL, fs_kobj);
	if (!xfs_kset) {
		error = -ENOMEM;
		goto out_sysctl_unregister;
	}

	xfsstats.xs_kobj.kobject.kset = xfs_kset;

	xfsstats.xs_stats = alloc_percpu(struct xfsstats);
	if (!xfsstats.xs_stats) {
		error = -ENOMEM;
		goto out_kset_unregister;
	}

	error = xfs_sysfs_init(&xfsstats.xs_kobj, &xfs_stats_ktype, NULL,
			       "stats");
	if (error)
		goto out_free_stats;

#ifdef DEBUG
	xfs_dbg_kobj.kobject.kset = xfs_kset;
	error = xfs_sysfs_init(&xfs_dbg_kobj, &xfs_dbg_ktype, NULL, "debug");
	if (error)
		goto out_remove_stats_kobj;
#endif

	error = xfs_qm_init();
	if (error)
		goto out_remove_dbg_kobj;

	error = register_filesystem(&xfs_fs_type);
	if (error)
		goto out_qm_exit;
	return 0;

 out_qm_exit:
	xfs_qm_exit();
 out_remove_dbg_kobj:
#ifdef DEBUG
	xfs_sysfs_del(&xfs_dbg_kobj);
 out_remove_stats_kobj:
#endif
	xfs_sysfs_del(&xfsstats.xs_kobj);
 out_free_stats:
	free_percpu(xfsstats.xs_stats);
 out_kset_unregister:
	kset_unregister(xfs_kset);
 out_sysctl_unregister:
	xfs_sysctl_unregister();
 out_cleanup_procfs:
	xfs_cleanup_procfs();
 out_buf_terminate:
	xfs_buf_terminate();
 out_mru_cache_uninit:
	xfs_mru_cache_uninit();
 out_destroy_wq:
	xfs_destroy_workqueues();
 out_destroy_zones:
	xfs_destroy_zones();
 out:
	return error;
}


xfs_fs_dirty_inode(
	struct inode			*inode,
	int				flag)
{
	struct xfs_inode		*ip = XFS_I(inode);
	struct xfs_mount		*mp = ip->i_mount;
	struct xfs_trans		*tp;

	if (!(inode->i_sb->s_flags & SB_LAZYTIME))
		return;
	if (flag != I_DIRTY_SYNC || !(inode->i_state & I_DIRTY_TIME))
		return;

	if (xfs_trans_alloc(mp, &M_RES(mp)->tr_fsyncts, 0, 0, 0, &tp))
		return;
	xfs_ilock(ip, XFS_ILOCK_EXCL);
	xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
	xfs_trans_log_inode(tp, ip, XFS_ILOG_TIMESTAMP);
	xfs_trans_commit(tp);
}


xfs_fs_free_cached_objects(
	struct super_block	*sb,
	struct shrink_control	*sc)
{
	return xfs_reclaim_inodes_nr(XFS_M(sb), sc->nr_to_scan);
}


xfs_flush_inodes(
	struct xfs_mount	*mp)
{
	struct super_block	*sb = mp->m_super;

	if (down_read_trylock(&sb->s_umount)) {
		sync_inodes_sb(sb);
		up_read(&sb->s_umount);
	}
}


xfs_reinit_percpu_counters(
	struct xfs_mount	*mp)
{
	percpu_counter_set(&mp->m_icount, mp->m_sb.sb_icount);
	percpu_counter_set(&mp->m_ifree, mp->m_sb.sb_ifree);
	percpu_counter_set(&mp->m_fdblocks, mp->m_sb.sb_fdblocks);
}


xfs_init_percpu_counters(
	struct xfs_mount	*mp)
{
	int		error;

	error = percpu_counter_init(&mp->m_icount, 0, GFP_KERNEL);
	if (error)
		return -ENOMEM;

	error = percpu_counter_init(&mp->m_ifree, 0, GFP_KERNEL);
	if (error)
		goto free_icount;

	error = percpu_counter_init(&mp->m_fdblocks, 0, GFP_KERNEL);
	if (error)
		goto free_ifree;

	return 0;

free_ifree:
	percpu_counter_destroy(&mp->m_ifree);
free_icount:
	percpu_counter_destroy(&mp->m_icount);
	return -ENOMEM;
}


xfs_fs_mount(
	struct file_system_type	*fs_type,
	int			flags,
	const char		*dev_name,
	void			*data)
{
	return mount_bdev(fs_type, flags, dev_name, data, xfs_fs_fill_super);
}


static int ath6kl_usb_probe(struct usb_interface *interface,
			    const struct usb_device_id *id)
{
	struct usb_device *dev = interface_to_usbdev(interface);
	struct ath6kl *ar;
	struct ath6kl_usb *ar_usb = NULL;
	int vendor_id, product_id;
	int ret = 0;

	usb_get_dev(dev);

	vendor_id = le16_to_cpu(dev->descriptor.idVendor);
	product_id = le16_to_cpu(dev->descriptor.idProduct);

	ath6kl_dbg(ATH6KL_DBG_USB, "vendor_id = %04x\n", vendor_id);
	ath6kl_dbg(ATH6KL_DBG_USB, "product_id = %04x\n", product_id);

	if (interface->cur_altsetting)
		ath6kl_dbg(ATH6KL_DBG_USB, "USB Interface %d\n",
			   interface->cur_altsetting->desc.bInterfaceNumber);

	if (dev->speed == USB_SPEED_HIGH)
		ath6kl_dbg(ATH6KL_DBG_USB, "USB 2.0 Host\n");
	else
		ath6kl_dbg(ATH6KL_DBG_USB, "USB 1.1 Host\n");

	ar_usb = ath6kl_usb_create(interface);

	if (ar_usb == NULL) {
		ret = -ENOMEM;
		goto err_usb_put;
	}

	ar = ath6kl_core_create(&ar_usb->udev->dev);
	if (ar == NULL) {
		ath6kl_err("Failed to alloc ath6kl core\n");
		ret = -ENOMEM;
		goto err_usb_destroy;
	}

	ar->hif_priv = ar_usb;
	ar->hif_type = ATH6KL_HIF_TYPE_USB;
	ar->hif_ops = &ath6kl_usb_ops;
	ar->mbox_info.block_size = 16;
	ar->bmi.max_data_size = 252;

	ar_usb->ar = ar;

	ret = ath6kl_core_init(ar, ATH6KL_HTC_TYPE_PIPE);
	if (ret) {
		ath6kl_err("Failed to init ath6kl core: %d\n", ret);
		goto err_core_free;
	}

	return ret;

err_core_free:
	ath6kl_core_destroy(ar);
err_usb_destroy:
	ath6kl_usb_destroy(ar_usb);
err_usb_put:
	usb_put_dev(dev);

	return ret;
}


static int ath6kl_usb_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
{
	/*
	 * cfg80211 suspend/WOW currently not supported for USB.
	 */
	return 0;
}


static u8 ath6kl_usb_get_logical_pipe_num(struct ath6kl_usb *ar_usb,
					  u8 ep_address, int *urb_count)
{
	u8 pipe_num = ATH6KL_USB_PIPE_INVALID;

	switch (ep_address) {
	case ATH6KL_USB_EP_ADDR_APP_CTRL_IN:
		pipe_num = ATH6KL_USB_PIPE_RX_CTRL;
		*urb_count = RX_URB_COUNT;
		break;
	case ATH6KL_USB_EP_ADDR_APP_DATA_IN:
		pipe_num = ATH6KL_USB_PIPE_RX_DATA;
		*urb_count = RX_URB_COUNT;
		break;
	case ATH6KL_USB_EP_ADDR_APP_INT_IN:
		pipe_num = ATH6KL_USB_PIPE_RX_INT;
		*urb_count = RX_URB_COUNT;
		break;
	case ATH6KL_USB_EP_ADDR_APP_DATA2_IN:
		pipe_num = ATH6KL_USB_PIPE_RX_DATA2;
		*urb_count = RX_URB_COUNT;
		break;
	case ATH6KL_USB_EP_ADDR_APP_CTRL_OUT:
		pipe_num = ATH6KL_USB_PIPE_TX_CTRL;
		*urb_count = TX_URB_COUNT;
		break;
	case ATH6KL_USB_EP_ADDR_APP_DATA_LP_OUT:
		pipe_num = ATH6KL_USB_PIPE_TX_DATA_LP;
		*urb_count = TX_URB_COUNT;
		break;
	case ATH6KL_USB_EP_ADDR_APP_DATA_MP_OUT:
		pipe_num = ATH6KL_USB_PIPE_TX_DATA_MP;
		*urb_count = TX_URB_COUNT;
		break;
	case ATH6KL_USB_EP_ADDR_APP_DATA_HP_OUT:
		pipe_num = ATH6KL_USB_PIPE_TX_DATA_HP;
		*urb_count = TX_URB_COUNT;
		break;
	default:
		/* note: there may be endpoints not currently used */
		break;
	}

	return pipe_num;
}


read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
{
	DEFINE_WAIT(wait);
	struct rio_usb_data *rio = &rio_instance;
	ssize_t read_count;
	unsigned int partial;
	int this_read;
	int result;
	int maxretry = 10;
	char *ibuf;
	int intr;

	intr = mutex_lock_interruptible(&(rio->lock));
	if (intr)
		return -EINTR;
	/* Sanity check to make sure rio is connected, powered, etc */
        if (rio->present == 0 || rio->rio_dev == NULL) {
		mutex_unlock(&(rio->lock));
		return -ENODEV;
	}

	ibuf = rio->ibuf;

	read_count = 0;

	while (count > 0) {
		if (signal_pending(current)) {
			mutex_unlock(&(rio->lock));
			return read_count ? read_count : -EINTR;
		}
		if (!rio->rio_dev) {
			mutex_unlock(&(rio->lock));
			return -ENODEV;
		}
		this_read = (count >= IBUF_SIZE) ? IBUF_SIZE : count;

		result = usb_bulk_msg(rio->rio_dev,
				      usb_rcvbulkpipe(rio->rio_dev, 1),
				      ibuf, this_read, &partial,
				      8000);

		dev_dbg(&rio->rio_dev->dev,
			"read stats: result:%d this_read:%u partial:%u\n",
			result, this_read, partial);

		if (partial) {
			count = this_read = partial;
		} else if (result == -ETIMEDOUT || result == 15) {	/* FIXME: 15 ??? */
			if (!maxretry--) {
				mutex_unlock(&(rio->lock));
				dev_err(&rio->rio_dev->dev,
					"read_rio: maxretry timeout\n");
				return -ETIME;
			}
			prepare_to_wait(&rio->wait_q, &wait, TASK_INTERRUPTIBLE);
			schedule_timeout(NAK_TIMEOUT);
			finish_wait(&rio->wait_q, &wait);
			continue;
		} else if (result != -EREMOTEIO) {
			mutex_unlock(&(rio->lock));
			dev_err(&rio->rio_dev->dev,
				"Read Whoops - result:%d partial:%u this_read:%u\n",
				result, partial, this_read);
			return -EIO;
		} else {
			mutex_unlock(&(rio->lock));
			return (0);
		}

		if (this_read) {
			if (copy_to_user(buffer, ibuf, this_read)) {
				mutex_unlock(&(rio->lock));
				return -EFAULT;
			}
			count -= this_read;
			read_count += this_read;
			buffer += this_read;
		}
	}
	mutex_unlock(&(rio->lock));
	return read_count;
}


static void ath10k_usb_free_pipe_resources(struct ath10k *ar,
					   struct ath10k_usb_pipe *pipe)
{
	struct ath10k_urb_context *urb_context;

	if (!pipe->ar_usb) {
		/* nothing allocated for this pipe */
		return;
	}

	ath10k_dbg(ar, ATH10K_DBG_USB,
		   "usb free resources lpipe %d hpipe 0x%x urbs %d avail %d\n",
		   pipe->logical_pipe_num, pipe->usb_pipe_handle,
		   pipe->urb_alloc, pipe->urb_cnt);

	if (pipe->urb_alloc != pipe->urb_cnt) {
		ath10k_dbg(ar, ATH10K_DBG_USB,
			   "usb urb leak lpipe %d hpipe 0x%x urbs %d avail %d\n",
			   pipe->logical_pipe_num, pipe->usb_pipe_handle,
			   pipe->urb_alloc, pipe->urb_cnt);
	}

	for (;;) {
		urb_context = ath10k_usb_alloc_urb_from_pipe(pipe);

		if (!urb_context)
			break;

		kfree(urb_context);
	}
}


static void ath10k_usb_hif_send_complete_check(struct ath10k *ar,
					       u8 pipe, int force)
{
}


int snd_card_file_add(struct snd_card *card, struct file *file)
{
	struct snd_monitor_file *mfile;

	mfile = kmalloc(sizeof(*mfile), GFP_KERNEL);
	if (mfile == NULL)
		return -ENOMEM;
	mfile->file = file;
	mfile->disconnected_f_op = NULL;
	INIT_LIST_HEAD(&mfile->shutdown_list);
	spin_lock(&card->files_lock);
	if (card->shutdown) {
		spin_unlock(&card->files_lock);
		kfree(mfile);
		return -ENODEV;
	}
	list_add(&mfile->list, &card->files_list);
	get_device(&card->card_dev);
	spin_unlock(&card->files_lock);
	return 0;
}


int snd_card_file_remove(struct snd_card *card, struct file *file)
{
	struct snd_monitor_file *mfile, *found = NULL;

	spin_lock(&card->files_lock);
	list_for_each_entry(mfile, &card->files_list, list) {
		if (mfile->file == file) {
			list_del(&mfile->list);
			spin_lock(&shutdown_lock);
			list_del(&mfile->shutdown_list);
			spin_unlock(&shutdown_lock);
			if (mfile->disconnected_f_op)
				fops_put(mfile->disconnected_f_op);
			found = mfile;
			break;
		}
	}
	if (list_empty(&card->files_list))
		wake_up_all(&card->remove_sleep);
	spin_unlock(&card->files_lock);
	if (!found) {
		dev_err(card->dev, "card file remove problem (%p)\n", file);
		return -ENOENT;
	}
	kfree(found);
	put_device(&card->card_dev);
	return 0;
}


int __exit snd_info_done(void)
{
	snd_info_free_entry(snd_proc_root);
	return 0;
}


static ssize_t snd_info_entry_read(struct file *file, char __user *buffer,
				   size_t count, loff_t * offset)
{
	struct snd_info_private_data *data = file->private_data;
	struct snd_info_entry *entry = data->entry;
	size_t size;
	loff_t pos;

	pos = *offset;
	if (!valid_pos(pos, count))
		return -EIO;
	if (pos >= entry->size)
		return 0;
	size = entry->size - pos;
	size = min(count, size);
	size = entry->c.ops->read(entry, data->file_private_data,
				  file, buffer, size, pos);
	if ((ssize_t) size > 0)
		*offset = pos + size;
	return size;
}


static void snd_card_id_read(struct snd_info_entry *entry,
			     struct snd_info_buffer *buffer)
{
	struct snd_card *card = entry->private_data;

	snd_iprintf(buffer, "%s\n", card->id);
}


int snd_info_card_register(struct snd_card *card)
{
	struct proc_dir_entry *p;
	int err;

	if (snd_BUG_ON(!card))
		return -ENXIO;

	err = snd_info_register(card->proc_root);
	if (err < 0)
		return err;

	if (!strcmp(card->id, card->proc_root->name))
		return 0;

	if (card->proc_root_link)
		return 0;
	p = proc_symlink(card->id, snd_proc_root->p, card->proc_root->name);
	if (!p)
		return -ENOMEM;
	card->proc_root_link = p;
	return 0;
}


void radeon_atom_initialize_bios_scratch_regs(struct drm_device *dev)
{
	struct radeon_device *rdev = dev->dev_private;
	uint32_t bios_2_scratch, bios_6_scratch;

	if (rdev->family >= CHIP_R600) {
		bios_2_scratch = RREG32(R600_BIOS_2_SCRATCH);
		bios_6_scratch = RREG32(R600_BIOS_6_SCRATCH);
	} else {
		bios_2_scratch = RREG32(RADEON_BIOS_2_SCRATCH);
		bios_6_scratch = RREG32(RADEON_BIOS_6_SCRATCH);
	}

	/* let the bios control the backlight */
	bios_2_scratch &= ~ATOM_S2_VRI_BRIGHT_ENABLE;

	/* tell the bios not to handle mode switching */
	bios_6_scratch |= (ATOM_S6_ACC_BLOCK_DISPLAY_SWITCH | ATOM_S6_ACC_MODE);

	if (rdev->family >= CHIP_R600) {
		WREG32(R600_BIOS_2_SCRATCH, bios_2_scratch);
		WREG32(R600_BIOS_6_SCRATCH, bios_6_scratch);
	} else {
		WREG32(RADEON_BIOS_2_SCRATCH, bios_2_scratch);
		WREG32(RADEON_BIOS_6_SCRATCH, bios_6_scratch);
	}

}


void mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, int index)
{
	struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table;

	if (index < MLX4_VLAN_REGULAR) {
		mlx4_warn(dev, "Trying to free special vlan index %d\n", index);
		return;
	}

	mutex_lock(&table->mutex);
	if (!table->refs[index]) {
		mlx4_warn(dev, "No vlan entry for index %d\n", index);
		goto out;
	}
	if (--table->refs[index]) {
		mlx4_dbg(dev, "Have more references for index %d,"
			 "no need to modify vlan table\n", index);
		goto out;
	}
	table->entries[index] = 0;
	mlx4_set_port_vlan_table(dev, port, table->entries);
	--table->total;
out:
	mutex_unlock(&table->mutex);
}


mwifiex_uap_bss_wep(u8 **tlv_buf, void *cmd_buf, u16 *param_size)
{
	struct host_cmd_tlv_wep_key *wep_key;
	u16 cmd_size = *param_size;
	int i;
	u8 *tlv = *tlv_buf;
	struct mwifiex_uap_bss_param *bss_cfg = cmd_buf;

	for (i = 0; i < NUM_WEP_KEYS; i++) {
		if (bss_cfg->wep_cfg[i].length &&
		    (bss_cfg->wep_cfg[i].length == WLAN_KEY_LEN_WEP40 ||
		     bss_cfg->wep_cfg[i].length == WLAN_KEY_LEN_WEP104)) {
			wep_key = (struct host_cmd_tlv_wep_key *)tlv;
			wep_key->header.type =
				cpu_to_le16(TLV_TYPE_UAP_WEP_KEY);
			wep_key->header.len =
				cpu_to_le16(bss_cfg->wep_cfg[i].length + 2);
			wep_key->key_index = bss_cfg->wep_cfg[i].key_index;
			wep_key->is_default = bss_cfg->wep_cfg[i].is_default;
			memcpy(wep_key->key, bss_cfg->wep_cfg[i].key,
			       bss_cfg->wep_cfg[i].length);
			cmd_size += sizeof(struct mwifiex_ie_types_header) + 2 +
				    bss_cfg->wep_cfg[i].length;
			tlv += sizeof(struct mwifiex_ie_types_header) + 2 +
				    bss_cfg->wep_cfg[i].length;
		}
	}

	*param_size = cmd_size;
	*tlv_buf = tlv;

	return;
}


int cpia2_usb_stream_resume(struct camera_data *cam)
{
	int ret = 0;
	if(cam->streaming) {
		cam->first_image_seen = 0;
		ret = set_alternate(cam, cam->params.camera_state.stream_mode);
		if(ret == 0) {
			/* for some reason the user effects need to be set
			   again when starting streaming. */
			cpia2_do_command(cam, CPIA2_CMD_SET_USER_EFFECTS, TRANSFER_WRITE,
					cam->params.vp_params.user_effects);
			ret = submit_urbs(cam);
		}
	}
	return ret;
}


static int zr364xx_vidioc_qbuf(struct file *file,
				void *priv,
				struct v4l2_buffer *p)
{
	int rc;
	struct zr364xx_camera *cam = video_drvdata(file);
	_DBG("%s\n", __func__);
	if (cam->owner && cam->owner != priv)
		return -EBUSY;
	rc = videobuf_qbuf(&cam->vb_vidq, p);
	return rc;
}


static int zr364xx_open(struct file *file)
{
	struct zr364xx_camera *cam = video_drvdata(file);
	int err;

	DBG("%s\n", __func__);

	if (mutex_lock_interruptible(&cam->lock))
		return -ERESTARTSYS;

	err = v4l2_fh_open(file);
	if (err)
		goto out;

	/* Added some delay here, since opening/closing the camera quickly,
	 * like Ekiga does during its startup, can crash the webcam
	 */
	mdelay(100);
	err = 0;

out:
	mutex_unlock(&cam->lock);
	DBG("%s: %d\n", __func__, err);
	return err;
}


static int zr364xx_close(struct file *file)
{
	struct zr364xx_camera *cam;
	struct usb_device *udev;
	int i;

	DBG("%s\n", __func__);
	cam = video_drvdata(file);

	mutex_lock(&cam->lock);
	udev = cam->udev;

	if (file->private_data == cam->owner) {
		/* turn off stream */
		if (cam->b_acquire)
			zr364xx_stop_acquire(cam);
		videobuf_streamoff(&cam->vb_vidq);

		for (i = 0; i < 2; i++) {
			send_control_msg(udev, 1, init[cam->method][i].value,
					0, init[cam->method][i].bytes,
					init[cam->method][i].size);
		}
		cam->owner = NULL;
	}

	/* Added some delay here, since opening/closing the camera quickly,
	 * like Ekiga does during its startup, can crash the webcam
	 */
	mdelay(100);
	mutex_unlock(&cam->lock);
	return v4l2_fh_release(file);
}


static void zr364xx_stop_readpipe(struct zr364xx_camera *cam)
{
	struct zr364xx_pipeinfo *pipe_info;

	if (!cam) {
		printk(KERN_ERR KBUILD_MODNAME ": invalid device\n");
		return;
	}
	DBG("stop read pipe\n");
	pipe_info = cam->pipe;
	if (pipe_info) {
		if (pipe_info->state != 0)
			pipe_info->state = 0;

		if (pipe_info->stream_urb) {
			/* cancel urb */
			usb_kill_urb(pipe_info->stream_urb);
			usb_free_urb(pipe_info->stream_urb);
			pipe_info->stream_urb = NULL;
		}
	}
	return;
}


static int zr364xx_vidioc_streamoff(struct file *file, void *priv,
				    enum v4l2_buf_type type)
{
	struct zr364xx_camera *cam = video_drvdata(file);

	DBG("%s\n", __func__);
	if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
		return -EINVAL;
	if (cam->owner && cam->owner != priv)
		return -EBUSY;
	zr364xx_stop_acquire(cam);
	return videobuf_streamoff(&cam->vb_vidq);
}


static int smsusb_start_streaming(struct smsusb_device_t *dev)
{
	int i, rc;

	for (i = 0; i < MAX_URBS; i++) {
		rc = smsusb_submit_urb(dev, &dev->surbs[i]);
		if (rc < 0) {
			pr_err("smsusb_submit_urb(...) failed\n");
			smsusb_stop_streaming(dev);
			break;
		}
	}

	return rc;
}


static void smsusb_disconnect(struct usb_interface *intf)
{
	smsusb_term_device(intf);
}


static int sisusb_alloc_outbuf(struct sisusb_usb_data *sisusb)
{
	int i;

	i = sisusb_outurb_available(sisusb);

	if (i >= 0)
		sisusb->urbstatus[i] |= SU_URB_ALLOC;

	return i;
}


static int sisusb_clear_vram(struct sisusb_usb_data *sisusb,
		u32 address, int length)
{
	int ret, i;
	ssize_t j;

	if (address < sisusb->vrambase)
		return 1;

	if (address >= sisusb->vrambase + sisusb->vramsize)
		return 1;

	if (address + length > sisusb->vrambase + sisusb->vramsize)
		length = sisusb->vrambase + sisusb->vramsize - address;

	if (length <= 0)
		return 0;

	/* allocate free buffer/urb and clear the buffer */
	i = sisusb_alloc_outbuf(sisusb);
	if (i < 0)
		return -EBUSY;

	memset(sisusb->obuf[i], 0, sisusb->obufsize);

	/* We can write a length > buffer size here. The buffer
	 * data will simply be re-used (like a ring-buffer).
	 */
	ret = sisusb_write_mem_bulk(sisusb, address, NULL, length, NULL, i, &j);

	/* Free the buffer/urb */
	sisusb_free_outbuf(sisusb, i);

	return ret;
}


int sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port,
		u8 index, u8 myor)
{
	return sisusb_setidxregandor(sisusb, port, index, 0xff, myor);
}


static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
		char *kernbuffer, int length, char __user *userbuffer,
		ssize_t *bytes_read)
{
	int ret = 0;
	char buf[4];
	u16 swap16;
	u32 swap32;

	(*bytes_read = 0);

	length &= 0x00ffffff;

	while (length) {
		switch (length) {
		case 1:
			ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM,
					addr, &buf[0]);
			if (!ret) {
				(*bytes_read)++;
				if (userbuffer) {
					if (put_user(buf[0], (u8 __user *)userbuffer))
						return -EFAULT;
				} else
					kernbuffer[0] = buf[0];
			}
			return ret;

		case 2:
			ret |= sisusb_read_memio_word(sisusb, SISUSB_TYPE_MEM,
					addr, &swap16);
			if (!ret) {
				(*bytes_read) += 2;
				if (userbuffer) {
					if (put_user(swap16, (u16 __user *)userbuffer))
						return -EFAULT;
				} else {
					*((u16 *)kernbuffer) = swap16;
				}
			}
			return ret;

		case 3:
			ret |= sisusb_read_memio_24bit(sisusb, SISUSB_TYPE_MEM,
					addr, &swap32);
			if (!ret) {
				(*bytes_read) += 3;
#ifdef __BIG_ENDIAN
				buf[0] = (swap32 >> 16) & 0xff;
				buf[1] = (swap32 >> 8) & 0xff;
				buf[2] = swap32 & 0xff;
#else
				buf[2] = (swap32 >> 16) & 0xff;
				buf[1] = (swap32 >> 8) & 0xff;
				buf[0] = swap32 & 0xff;
#endif
				if (userbuffer) {
					if (copy_to_user(userbuffer,
							&buf[0], 3))
						return -EFAULT;
				} else {
					kernbuffer[0] = buf[0];
					kernbuffer[1] = buf[1];
					kernbuffer[2] = buf[2];
				}
			}
			return ret;

		default:
			ret |= sisusb_read_memio_long(sisusb, SISUSB_TYPE_MEM,
					addr, &swap32);
			if (!ret) {
				(*bytes_read) += 4;
				if (userbuffer) {
					if (put_user(swap32, (u32 __user *)userbuffer))
						return -EFAULT;

					userbuffer += 4;
				} else {
					*((u32 *)kernbuffer) = swap32;
					kernbuffer += 4;
				}
				addr += 4;
				length -= 4;
			}
		}
		if (ret)
			break;
	}

	return ret;
}


static int sisusb_write_memio_word(struct sisusb_usb_data *sisusb, int type,
		u32 addr, u16 data)
{
	struct sisusb_packet packet;
	int ret = 0;

	packet.address = addr & ~3;

	switch (addr & 3) {
	case 0:
		packet.header = (type << 6) | 0x0003;
		packet.data   = (u32)data;
		ret = sisusb_send_packet(sisusb, 10, &packet);
		break;
	case 1:
		packet.header = (type << 6) | 0x0006;
		packet.data   = (u32)data << 8;
		ret = sisusb_send_packet(sisusb, 10, &packet);
		break;
	case 2:
		packet.header = (type << 6) | 0x000c;
		packet.data   = (u32)data << 16;
		ret = sisusb_send_packet(sisusb, 10, &packet);
		break;
	case 3:
		packet.header = (type << 6) | 0x0008;
		packet.data   = (u32)data << 24;
		ret = sisusb_send_packet(sisusb, 10, &packet);
		packet.header = (type << 6) | 0x0001;
		packet.address = (addr & ~3) + 4;
		packet.data   = (u32)data >> 8;
		ret |= sisusb_send_packet(sisusb, 10, &packet);
	}

	return ret;
}


static int sisusb_verify_mclk(struct sisusb_usb_data *sisusb)
{
	int ret = 0;
	u32 ramptr = SISUSB_PCI_MEMBASE;
	u8 tmp1, tmp2, i, j;

	ret |= WRITEB(ramptr, 0xaa);
	ret |= WRITEB(ramptr + 16, 0x55);
	ret |= READB(ramptr, &tmp1);
	ret |= READB(ramptr + 16, &tmp2);
	if ((tmp1 != 0xaa) || (tmp2 != 0x55)) {
		for (i = 0, j = 16; i < 2; i++, j += 16) {
			ret |= GETIREG(SISSR, 0x21, &tmp1);
			ret |= SETIREGAND(SISSR, 0x21, (tmp1 & 0xfb));
			ret |= SETIREGOR(SISSR, 0x3c, 0x01);  /* not on 330 */
			ret |= SETIREGAND(SISSR, 0x3c, 0xfe); /* not on 330 */
			ret |= SETIREG(SISSR, 0x21, tmp1);
			ret |= WRITEB(ramptr + 16 + j, j);
			ret |= READB(ramptr + 16 + j, &tmp1);
			if (tmp1 == j) {
				ret |= WRITEB(ramptr + j, j);
				break;
			}
		}
	}
	return ret;
}


static ssize_t sisusb_write(struct file *file, const char __user *buffer,
		size_t count, loff_t *ppos)
{
	struct sisusb_usb_data *sisusb;
	int errno = 0;
	ssize_t bytes_written = 0;
	u8 buf8;
	u16 buf16;
	u32 buf32, address;

	sisusb = file->private_data;
	if (!sisusb)
		return -ENODEV;

	mutex_lock(&sisusb->lock);

	/* Sanity check */
	if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
		mutex_unlock(&sisusb->lock);
		return -ENODEV;
	}

	if ((*ppos) >= SISUSB_PCI_PSEUDO_IOPORTBASE &&
			(*ppos) <  SISUSB_PCI_PSEUDO_IOPORTBASE + 128) {

		address = (*ppos) - SISUSB_PCI_PSEUDO_IOPORTBASE +
				SISUSB_PCI_IOPORTBASE;

		/* Write i/o ports
		 * Byte, word and long(32) can be written. As this
		 * emulates outX instructions, the data is expected
		 * in machine-endianness.
		 */
		switch (count) {
		case 1:
			if (get_user(buf8, (u8 __user *)buffer))
				errno = -EFAULT;
			else if (sisusb_write_memio_byte(sisusb,
					SISUSB_TYPE_IO, address, buf8))
				errno = -EIO;
			else
				bytes_written = 1;

			break;

		case 2:
			if (get_user(buf16, (u16 __user *)buffer))
				errno = -EFAULT;
			else if (sisusb_write_memio_word(sisusb,
					SISUSB_TYPE_IO, address, buf16))
				errno = -EIO;
			else
				bytes_written = 2;

			break;

		case 4:
			if (get_user(buf32, (u32 __user *)buffer))
				errno = -EFAULT;
			else if (sisusb_write_memio_long(sisusb,
					SISUSB_TYPE_IO, address, buf32))
				errno = -EIO;
			else
				bytes_written = 4;

			break;

		default:
			errno = -EIO;
		}

	} else if ((*ppos) >= SISUSB_PCI_PSEUDO_MEMBASE &&
			(*ppos) <  SISUSB_PCI_PSEUDO_MEMBASE +
			sisusb->vramsize) {

		address = (*ppos) - SISUSB_PCI_PSEUDO_MEMBASE +
				SISUSB_PCI_MEMBASE;

		/* Write video ram.
		 * Buffer is copied 1:1, therefore, on big-endian
		 * machines, the data must be swapped by userland
		 * in advance (if applicable; no swapping in 8bpp
		 * mode or if YUV data is being transferred).
		 */
		errno = sisusb_write_mem_bulk(sisusb, address, NULL,
				count, buffer, 0, &bytes_written);

		if (bytes_written)
			errno = bytes_written;

	} else  if ((*ppos) >= SISUSB_PCI_PSEUDO_MMIOBASE &&
			(*ppos) <  SISUSB_PCI_PSEUDO_MMIOBASE +
			SISUSB_PCI_MMIOSIZE) {

		address = (*ppos) - SISUSB_PCI_PSEUDO_MMIOBASE +
				SISUSB_PCI_MMIOBASE;

		/* Write MMIO.
		 * Buffer is copied 1:1, therefore, on big-endian
		 * machines, the data must be swapped by userland
		 * in advance.
		 */
		errno = sisusb_write_mem_bulk(sisusb, address, NULL,
				count, buffer, 0, &bytes_written);

		if (bytes_written)
			errno = bytes_written;

	} else  if ((*ppos) >= SISUSB_PCI_PSEUDO_PCIBASE &&
				(*ppos) <= SISUSB_PCI_PSEUDO_PCIBASE +
				SISUSB_PCI_PCONFSIZE) {

		if (count != 4) {
			mutex_unlock(&sisusb->lock);
			return -EINVAL;
		}

		address = (*ppos) - SISUSB_PCI_PSEUDO_PCIBASE;

		/* Write PCI config register.
		 * Given value expected in machine endianness.
		 */
		if (get_user(buf32, (u32 __user *)buffer))
			errno = -EFAULT;
		else if (sisusb_write_pci_config(sisusb, address, buf32))
			errno = -EIO;
		else
			bytes_written = 4;

	} else {

		/* Error */
		errno = -EBADFD;

	}

	(*ppos) += bytes_written;

	mutex_unlock(&sisusb->lock);

	return errno ? errno : bytes_written;
}


bool AuthorizationSessionImpl::isCoauthorizedWith(UserNameIterator userNameIter) {
    if (!getAuthorizationManager().isAuthEnabled()) {
        return true;
    }
    if (!userNameIter.more() && !isAuthenticated()) {
        return true;
    }

    for (; userNameIter.more(); userNameIter.next()) {
        for (UserNameIterator thisUserNameIter = getAuthenticatedUserNames();
             thisUserNameIter.more();
             thisUserNameIter.next()) {
            if (*userNameIter == *thisUserNameIter) {
                return true;
            }
        }
    }

    return false;
}


    explicit BSONElement(const char* d) : data(d) {
        if (eoo()) {
            fieldNameSize_ = 0;
            totalSize = 1;
        } else {
            fieldNameSize_ = strlen(d + 1 /*skip type*/) + 1 /*include NUL byte*/;
            totalSize = computeSize();
        }
    }


    size_t objsize() const {
        return ConstDataView(value()).read<LittleEndian<uint32_t>>();
    }


inline Status _badValue(const char* reason) {
    return Status(ErrorCodes::BadValue, reason);
}


StatusWith<AuthzLockGuard> requireWritableAuthSchema28SCRAM(OperationContext* opCtx,
                                                            AuthorizationManager* authzManager) {
    int foundSchemaVersion;
    // We take a MODE_X lock during writes because we want to be sure that we can read any pinned
    // user documents back out of the database after writing them during the user management
    // commands, and to ensure only one user management command is running at a time.
    AuthzLockGuard lk(opCtx, MODE_X);
    Status status = authzManager->getAuthorizationVersion(opCtx, &foundSchemaVersion);
    if (!status.isOK()) {
        return status;
    }

    if (foundSchemaVersion < AuthorizationManager::schemaVersion28SCRAM) {
        return Status(ErrorCodes::AuthSchemaIncompatible,
                      str::stream()
                          << "User and role management commands require auth data to have "
                          << "at least schema version "
                          << AuthorizationManager::schemaVersion28SCRAM
                          << " but found "
                          << foundSchemaVersion);
    }
    status = writeAuthSchemaVersionIfNeeded(opCtx, authzManager, foundSchemaVersion);
    if (!status.isOK()) {
        return status;
    }

    return std::move(lk);
}


    Status processUsers(OperationContext* opCtx,
                        AuthorizationManager* authzManager,
                        StringData usersCollName,
                        StringData db,
                        bool drop) {
        // When the "drop" argument has been provided, we use this set to store the users
        // that are currently in the system, and remove from it as we encounter
        // same-named users in the collection we are restoring from.  Once we've fully
        // moved over the temp users collection into its final location, we drop
        // any users that previously existed there but weren't in the temp collection.
        // This is so that we can completely replace the system.users
        // collection with the users from the temp collection, without removing all
        // users at the beginning and thus potentially locking ourselves out by having
        // no users in the whole system for a time.
        stdx::unordered_set<UserName> usersToDrop;

        if (drop) {
            // Create map of the users currently in the DB
            BSONObj query =
                db.empty() ? BSONObj() : BSON(AuthorizationManager::USER_DB_FIELD_NAME << db);
            BSONObj fields = BSON(AuthorizationManager::USER_NAME_FIELD_NAME
                                  << 1
                                  << AuthorizationManager::USER_DB_FIELD_NAME
                                  << 1);

            Status status =
                queryAuthzDocument(opCtx,
                                   AuthorizationManager::usersCollectionNamespace,
                                   query,
                                   fields,
                                   [&](const BSONObj& userObj) {
                                       usersToDrop.insert(extractUserNameFromBSON(userObj));
                                   });
            if (!status.isOK()) {
                return status;
            }
        }

        Status status = queryAuthzDocument(
            opCtx,
            NamespaceString(usersCollName),
            db.empty() ? BSONObj() : BSON(AuthorizationManager::USER_DB_FIELD_NAME << db),
            BSONObj(),
            [&](const BSONObj& userObj) {
                return addUser(opCtx, authzManager, db, drop, &usersToDrop, userObj);
            });
        if (!status.isOK()) {
            return status;
        }

        if (drop) {
            long long numRemoved;
            for (const UserName& userName : usersToDrop) {
                audit::logDropUser(Client::getCurrent(), userName);
                status = removePrivilegeDocuments(opCtx,
                                                  BSON(AuthorizationManager::USER_NAME_FIELD_NAME
                                                       << userName.getUser().toString()
                                                       << AuthorizationManager::USER_DB_FIELD_NAME
                                                       << userName.getDB().toString()),
                                                  &numRemoved);
                if (!status.isOK()) {
                    return status;
                }
                dassert(numRemoved == 1);
            }
        }

        return Status::OK();
    }


    void setInUserManagementCommand(OperationContext*, bool) override {
        UASSERT_NOT_IMPLEMENTED;
    }


Status insertPrivilegeDocument(OperationContext* opCtx, const BSONObj& userObj) {
    Status status =
        insertAuthzDocument(opCtx, AuthorizationManager::usersCollectionNamespace, userObj);
    if (status.isOK()) {
        return status;
    }
    if (status.code() == ErrorCodes::DuplicateKey) {
        std::string name = userObj[AuthorizationManager::USER_NAME_FIELD_NAME].String();
        std::string source = userObj[AuthorizationManager::USER_DB_FIELD_NAME].String();
        return Status(ErrorCodes::Error(51003),
                      str::stream() << "User \"" << name << "@" << source << "\" already exists");
    }
    if (status.code() == ErrorCodes::UnknownError) {
        return Status(ErrorCodes::UserModificationFailed, status.reason());
    }
    return status;
}


Status V2UserDocumentParser::parseRoleName(const BSONObj& roleObject, RoleName* result) {
    BSONElement roleNameElement;
    BSONElement roleSourceElement;
    Status status = _extractRoleDocumentElements(roleObject, &roleNameElement, &roleSourceElement);
    if (!status.isOK())
        return status;
    *result = RoleName(roleNameElement.str(), roleSourceElement.str());
    return status;
}


Status AuthorizationManagerImpl::_initializeUserFromPrivilegeDocument(User* user,
                                                                      const BSONObj& privDoc) {
    V2UserDocumentParser parser;
    std::string userName = parser.extractUserNameFromUserDocument(privDoc);
    if (userName != user->getName().getUser()) {
        return Status(ErrorCodes::BadValue,
                      mongoutils::str::stream() << "User name from privilege document \""
                                                << userName
                                                << "\" doesn't match name of provided User \""
                                                << user->getName().getUser()
                                                << "\"");
    }

    user->setID(parser.extractUserIDFromUserDocument(privDoc));

    Status status = parser.initializeUserCredentialsFromUserDocument(user, privDoc);
    if (!status.isOK()) {
        return status;
    }
    status = parser.initializeUserRolesFromUserDocument(privDoc, user);
    if (!status.isOK()) {
        return status;
    }
    status = parser.initializeUserIndirectRolesFromUserDocument(privDoc, user);
    if (!status.isOK()) {
        return status;
    }
    status = parser.initializeUserPrivilegesFromUserDocument(privDoc, user);
    if (!status.isOK()) {
        return status;
    }
    status = parser.initializeAuthenticationRestrictionsFromUserDocument(privDoc, user);
    if (!status.isOK()) {
        return status;
    }

    return Status::OK();
}


    Date_t timestampTime() const {
        unsigned long long t = ConstDataView(value() + 4).read<LittleEndian<unsigned int>>();
        return Date_t::fromMillisSinceEpoch(t * 1000);
    }


bool AuthorizationManagerImpl::shouldValidateAuthSchemaOnStartup() {
    return _startupAuthSchemaValidation;
}


    void setShouldValidateAuthSchemaOnStartup(const bool check) override {
        _shouldValidate = check;
    }


bool AuthorizationSessionImpl::isImpersonating() const {
    return _impersonationFlag;
}


    AllowedOnSecondary secondaryAllowed(ServiceContext*) const override {
        return AllowedOnSecondary::kOptIn;
    }


    bool run(OperationContext* opCtx,
             const string& dbname,
             const BSONObj& cmdObj,
             BSONObjBuilder& result) {
        auth::CreateOrUpdateUserArgs args;
        Status status = auth::parseCreateOrUpdateUserCommands(cmdObj, "updateUser", dbname, &args);
        uassertStatusOK(status);

        if (!args.hasPassword && !args.hasCustomData && !args.hasRoles &&
            !args.authenticationRestrictions && args.mechanisms.empty()) {
            uasserted(ErrorCodes::BadValue,
                      "Must specify at least one field to update in updateUser");
        }

        if (args.hasPassword && args.userName.getDB() == "$external") {
            uasserted(ErrorCodes::BadValue,
                      "Cannot set the password for users defined on the '$external' "
                      "database");
        }

        BSONObjBuilder queryBuilder;
        queryBuilder.append(AuthorizationManager::USER_NAME_FIELD_NAME, args.userName.getUser());
        queryBuilder.append(AuthorizationManager::USER_DB_FIELD_NAME, args.userName.getDB());

        BSONObjBuilder updateSetBuilder;
        BSONObjBuilder updateUnsetBuilder;
        if (args.hasPassword) {
            BSONObjBuilder credentialsBuilder(updateSetBuilder.subobjStart("credentials"));
            status = buildCredentials(&credentialsBuilder, args);
            uassertStatusOK(status);
            credentialsBuilder.done();
        } else if (!args.mechanisms.empty()) {
            status = trimCredentials(opCtx, &queryBuilder, &updateUnsetBuilder, args);
            uassertStatusOK(status);
        }

        if (args.hasCustomData) {
            updateSetBuilder.append("customData", args.customData);
        }

        if (args.authenticationRestrictions) {
            if (args.authenticationRestrictions->isEmpty()) {
                updateUnsetBuilder.append("authenticationRestrictions", "");
            } else {
                auto swParsedRestrictions =
                    parseAuthenticationRestriction(*args.authenticationRestrictions);
                uassertStatusOK(swParsedRestrictions.getStatus());

                updateSetBuilder.append("authenticationRestrictions",
                                        *args.authenticationRestrictions);
            }
        }

        if (args.hasRoles) {
            updateSetBuilder.append("roles", rolesVectorToBSONArray(args.roles));
        }

        BSONObj updateSet = updateSetBuilder.done();
        BSONObj updateUnset = updateUnsetBuilder.done();
        BSONObjBuilder updateDocumentBuilder;
        if (!updateSet.isEmpty()) {
            updateDocumentBuilder << "$set" << updateSet;
        }
        if (!updateUnset.isEmpty()) {
            updateDocumentBuilder << "$unset" << updateUnset;
        }

        ServiceContext* serviceContext = opCtx->getClient()->getServiceContext();
        AuthorizationManager* authzManager = AuthorizationManager::get(serviceContext);

        auto lk = uassertStatusOK(requireWritableAuthSchema28SCRAM(opCtx, authzManager));

        // Role existence has to be checked after acquiring the update lock
        if (args.hasRoles) {
            for (size_t i = 0; i < args.roles.size(); ++i) {
                BSONObj ignored;
                status = authzManager->getRoleDescription(opCtx, args.roles[i], &ignored);
                uassertStatusOK(status);
            }
        }

        audit::logUpdateUser(Client::getCurrent(),
                             args.userName,
                             args.hasPassword,
                             args.hasCustomData ? &args.customData : NULL,
                             args.hasRoles ? &args.roles : NULL,
                             args.authenticationRestrictions);

        status = updatePrivilegeDocument(
            opCtx, args.userName, queryBuilder.done(), updateDocumentBuilder.done());
        // Must invalidate even on bad status - what if the write succeeded but the GLE failed?
        authzManager->invalidateUserByName(opCtx, args.userName);
        uassertStatusOK(status);
        return true;
    }


Status V2UserDocumentParser::checkValidRoleObject(const BSONObj& roleObject) {
    BSONElement roleNameElement;
    BSONElement roleSourceElement;
    return _extractRoleDocumentElements(roleObject, &roleNameElement, &roleSourceElement);
}


    virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
        return false;
    }


    bool run(OperationContext* opCtx,
             const string& dbname,
             const BSONObj& cmdObj,
             BSONObjBuilder& result) {
        RoleName roleName;
        Status status = auth::parseDropRoleCommand(cmdObj, dbname, &roleName);
        uassertStatusOK(status);

        ServiceContext* serviceContext = opCtx->getClient()->getServiceContext();
        AuthorizationManager* authzManager = AuthorizationManager::get(serviceContext);

        auto lk = uassertStatusOK(requireWritableAuthSchema28SCRAM(opCtx, authzManager));

        if (RoleGraph::isBuiltinRole(roleName)) {
            uasserted(ErrorCodes::InvalidRoleModification,
                      str::stream() << roleName.getFullName()
                                    << " is a built-in role and cannot be modified.");
        }

        BSONObj roleDoc;
        status = authzManager->getRoleDescription(opCtx, roleName, &roleDoc);
        uassertStatusOK(status);

        // From here on, we always want to invalidate the user cache before returning.
        auto invalidateGuard = makeGuard([&] {
            try {
                authzManager->invalidateUserCache(opCtx);
            } catch (const DBException& e) {
                // Since this may be called after a uassert, we want to catch any uasserts
                // that come out of invalidating the user cache and explicitly append it to
                // the command response.
                CommandHelpers::appendCommandStatusNoThrow(result, e.toStatus());
            }
        });

        // Remove this role from all users
        long long nMatched;
        status = updateAuthzDocuments(
            opCtx,
            AuthorizationManager::usersCollectionNamespace,
            BSON("roles" << BSON("$elemMatch" << BSON(AuthorizationManager::ROLE_NAME_FIELD_NAME
                                                      << roleName.getRole()
                                                      << AuthorizationManager::ROLE_DB_FIELD_NAME
                                                      << roleName.getDB()))),
            BSON("$pull" << BSON("roles" << BSON(AuthorizationManager::ROLE_NAME_FIELD_NAME
                                                 << roleName.getRole()
                                                 << AuthorizationManager::ROLE_DB_FIELD_NAME
                                                 << roleName.getDB()))),
            false,
            true,
            &nMatched);
        if (!status.isOK()) {
            uassertStatusOK(useDefaultCode(status, ErrorCodes::UserModificationFailed)
                                .withContext(str::stream() << "Failed to remove role "
                                                           << roleName.getFullName()
                                                           << " from all users"));
        }

        // Remove this role from all other roles
        status = updateAuthzDocuments(
            opCtx,
            AuthorizationManager::rolesCollectionNamespace,
            BSON("roles" << BSON("$elemMatch" << BSON(AuthorizationManager::ROLE_NAME_FIELD_NAME
                                                      << roleName.getRole()
                                                      << AuthorizationManager::ROLE_DB_FIELD_NAME
                                                      << roleName.getDB()))),
            BSON("$pull" << BSON("roles" << BSON(AuthorizationManager::ROLE_NAME_FIELD_NAME
                                                 << roleName.getRole()
                                                 << AuthorizationManager::ROLE_DB_FIELD_NAME
                                                 << roleName.getDB()))),
            false,
            true,
            &nMatched);
        if (!status.isOK()) {
            uassertStatusOK(
                useDefaultCode(status, ErrorCodes::RoleModificationFailed)
                    .withContext(
                        str::stream() << "Removed role " << roleName.getFullName()
                                      << " from all users but failed to remove from all roles"));
        }

        audit::logDropRole(Client::getCurrent(), roleName);
        // Finally, remove the actual role document
        status = removeRoleDocuments(opCtx,
                                     BSON(AuthorizationManager::ROLE_NAME_FIELD_NAME
                                          << roleName.getRole()
                                          << AuthorizationManager::ROLE_DB_FIELD_NAME
                                          << roleName.getDB()),
                                     &nMatched);
        if (!status.isOK()) {
            uassertStatusOK(status.withContext(
                str::stream() << "Removed role " << roleName.getFullName()
                              << " from all users and roles but failed to actually delete"
                                 " the role itself"));
        }

        dassert(nMatched == 0 || nMatched == 1);
        if (nMatched == 0) {
            uasserted(ErrorCodes::RoleNotFound,
                      str::stream() << "Role '" << roleName.getFullName() << "' not found");
        }

        return true;
    }


    BSONType type() const {
        const signed char typeByte = ConstDataView(data).read<signed char>();
        return static_cast<BSONType>(typeByte);
    }


inline Decimal128 BSONElement::numberDecimal() const {
    switch (type()) {
        case NumberDouble:
            return Decimal128(_numberDouble());
        case NumberInt:
            return Decimal128(_numberInt());
        case NumberLong:
            return Decimal128(static_cast<int64_t>(_numberLong()));
        case NumberDecimal:
            return _numberDecimal();
        default:
            return Decimal128::kNormalizedZero;
    }
}


    StringData sensitiveFieldName() const final {
        return "pwd"_sd;
    }


bool AuthorizationSessionImpl::isAuthorizedToGrantRole(const RoleName& role) {
    return isAuthorizedForActionsOnResource(ResourcePattern::forDatabaseName(role.getDB()),
                                            ActionType::grantRole);
}


    const char* dbrefNS() const {
        uassert(10063, "not a dbref", type() == DBRef);
        return value() + 4;
    }


inline bool BSONElement::isNumber() const {
    switch (type()) {
        case NumberLong:
        case NumberDouble:
        case NumberDecimal:
        case NumberInt:
            return true;
        default:
            return false;
    }
}


    void wait() {
        fassert(17222, !_isThisGuardInFetchPhase);
        _authzManager->_fetchPhaseIsReady.wait(_lock);
    }


StatusWith<UserHandle> AuthorizationManagerImpl::acquireUser(OperationContext* opCtx,
                                                             const UserName& userName) {
    if (userName == internalSecurity.user->getName()) {
        return internalSecurity.user;
    }

    boost::optional<UserHandle> cachedUser = _userCache.get(userName);
    auto returnUser = [&](boost::optional<UserHandle> cachedUser) {
        auto ret = *cachedUser;
        fassert(16914, ret.get());
        fassert(17003, ret->isValid());

        LOG(1) << "Returning user " << userName << " from cache";
        return ret;
    };

    // The userCache is thread-safe, so if we can get a user out of the cache we don't need to
    // take any locks!
    if (cachedUser) {
        return returnUser(cachedUser);
    }

    // Otherwise make sure we have the locks we need and check whether and wait on another
    // thread is fetching into the cache
    CacheGuard guard(opCtx, this);

    while ((boost::none == (cachedUser = _userCache.get(userName))) &&
           guard.otherUpdateInFetchPhase()) {
        guard.wait();
    }

    if (cachedUser != boost::none) {
        return returnUser(cachedUser);
    }

    guard.beginFetchPhase();
    // If there's still no user in the cache, then we need to go to disk. Take the slow path.
    LOG(1) << "Getting user " << userName << " from disk";
    auto ret = _acquireUserSlowPath(guard, opCtx, userName);

    guard.endFetchPhase();
    if (!ret.isOK()) {
        return ret.getStatus();
    }

    auto user = std::move(ret.getValue());
    if (user->isValid()) {
        _updateCacheGeneration_inlock(guard);
    }

    return user;
}


Status AuthorizationSessionImpl::checkAuthForGetMore(const NamespaceString& ns,
                                                     long long cursorID,
                                                     bool hasTerm) {
    // Since users can only getMore their own cursors, we verify that a user either is authenticated
    // or does not need to be.
    if (!_externalState->shouldIgnoreAuthChecks() && !isAuthenticated()) {
        return Status(ErrorCodes::Unauthorized,
                      str::stream() << "not authorized for getMore on " << ns.db());
    }

    // Only internal clients (such as other nodes in a replica set) are allowed to use
    // the 'term' field in a getMore operation. Use of this field could trigger changes
    // in the receiving server's replication state and should be protected.
    if (hasTerm &&
        !isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(),
                                          ActionType::internal)) {
        return Status(ErrorCodes::Unauthorized,
                      str::stream() << "not authorized for getMore with term on " << ns.ns());
    }

    return Status::OK();
}


    DeferredComparison operator<=(const BSONElement& other) const {
        return DeferredComparison(DeferredComparison::Type::kLTE, *this, other);
    }


    Decimal128 Decimal() const {
        return chk(NumberDecimal)._numberDecimal();
    }


inline bool BSONElement::trueValue() const {
    // NOTE Behavior changes must be replicated in Value::coerceToBool().
    switch (type()) {
        case NumberLong:
            return _numberLong() != 0;
        case NumberDouble:
            return _numberDouble() != 0;
        case NumberDecimal:
            return _numberDecimal().isNotEqual(Decimal128(0));
        case NumberInt:
            return _numberInt() != 0;
        case mongo::Bool:
            return boolean();
        case EOO:
        case jstNULL:
        case Undefined:
            return false;
        default:
            return true;
    }
}


    double number() const {
        return numberDouble();
    }


    bool isSameCacheGeneration() const {
        fassert(17223, _isThisGuardInFetchPhase);
        fassert(17231, _lock.owns_lock());
        return _startGeneration == _authzManager->_cacheGeneration;
    }


    bool run(OperationContext* opCtx,
             const string& dbname,
             const BSONObj& cmdObj,
             BSONObjBuilder& result) {
        RoleName roleName;
        PrivilegeVector privilegesToRemove;
        Status status = auth::parseAndValidateRolePrivilegeManipulationCommands(
            cmdObj, "revokePrivilegesFromRole", dbname, &roleName, &privilegesToRemove);
        uassertStatusOK(status);

        ServiceContext* serviceContext = opCtx->getClient()->getServiceContext();
        stdx::lock_guard<stdx::mutex> lk(getAuthzDataMutex(serviceContext));

        AuthorizationManager* authzManager = AuthorizationManager::get(serviceContext);
        status = requireWritableAuthSchema28SCRAM(opCtx, authzManager);
        uassertStatusOK(status);

        if (RoleGraph::isBuiltinRole(roleName)) {
            uasserted(ErrorCodes::InvalidRoleModification,
                      str::stream() << roleName.getFullName()
                                    << " is a built-in role and cannot be modified.");
        }

        BSONObj roleDoc;
        status = authzManager->getRoleDescription(opCtx,
                                                  roleName,
                                                  PrivilegeFormat::kShowSeparate,
                                                  AuthenticationRestrictionsFormat::kOmit,
                                                  &roleDoc);
        uassertStatusOK(status);

        PrivilegeVector privileges;
        status = auth::parseAndValidatePrivilegeArray(BSONArray(roleDoc["privileges"].Obj()),
                                                      &privileges);
        uassertStatusOK(status);

        for (PrivilegeVector::iterator itToRm = privilegesToRemove.begin();
             itToRm != privilegesToRemove.end();
             ++itToRm) {
            for (PrivilegeVector::iterator curIt = privileges.begin(); curIt != privileges.end();
                 ++curIt) {
                if (curIt->getResourcePattern() == itToRm->getResourcePattern()) {
                    curIt->removeActions(itToRm->getActions());
                    if (curIt->getActions().empty()) {
                        privileges.erase(curIt);
                    }
                    break;
                }
            }
        }

        // Build up update modifier object to $set privileges.
        mutablebson::Document updateObj;
        mutablebson::Element setElement = updateObj.makeElementObject("$set");
        status = updateObj.root().pushBack(setElement);
        uassertStatusOK(status);
        mutablebson::Element privilegesElement = updateObj.makeElementArray("privileges");
        status = setElement.pushBack(privilegesElement);
        uassertStatusOK(status);
        status = Privilege::getBSONForPrivileges(privileges, privilegesElement);
        uassertStatusOK(status);

        audit::logRevokePrivilegesFromRole(Client::getCurrent(), roleName, privilegesToRemove);

        BSONObjBuilder updateBSONBuilder;
        updateObj.writeTo(&updateBSONBuilder);
        status = updateRoleDocument(opCtx, roleName, updateBSONBuilder.done());
        // Must invalidate even on bad status - what if the write succeeded but the GLE failed?
        authzManager->invalidateUserCache();
        uassertStatusOK(status);
        return true;
    }


void AuthorizationManagerImpl::logOp(OperationContext* opCtx,
                                     const char* op,
                                     const NamespaceString& nss,
                                     const BSONObj& o,
                                     const BSONObj* o2) {
    if (appliesToAuthzData(op, nss, o)) {
        _externalState->logOp(opCtx, op, nss, o, o2);
        _invalidateRelevantCacheData(op, nss, o, o2);
    }
}


void AuthorizationManagerImpl::_updateCacheGeneration_inlock() {
    _cacheGeneration = OID::gen();
}


    Status getRoleDescriptionsForDB(OperationContext*,
                                    std::string,
                                    PrivilegeFormat,
                                    AuthenticationRestrictionsFormat,
                                    bool,
                                    std::vector<BSONObj>*) override {
        UASSERT_NOT_IMPLEMENTED;
    }


    bool run(OperationContext* opCtx,
             const string& dbname,
             const BSONObj& cmdObj,
             BSONObjBuilder& result) {
        auth::RolesInfoArgs args;
        Status status = auth::parseRolesInfoCommand(cmdObj, dbname, &args);
        uassertStatusOK(status);

        status = requireReadableAuthSchema26Upgrade(opCtx, getGlobalAuthorizationManager());
        uassertStatusOK(status);

        if (args.allForDB) {
            std::vector<BSONObj> rolesDocs;
            status = getGlobalAuthorizationManager()->getRoleDescriptionsForDB(
                opCtx,
                dbname,
                args.privilegeFormat,
                args.authenticationRestrictionsFormat,
                args.showBuiltinRoles,
                &rolesDocs);
            uassertStatusOK(status);

            if (args.privilegeFormat == PrivilegeFormat::kShowAsUserFragment) {
                uasserted(ErrorCodes::IllegalOperation,
                          "Cannot get user fragment for all roles in a database");
            }
            BSONArrayBuilder rolesArrayBuilder;
            for (size_t i = 0; i < rolesDocs.size(); ++i) {
                rolesArrayBuilder.append(rolesDocs[i]);
            }
            result.append("roles", rolesArrayBuilder.arr());
        } else {
            BSONObj roleDetails;
            status = getGlobalAuthorizationManager()->getRolesDescription(
                opCtx,
                args.roleNames,
                args.privilegeFormat,
                args.authenticationRestrictionsFormat,
                &roleDetails);
            uassertStatusOK(status);

            if (args.privilegeFormat == PrivilegeFormat::kShowAsUserFragment) {
                result.append("userFragment", roleDetails);
            } else {
                result.append("roles", BSONArray(roleDetails));
            }
        }

        return true;
    }


void AuthorizationManagerImpl::invalidateUserCache() {
    CacheGuard guard(this, CacheGuard::fetchSynchronizationManual);
    _invalidateUserCache_inlock();
}


    Status acquireUser(OperationContext*, const UserName&, User**) override {
        UASSERT_NOT_IMPLEMENTED;
    }


void AuthorizationManagerImpl::_invalidateUserCache_inlock() {
    _updateCacheGeneration_inlock();
    for (stdx::unordered_map<UserName, User*>::iterator it = _userCache.begin();
         it != _userCache.end();
         ++it) {
        fassert(17266, it->second != internalSecurity.user);
        it->second->invalidate();
    }
    _userCache.clear();

    // Reread the schema version before acquiring the next user.
    _version = schemaVersionInvalid;
}


Status AuthorizationManagerImpl::getRoleDescriptionsForDB(
    OperationContext* opCtx,
    const std::string dbname,
    PrivilegeFormat privileges,
    AuthenticationRestrictionsFormat restrictions,
    bool showBuiltinRoles,
    vector<BSONObj>* result) {
    return _externalState->getRoleDescriptionsForDB(
        opCtx, dbname, privileges, restrictions, showBuiltinRoles, result);
}


    void operator()(User* user) {
        // Remove the user from the borrower if it hasn't already been swapped out.
        if (_borrower && *_it == user) {
            fassert(40546, _borrower->removeAt(_it) == user);
        }
        _owner->releaseUser(user);
    }


bool AuthorizationSession::isAuthorizedToGrantRole(const RoleName& role) {
    return isAuthorizedForActionsOnResource(ResourcePattern::forDatabaseName(role.getDB()),
                                            ActionType::grantRole);
}


    virtual void redactForLogging(mutablebson::Document* cmdObj) {
        auth::redactPasswordData(cmdObj->root());
    }


    bool run(OperationContext* opCtx,
             const string& dbname,
             const BSONObj& cmdObj,
             BSONObjBuilder& result) {
        auth::RolesInfoArgs args;
        Status status = auth::parseRolesInfoCommand(cmdObj, dbname, &args);
        if (!status.isOK()) {
            return appendCommandStatus(result, status);
        }

        status = requireAuthSchemaVersion26UpgradeOrFinal(opCtx, getGlobalAuthorizationManager());
        if (!status.isOK()) {
            return appendCommandStatus(result, status);
        }

        if (args.allForDB) {
            std::vector<BSONObj> rolesDocs;
            status = getGlobalAuthorizationManager()->getRoleDescriptionsForDB(
                opCtx,
                dbname,
                args.privilegeFormat,
                args.authenticationRestrictionsFormat,
                args.showBuiltinRoles,
                &rolesDocs);
            if (!status.isOK()) {
                return appendCommandStatus(result, status);
            }

            if (args.privilegeFormat == PrivilegeFormat::kShowAsUserFragment) {
                return appendCommandStatus(
                    result,
                    Status(ErrorCodes::IllegalOperation,
                           "Cannot get user fragment for all roles in a database"));
            }
            BSONArrayBuilder rolesArrayBuilder;
            for (size_t i = 0; i < rolesDocs.size(); ++i) {
                rolesArrayBuilder.append(rolesDocs[i]);
            }
            result.append("roles", rolesArrayBuilder.arr());
        } else {
            BSONObj roleDetails;
            status = getGlobalAuthorizationManager()->getRolesDescription(
                opCtx,
                args.roleNames,
                args.privilegeFormat,
                args.authenticationRestrictionsFormat,
                &roleDetails);
            if (!status.isOK()) {
                return appendCommandStatus(result, status);
            }

            if (args.privilegeFormat == PrivilegeFormat::kShowAsUserFragment) {
                result.append("userFragment", roleDetails);
            } else {
                result.append("roles", BSONArray(roleDetails));
            }
        }

        return true;
    }


CmdAuthSchemaUpgrade() : BasicCommand("authSchemaUpgrade") {}


    virtual void help(stringstream& ss) const {
        ss << "Grants privileges to a role" << endl;
    }


bool AuthorizationSession::isUsingLocalhostBypass() {
    return getAuthorizationManager().isAuthEnabled() && _externalState->shouldAllowLocalhost();
}


Status AuthorizationSession::checkAuthForAggregate(const NamespaceString& nss,
                                                   const BSONObj& cmdObj,
                                                   bool isMongos) {
    if (!nss.isValid()) {
        return Status(ErrorCodes::InvalidNamespace,
                      mongoutils::str::stream() << "Invalid input namespace, " << nss.ns());
    }

    // If this connection does not need to be authenticated (for instance, if auth is disabled),
    // return Status::OK() immediately.
    if (_externalState->shouldIgnoreAuthChecks()) {
        return Status::OK();
    }

    // We require at least one authenticated user when running aggregate with auth enabled.
    if (!getAuthenticatedUserNames().more()) {
        return Status(ErrorCodes::Unauthorized, "unauthorized");
    }

    auto statusWithAggRequest = AggregationRequest::parseFromBSON(nss, cmdObj);
    if (!statusWithAggRequest.isOK()) {
        return statusWithAggRequest.getStatus();
    }
    AggregationRequest aggRequest = std::move(statusWithAggRequest.getValue());

    const auto& pipeline = aggRequest.getPipeline();

    // If the aggregation pipeline is empty, confirm the user is authorized for find on 'nss'.
    if (pipeline.empty()) {
        if (!isAuthorizedForPrivilege(
                Privilege(ResourcePattern::forExactNamespace(nss), ActionType::find))) {
            return Status(ErrorCodes::Unauthorized, "unauthorized");
        }

        return Status::OK();
    }

    // Confirm the user is authorized for the pipeline's initial document source. We confirm a user
    // is authorized incrementally rather than once for the entire pipeline. This will prevent a
    // malicious user, who doesn't have access to the initial document source, from consuming the
    // resources needed to parse a potentially large pipeline.
    auto liteParsedFirstDocumentSource = LiteParsedDocumentSource::parse(aggRequest, pipeline[0]);
    if (!liteParsedFirstDocumentSource->isInitialSource() &&
        !isAuthorizedForPrivilege(
            Privilege(ResourcePattern::forExactNamespace(nss), ActionType::find))) {
        return Status(ErrorCodes::Unauthorized, "unauthorized");
    }

    // We have done the work to lite parse the first stage. Given that, we check required privileges
    // for it using 'liteParsedFirstDocumentSource' regardless of whether is an initial source or
    // not.
    if (!isAuthorizedForPrivileges(liteParsedFirstDocumentSource->requiredPrivileges(isMongos))) {
        return Status(ErrorCodes::Unauthorized, "unauthorized");
    }

    // Confirm privileges for the remainder of the pipepline. Start with the second stage as we have
    // already authorized the first.
    auto pipelineIter = pipeline.begin() + 1;

    for (; pipelineIter != pipeline.end(); ++pipelineIter) {
        auto liteParsedDocSource = LiteParsedDocumentSource::parse(aggRequest, *pipelineIter);
        if (!isAuthorizedForPrivileges(liteParsedDocSource->requiredPrivileges(isMongos))) {
            return Status(ErrorCodes::Unauthorized, "unauthorized");
        }
    }

    return Status::OK();
}


bool AuthorizationSession::isAuthorizedToChangeOwnCustomDataAsUser(const UserName& userName) {
    return AuthorizationSession::isAuthorizedToChangeAsUser(userName,
                                                            ActionType::changeOwnCustomData);
}


void AuthorizationManager::_invalidateRelevantCacheData(const char* op,
                                                        const NamespaceString& ns,
                                                        const BSONObj& o,
                                                        const BSONObj* o2) {
    if (ns == AuthorizationManager::rolesCollectionNamespace ||
        ns == AuthorizationManager::versionCollectionNamespace) {
        invalidateUserCache();
        return;
    }

    if (*op == 'i' || *op == 'd' || *op == 'u') {
        // If you got into this function isAuthzNamespace() must have returned true, and we've
        // already checked that it's not the roles or version collection.
        invariant(ns == AuthorizationManager::usersCollectionNamespace);

        StatusWith<UserName> userName = (*op == 'u')
            ? extractUserNameFromIdString((*o2)["_id"].str())
            : extractUserNameFromIdString(o["_id"].str());

        if (!userName.isOK()) {
            warning() << "Invalidating user cache based on user being updated failed, will "
                         "invalidate the entire cache instead: "
                      << userName.getStatus();
            invalidateUserCache();
            return;
        }
        invalidateUserByName(userName.getValue());
    } else {
        invalidateUserCache();
    }
}


Status AuthorizationManager::acquireUserForSessionRefresh(OperationContext* opCtx,
                                                          const UserName& userName,
                                                          const User::UserId& uid,
                                                          User** user) {
    auto status = acquireUser(opCtx, userName, user);
    if (!status.isOK()) {
        return status;
    }

    if (uid != (*user)->getID()) {
        *user = nullptr;
        return {ErrorCodes::UserNotFound,
                str::stream() << "User id from privilege document '" << userName.toString()
                              << "' does not match user id in session."};
    }

    return Status::OK();
}


inline long long BSONElement::safeNumberLong() const {
    switch (type()) {
        case NumberDouble: {
            double d = numberDouble();
            if (std::isnan(d)) {
                return 0;
            }
            if (d > (double)std::numeric_limits<long long>::max()) {
                return std::numeric_limits<long long>::max();
            }
            if (d < std::numeric_limits<long long>::min()) {
                return std::numeric_limits<long long>::min();
            }
            return numberLong();
        }
        case NumberDecimal: {
            Decimal128 d = numberDecimal();
            if (d.isNaN()) {
                return 0;
            }
            if (d.isGreater(Decimal128(std::numeric_limits<int64_t>::max()))) {
                return static_cast<long long>(std::numeric_limits<int64_t>::max());
            }
            if (d.isLess(Decimal128(std::numeric_limits<int64_t>::min()))) {
                return static_cast<long long>(std::numeric_limits<int64_t>::min());
            }
            return numberLong();
        }
        default:
            return numberLong();
    }
}


    virtual void help(stringstream& ss) const {
        ss << "Grants roles to a user." << endl;
    }


    virtual Status checkAuthForCommand(Client* client,
                                       const std::string& dbname,
                                       const BSONObj& cmdObj) {
        return auth::checkAuthForAuthSchemaUpgradeCommand(client);
    }


RoleNameIterator AuthorizationSession::getAuthenticatedRoleNames() {
    return makeRoleNameIterator(_authenticatedRoleNames.begin(), _authenticatedRoleNames.end());
}