10Sigor@sysoev.ru 20Sigor@sysoev.ru /* 30Sigor@sysoev.ru * Copyright (C) Igor Sysoev 40Sigor@sysoev.ru * Copyright (C) NGINX, Inc. 50Sigor@sysoev.ru */ 60Sigor@sysoev.ru 70Sigor@sysoev.ru 80Sigor@sysoev.ru #include <nxt_main.h> 90Sigor@sysoev.ru 100Sigor@sysoev.ru 11*1Sigor@sysoev.ru static void nxt_job_file_open_and_read(nxt_task_t *task, void *obj, void *data); 120Sigor@sysoev.ru static nxt_int_t nxt_job_file_open(nxt_job_file_t *jbf); 130Sigor@sysoev.ru static nxt_int_t nxt_job_file_info(nxt_job_file_t *jbf); 140Sigor@sysoev.ru static nxt_int_t nxt_job_file_mmap(nxt_job_file_t *jbf, size_t size); 150Sigor@sysoev.ru static nxt_int_t nxt_job_file_read_data(nxt_job_file_t *jbf, size_t size); 160Sigor@sysoev.ru static nxt_int_t nxt_job_file_read_required(nxt_job_file_t *jbf); 170Sigor@sysoev.ru 180Sigor@sysoev.ru 190Sigor@sysoev.ru nxt_job_file_t * 200Sigor@sysoev.ru nxt_job_file_create(nxt_mem_pool_t *mp) 210Sigor@sysoev.ru { 220Sigor@sysoev.ru nxt_job_file_t *jbf; 230Sigor@sysoev.ru 240Sigor@sysoev.ru jbf = nxt_job_create(mp, sizeof(nxt_job_file_t)); 250Sigor@sysoev.ru 260Sigor@sysoev.ru if (nxt_fast_path(jbf != NULL)) { 270Sigor@sysoev.ru jbf->file.fd = NXT_FILE_INVALID; 280Sigor@sysoev.ru jbf->file.accessed = NXT_FILE_ACCESSED_LONG_AGO; 290Sigor@sysoev.ru jbf->read_required = nxt_job_file_read_required; 300Sigor@sysoev.ru } 310Sigor@sysoev.ru 320Sigor@sysoev.ru return jbf; 330Sigor@sysoev.ru } 340Sigor@sysoev.ru 350Sigor@sysoev.ru 360Sigor@sysoev.ru void 370Sigor@sysoev.ru nxt_job_file_init(nxt_job_file_t *jbf) 380Sigor@sysoev.ru { 390Sigor@sysoev.ru nxt_job_init(&jbf->job, sizeof(nxt_job_file_t)); 400Sigor@sysoev.ru 410Sigor@sysoev.ru jbf->file.fd = NXT_FILE_INVALID; 420Sigor@sysoev.ru jbf->file.accessed = NXT_FILE_ACCESSED_LONG_AGO; 430Sigor@sysoev.ru jbf->read_required = nxt_job_file_read_required; 440Sigor@sysoev.ru } 450Sigor@sysoev.ru 460Sigor@sysoev.ru 470Sigor@sysoev.ru /* 480Sigor@sysoev.ru * Must be a function but not a macro, because 490Sigor@sysoev.ru * it can be used as function pointer. 500Sigor@sysoev.ru */ 510Sigor@sysoev.ru 520Sigor@sysoev.ru void 53*1Sigor@sysoev.ru nxt_job_file_read(nxt_task_t *task, nxt_job_t *job) 540Sigor@sysoev.ru { 55*1Sigor@sysoev.ru nxt_job_start(task, job, nxt_job_file_open_and_read); 560Sigor@sysoev.ru } 570Sigor@sysoev.ru 580Sigor@sysoev.ru 590Sigor@sysoev.ru static void 60*1Sigor@sysoev.ru nxt_job_file_open_and_read(nxt_task_t *task, void *obj, void *data) 610Sigor@sysoev.ru { 620Sigor@sysoev.ru size_t size; 630Sigor@sysoev.ru nxt_int_t n; 640Sigor@sysoev.ru nxt_bool_t read_ahead; 650Sigor@sysoev.ru nxt_file_t *file; 660Sigor@sysoev.ru nxt_job_file_t *jbf; 670Sigor@sysoev.ru nxt_work_handler_t handler; 680Sigor@sysoev.ru 690Sigor@sysoev.ru jbf = obj; 700Sigor@sysoev.ru file = &jbf->file; 710Sigor@sysoev.ru 72*1Sigor@sysoev.ru nxt_debug(task, "file job read: \"%FN\"", file->name); 730Sigor@sysoev.ru 740Sigor@sysoev.ru if (file->fd != NXT_FILE_INVALID && jbf->close_before_open) { 750Sigor@sysoev.ru nxt_file_close(file); 760Sigor@sysoev.ru file->fd = NXT_FILE_INVALID; 770Sigor@sysoev.ru } 780Sigor@sysoev.ru 790Sigor@sysoev.ru if (file->fd == NXT_FILE_INVALID) { 800Sigor@sysoev.ru 810Sigor@sysoev.ru switch (nxt_job_file_open(jbf)) { 820Sigor@sysoev.ru 830Sigor@sysoev.ru case NXT_OK: 840Sigor@sysoev.ru break; 850Sigor@sysoev.ru 860Sigor@sysoev.ru case NXT_DECLINED: 870Sigor@sysoev.ru handler = jbf->ready_handler; 880Sigor@sysoev.ru goto done; 890Sigor@sysoev.ru 900Sigor@sysoev.ru default: /* NXT_ERROR */ 910Sigor@sysoev.ru handler = jbf->error_handler; 920Sigor@sysoev.ru goto done; 930Sigor@sysoev.ru } 940Sigor@sysoev.ru } 950Sigor@sysoev.ru 960Sigor@sysoev.ru if (file->size > 0) { 970Sigor@sysoev.ru 980Sigor@sysoev.ru if (jbf->buffer != NULL) { 990Sigor@sysoev.ru size = nxt_buf_mem_size(&jbf->buffer->mem); 1000Sigor@sysoev.ru size = nxt_min(file->size, (nxt_off_t) size); 1010Sigor@sysoev.ru read_ahead = nxt_buf_is_mmap(jbf->buffer); 1020Sigor@sysoev.ru 1030Sigor@sysoev.ru } else { 1040Sigor@sysoev.ru size = nxt_min(file->size, 1024 * 1024); 1050Sigor@sysoev.ru read_ahead = jbf->read_ahead; 1060Sigor@sysoev.ru } 1070Sigor@sysoev.ru 1080Sigor@sysoev.ru if (read_ahead) { 1090Sigor@sysoev.ru nxt_file_read_ahead(&jbf->file, jbf->offset, size); 1100Sigor@sysoev.ru } 1110Sigor@sysoev.ru 1120Sigor@sysoev.ru if (jbf->buffer != NULL) { 1130Sigor@sysoev.ru 1140Sigor@sysoev.ru if (nxt_buf_is_mmap(jbf->buffer)) { 1150Sigor@sysoev.ru n = nxt_job_file_mmap(jbf, size); 1160Sigor@sysoev.ru 1170Sigor@sysoev.ru } else { 1180Sigor@sysoev.ru n = nxt_job_file_read_data(jbf, size); 1190Sigor@sysoev.ru } 1200Sigor@sysoev.ru 1210Sigor@sysoev.ru if (nxt_slow_path(n != NXT_OK)) { 1220Sigor@sysoev.ru handler = jbf->error_handler; 1230Sigor@sysoev.ru goto done; 1240Sigor@sysoev.ru } 1250Sigor@sysoev.ru } 1260Sigor@sysoev.ru } 1270Sigor@sysoev.ru 1280Sigor@sysoev.ru if (jbf->offset == file->size) { 1290Sigor@sysoev.ru jbf->complete = 1; 1300Sigor@sysoev.ru 1310Sigor@sysoev.ru if (jbf->close) { 1320Sigor@sysoev.ru nxt_file_close(file); 1330Sigor@sysoev.ru file->fd = NXT_FILE_INVALID; 1340Sigor@sysoev.ru } 1350Sigor@sysoev.ru } 1360Sigor@sysoev.ru 137*1Sigor@sysoev.ru nxt_job_return(task, &jbf->job, jbf->ready_handler); 1380Sigor@sysoev.ru return; 1390Sigor@sysoev.ru 1400Sigor@sysoev.ru done: 1410Sigor@sysoev.ru 1420Sigor@sysoev.ru if (file->fd != NXT_FILE_INVALID) { 1430Sigor@sysoev.ru nxt_file_close(file); 1440Sigor@sysoev.ru file->fd = NXT_FILE_INVALID; 1450Sigor@sysoev.ru } 1460Sigor@sysoev.ru 147*1Sigor@sysoev.ru nxt_job_return(task, &jbf->job, handler); 1480Sigor@sysoev.ru } 1490Sigor@sysoev.ru 1500Sigor@sysoev.ru 1510Sigor@sysoev.ru static nxt_int_t 1520Sigor@sysoev.ru nxt_job_file_open(nxt_job_file_t *jbf) 1530Sigor@sysoev.ru { 1540Sigor@sysoev.ru nxt_int_t n; 1550Sigor@sysoev.ru 1560Sigor@sysoev.ru if (jbf->test_before_open) { 1570Sigor@sysoev.ru n = nxt_job_file_info(jbf); 1580Sigor@sysoev.ru 1590Sigor@sysoev.ru if (n != NXT_OK) { 1600Sigor@sysoev.ru goto test_directory; 1610Sigor@sysoev.ru } 1620Sigor@sysoev.ru 1630Sigor@sysoev.ru if (jbf->file.type == NXT_FILE_DIRECTORY) { 1640Sigor@sysoev.ru return NXT_DECLINED; 1650Sigor@sysoev.ru } 1660Sigor@sysoev.ru 1670Sigor@sysoev.ru if (jbf->read_required(jbf) != NXT_OK) { 1680Sigor@sysoev.ru return NXT_DECLINED; 1690Sigor@sysoev.ru } 1700Sigor@sysoev.ru } 1710Sigor@sysoev.ru 1720Sigor@sysoev.ru n = nxt_file_open(&jbf->file, NXT_FILE_RDONLY, NXT_FILE_OPEN, 0); 1730Sigor@sysoev.ru 1740Sigor@sysoev.ru if (n == NXT_OK) { 1750Sigor@sysoev.ru n = nxt_job_file_info(jbf); 1760Sigor@sysoev.ru 1770Sigor@sysoev.ru if (nxt_fast_path(n == NXT_OK)) { 1780Sigor@sysoev.ru 1790Sigor@sysoev.ru if (jbf->file.type == NXT_FILE_DIRECTORY) { 1800Sigor@sysoev.ru return NXT_DECLINED; 1810Sigor@sysoev.ru } 1820Sigor@sysoev.ru 1830Sigor@sysoev.ru return jbf->read_required(jbf); 1840Sigor@sysoev.ru } 1850Sigor@sysoev.ru 1860Sigor@sysoev.ru return n; 1870Sigor@sysoev.ru } 1880Sigor@sysoev.ru 1890Sigor@sysoev.ru test_directory: 1900Sigor@sysoev.ru 1910Sigor@sysoev.ru if (jbf->directory_end != 0 1920Sigor@sysoev.ru && jbf->file.error != NXT_ENOTDIR 1930Sigor@sysoev.ru && jbf->file.error != NXT_ENAMETOOLONG 1940Sigor@sysoev.ru && jbf->file.error != NXT_EACCES) 1950Sigor@sysoev.ru { 1960Sigor@sysoev.ru jbf->file.name[jbf->directory_end] = '\0'; 1970Sigor@sysoev.ru 1980Sigor@sysoev.ru return nxt_job_file_info(jbf); 1990Sigor@sysoev.ru } 2000Sigor@sysoev.ru 2010Sigor@sysoev.ru return n; 2020Sigor@sysoev.ru } 2030Sigor@sysoev.ru 2040Sigor@sysoev.ru 2050Sigor@sysoev.ru static nxt_int_t 2060Sigor@sysoev.ru nxt_job_file_info(nxt_job_file_t *jbf) 2070Sigor@sysoev.ru { 2080Sigor@sysoev.ru nxt_int_t n; 2090Sigor@sysoev.ru nxt_file_t *file; 2100Sigor@sysoev.ru nxt_file_info_t fi; 2110Sigor@sysoev.ru 2120Sigor@sysoev.ru file = &jbf->file; 2130Sigor@sysoev.ru 2140Sigor@sysoev.ru n = nxt_file_info(file, &fi); 2150Sigor@sysoev.ru 2160Sigor@sysoev.ru if (n != NXT_OK) { 2170Sigor@sysoev.ru return NXT_ERROR; 2180Sigor@sysoev.ru } 2190Sigor@sysoev.ru 2200Sigor@sysoev.ru if (nxt_is_file(&fi)) { 2210Sigor@sysoev.ru file->type = NXT_FILE_REGULAR; 2220Sigor@sysoev.ru file->size = nxt_file_size(&fi); 2230Sigor@sysoev.ru file->mtime = nxt_file_mtime(&fi); 2240Sigor@sysoev.ru 2250Sigor@sysoev.ru } else if (nxt_is_dir(&fi)) { 2260Sigor@sysoev.ru file->type = NXT_FILE_DIRECTORY; 2270Sigor@sysoev.ru file->size = nxt_file_size(&fi); 2280Sigor@sysoev.ru file->mtime = nxt_file_mtime(&fi); 2290Sigor@sysoev.ru } 2300Sigor@sysoev.ru 2310Sigor@sysoev.ru return NXT_OK; 2320Sigor@sysoev.ru } 2330Sigor@sysoev.ru 2340Sigor@sysoev.ru 2350Sigor@sysoev.ru static nxt_int_t 2360Sigor@sysoev.ru nxt_job_file_mmap(nxt_job_file_t *jbf, size_t size) 2370Sigor@sysoev.ru { 2380Sigor@sysoev.ru u_char *p, *end; 2390Sigor@sysoev.ru static nxt_uint_t n; 2400Sigor@sysoev.ru 2410Sigor@sysoev.ru p = nxt_mem_map(NULL, &jbf->buffer->mmap, size, NXT_MEM_MAP_READ, 2420Sigor@sysoev.ru (NXT_MEM_MAP_FILE | NXT_MEM_MAP_PREFAULT), 2430Sigor@sysoev.ru jbf->file.fd, jbf->offset); 2440Sigor@sysoev.ru 2450Sigor@sysoev.ru if (nxt_fast_path(p != NXT_MEM_MAP_FAILED)) { 2460Sigor@sysoev.ru 2470Sigor@sysoev.ru end = p + size; 2480Sigor@sysoev.ru 2490Sigor@sysoev.ru jbf->buffer->mem.pos = p; 2500Sigor@sysoev.ru jbf->buffer->mem.free = end; 2510Sigor@sysoev.ru jbf->buffer->mem.start = p; 2520Sigor@sysoev.ru jbf->buffer->mem.end = end; 2530Sigor@sysoev.ru jbf->buffer->file_end += size; 2540Sigor@sysoev.ru jbf->offset += size; 2550Sigor@sysoev.ru 2560Sigor@sysoev.ru /* 2570Sigor@sysoev.ru * The mapped pages should be already preloaded in the kernel page 2580Sigor@sysoev.ru * cache by nxt_file_read_ahead(). Touching them should wire the pages 2590Sigor@sysoev.ru * in user land memory if mmap() did not do this. Adding to the static 2600Sigor@sysoev.ru * variable "n" disables the loop elimination during optimization. 2610Sigor@sysoev.ru */ 2620Sigor@sysoev.ru n += *p; 2630Sigor@sysoev.ru 2640Sigor@sysoev.ru for (p = nxt_align_ptr(p, nxt_pagesize); p < end; p += nxt_pagesize) { 2650Sigor@sysoev.ru n += *p; 2660Sigor@sysoev.ru } 2670Sigor@sysoev.ru 2680Sigor@sysoev.ru return NXT_OK; 2690Sigor@sysoev.ru } 2700Sigor@sysoev.ru 2710Sigor@sysoev.ru return NXT_ERROR; 2720Sigor@sysoev.ru } 2730Sigor@sysoev.ru 2740Sigor@sysoev.ru 2750Sigor@sysoev.ru static nxt_int_t 2760Sigor@sysoev.ru nxt_job_file_read_data(nxt_job_file_t *jbf, size_t size) 2770Sigor@sysoev.ru { 2780Sigor@sysoev.ru ssize_t n; 2790Sigor@sysoev.ru 2800Sigor@sysoev.ru n = nxt_file_read(&jbf->file, jbf->buffer->mem.pos, size, jbf->offset); 2810Sigor@sysoev.ru 2820Sigor@sysoev.ru if (nxt_fast_path(n > 0)) { 2830Sigor@sysoev.ru 2840Sigor@sysoev.ru jbf->buffer->mem.free += n; 2850Sigor@sysoev.ru jbf->offset += n; 2860Sigor@sysoev.ru 2870Sigor@sysoev.ru if (nxt_buf_is_file(jbf->buffer)) { 2880Sigor@sysoev.ru jbf->buffer->file_end += n; 2890Sigor@sysoev.ru } 2900Sigor@sysoev.ru 2910Sigor@sysoev.ru return NXT_OK; 2920Sigor@sysoev.ru } 2930Sigor@sysoev.ru 2940Sigor@sysoev.ru return NXT_ERROR; 2950Sigor@sysoev.ru } 2960Sigor@sysoev.ru 2970Sigor@sysoev.ru 2980Sigor@sysoev.ru static nxt_int_t 2990Sigor@sysoev.ru nxt_job_file_read_required(nxt_job_file_t *jbf) 3000Sigor@sysoev.ru { 3010Sigor@sysoev.ru return NXT_OK; 3020Sigor@sysoev.ru } 303